Bug #11501
Scroll Lock translation to control sequence is patently unhelpful
100%
Description
Overview¶
Most keyboards (using any interconnect) have a series of function keys beyond the alphanumeric; e.g., F1, F2, F3, Pause, Print Screen, etc. Some function keys are generally "sticky" and associated with an indicator light; e.g., Caps Lock, Scroll Lock, and Num Lock.
Of the sticky keys, the Scroll Lock key is the most archaic: its function is not standard across different operating systems, or even different terminal or windowing environments. On illumos, the key is not even sticky when using the framebuffer text console! Instead of acting as a modifier or even merely influencing the indicator light state, a control sequence is emitted as keyboard input: CSI 210 z
. This control sequence is not, as near as I can tell, recognised by any software. A user pressing the Scroll Lock key will likely confuse whatever application (including the shell, or the kernel line discipline) is currently active.
The SPICE server code used for framebuffer and keyboard emulation in some hypervisors (e.g., QEMU/KVM on Linux) makes an unfortunately aggressive attempt to keep the emulated Scroll Lock indicator light (which we do not handle!) synchronised with the Scroll Lock state on the client keyboard. Every two seconds, it will produce an emulated press and release of the Scroll Lock key in the guest, making the console effectively unusable.
Keyboard Handling Background¶
The keyboard handling subsystem involves a number of modules and a somewhat impenetrable Rube Goldberg machine of STREAMS. Roughly, we're looking at this structure:
console stdin <- wc <- conskbd <- keyboard driver (kb8042, usbkbm, etc) [kbtrans] [kbtrans]
Drivers for physical keyboards (e.g., kb8042
on Intel, or usbkbm
on all platforms for USB keyboards) start out by setting up an instance of the common kbtrans
framework through kbtrans_streams_init()
. This framework begins in the TR_ASCII
translation mode. The keyboard drivers are capable of simulating either a native scancode set (e.g., PC AT keyboard for kb8042
) or the USB HID scancode set; this can be set via the CONSSETKBDTYPE
ioctl()
.
The conskbd
module is pushed on top of the lower keyboard driver. While it initialises, it forces the underlying keyboard to use the USB scancode set via CONSSETKBDTYPE
. It also disables translation to ASCII by switching to the TR_UNTRANS_EVENT
mode via KIOCTRANS
. This means that conskbd
gets raw key press/release events from the keyboard driver. The conskbd
module has its own kbtrans
instance which remains in the TR_ASCII
mode by default (for use on the text console) until a subsequent VUIDSFORMAT
or KIOCTRANS
ioctl(2)
from, say, a windowing system.
In practice, a key press or release event is received by the keyboard driver which passes it to kbtrans_streams_key()
where it is effectively handed on to conskbd
unmodified. It is then passed again to kbtrans_streams_key()
by conskbd
, where it is:
- transformed from a USB scancode to a symbolic key (see
sys/kbd.h
) - (for the console) transformed by
kbtrans_ascii_keypressed()
to an ASCII byte sequence to effectively be passed up tostdin
The structure of the key maps in sys/kbd.h
appears to reflect a world centred around the old Sun Type 3/4 keyboards. There are some comments in the sys/kbd.h
and terminfo.src
that suggest that the function keys were considered in groups based on their location on keyboards from that era. Of particular note: R3, the third key from the left on the top row of the right hand bank on a Sun Type 4, was labelled Scroll Lock. As such, it is represented using the macro RF(3)
in the tables that translate from scancodes to symbolic keys.
Proposed Fix¶
In the FUNCKEYS
arm of kbtrans_ascii_keypressed()
, we should just drop Scroll Lock key presses (i.e., RF(3)
) on the floor. This is late enough in processing that if a windowing system takes over and disables TR_ASCII
mode, the system can still receive the Scroll Lock presses and (hopefully) correctly control the indicator lights as SPICE expects. This also doesn't preclude subsequent reactivation of Scroll Lock processing on the text console if somebody wants to implement an actual scrolling lock of some kind, provided they are willing to absorb the keystrokes and toggle the indicator light as expected.
Updated by Joshua M. Clulow over 1 year ago
Testing Notes¶
I have an OpenIndiana guest that I use for testing. Before rebooting, checked that pressing Scroll Lock emitted the sequence on the terminal as described in the bug (CSI 220 z
). Built the change and rebooted, confirming that the sequence was no longer emitted. Confirmed with DTrace to make sure using this one-liner:
dtrace -qn ' kbtrans_ascii_keypressed:entry { self->x = 1; printf("kbtrans_ascii_keypressed 0x%x\n", args[2]); } kbtrans_putbuf:entry /self->x/ { tracemem(args[0], 14, strlen((char *)args[0])); } kbtrans_ascii_keypressed:return { self->x = 0; }'
Pre-Change¶
On a system without the change, I pressed Print Screen twice and then Scroll Lock twice:
kbtrans_ascii_keypressed 0x46 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 0: 1b 5b 32 30 39 7a .[209z kbtrans_ascii_keypressed 0x46 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 0: 1b 5b 32 30 39 7a .[209z kbtrans_ascii_keypressed 0x47 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 0: 1b 5b 32 31 30 7a .[210z kbtrans_ascii_keypressed 0x47 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 0: 1b 5b 32 31 30 7a .[210z
Post-Change¶
On the fixed system, I did the same thing:
kbtrans_ascii_keypressed 0x46 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 0: 1b 5b 32 30 39 7a .[209z kbtrans_ascii_keypressed 0x46 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 0: 1b 5b 32 30 39 7a .[209z kbtrans_ascii_keypressed 0x47 kbtrans_ascii_keypressed 0x47
Confirmed that other interaction with the framebuffer console still works as expected (including the numbered function keys, etc).
Updated by Joshua M. Clulow over 1 year ago
Note that if you need the old behaviour back, there's a workaround variable you can set; i.e.,
mdb -kwe 'kbtrans_ignore_scroll_lock/W 0'
This will restore the original behaviour.
Updated by Electric Monk over 1 year ago
- Status changed from New to Closed
- % Done changed from 0 to 100
git commit 7d724debd861d6eb53233974d0191aeef122cd23
commit 7d724debd861d6eb53233974d0191aeef122cd23 Author: Joshua M. Clulow <josh@sysmgr.org> Date: 2019-08-01T22:05:50.000Z 11501 Scroll Lock translation to control sequence is patently unhelpful Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com> Reviewed by: Andy Fiddaman <omnios@citrus-it.co.uk> Reviewed by: Patrick Mooney <patrick.mooney@joyent.com> Reviewed by: Toomas Soome <tsoome@me.com> Approved by: Richard Lowe <richlowe@richlowe.net>