#include "types.h" #include "x86.h" #include "defs.h" #include "kbd.h" #include "posix.h" #include "vt.h" /* NVT -- how many terminals the chords reach */ #include "input.h" // The chord, settable at run time through VT_SETCHORD. Defaults to // Ctrl+Shift+F1..F6: the host's display manager binds Ctrl+Alt+F and // matches it loosely, so anything containing Ctrl+Alt never reaches a guest, // whatever else is held with it. Ctrl+Shift is not a VT chord on any host and // is not a character on any layout. // // Zero modifiers disables the chord entirely; `chvt N` still works. uint vt_chord_mods = CTL | SHIFT; uint vt_chord_base = SCAN_F1; int kbdgetc(void) { static uint shift; static uchar *charcode[4] = { normalmap, shiftmap, ctlmap, ctlmap }; uint st, data, c; st = inb(KBSTATP); if((st & KBS_DIB) == 0) return -1; if(st & 0x20) return -1; data = inb(KBDATAP); if(data == 0xE0){ shift |= E0ESC; return 0; } // Feed /dev/input/event0 before the byte is turned into a character. This // has to happen here rather than in a second handler because the byte can // only be read from the port once -- whoever reads it owes it to everyone // else. The console path below is untouched: both consumers see every key. input_ps2_scancode(data, (shift & E0ESC) != 0); // While something holds an exclusive grab on the keyboard, the console gets // nothing. The shift/caps state below is still tracked, so releasing the // grab does not leave the line discipline believing a modifier is held. if(input_is_grabbed(INPUT_KBD)){ if(data & 0x80){ data = (shift & E0ESC ? data : data & 0x7F); shift &= ~(shiftcode[data] | E0ESC); } else { shift |= shiftcode[data]; shift ^= togglecode[data]; } return 0; } if(data & 0x80){ data = (shift & E0ESC ? data : data & 0x7F); shift &= ~(shiftcode[data] | E0ESC); return 0; } else if(shift & E0ESC){ data |= 0x80; shift &= ~E0ESC; } shift |= shiftcode[data]; shift ^= togglecode[data]; // The switch chord, before the character tables, because there is no // character to look up: it is a combination that means "show me a different // terminal". What it means is decided in console.c, which is where the // terminals are; this only has to name it. See console_vt_hotkey(). // // The modifier test is an equality, not a mask. A mask fires on any superset, // so a chord aimed at the host would switch terminals behind your back. // // The modifier test is an equality, not a mask. `shift & ALT` would fire on // Ctrl+Alt+1 and on AltGr+1 as well, so a chord aimed at the host -- or a // Polish keystroke -- would switch terminals behind your back. Exactly left // Alt, and nothing else held. if (vt_chord_mods != 0 && (shift & (CTL | SHIFT | ALT | RALT)) == vt_chord_mods && data >= vt_chord_base && data < vt_chord_base + NVT) return KEY_VT_SWITCH + (data - vt_chord_base); c = charcode[shift & (CTL | SHIFT)][data]; if(shift & CAPSLOCK){ if('a' <= c && c <= 'z') c += 'A' - 'a'; else if('A' <= c && c <= 'Z') c += 'a' - 'A'; } return c; } void kbdintr(void) { consoleintr(kbdgetc); } // The two headers describe the same bits to two different audiences, and a // mismatch would be silent: a chord set from userspace would simply never // match, and the only symptom would be a key that does nothing. _Static_assert(VTC_SHIFT == SHIFT && VTC_CTRL == CTL && VTC_ALT == ALT && VTC_RALT == RALT, "include/posix.h VTC_* must mirror include/kbd.h modifiers");