diff --git a/hw/input/ps2.c b/hw/input/ps2.c index dff3f1e024..1e6f6ae9b6 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -78,6 +78,14 @@ #define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */ +/* Bits for 'modifiers' field in PS2KbdState */ +#define MOD_CTRL_L (1 << 0) +#define MOD_SHIFT_L (1 << 1) +#define MOD_ALT_L (1 << 2) +#define MOD_CTRL_R (1 << 3) +#define MOD_SHIFT_R (1 << 4) +#define MOD_ALT_R (1 << 5) + typedef struct { /* Keep the data array 256 bytes long, which compatibility with older qemu versions. */ @@ -99,6 +107,7 @@ typedef struct { int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ int ledstate; bool need_high_bit; + unsigned int modifiers; /* bitmask of MOD_* constants above */ } PS2KbdState; typedef struct { @@ -545,6 +554,26 @@ static uint8_t translate_table[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, }; +static unsigned int ps2_modifier_bit(QKeyCode key) +{ + switch (key) { + case Q_KEY_CODE_CTRL: + return MOD_CTRL_L; + case Q_KEY_CODE_CTRL_R: + return MOD_CTRL_R; + case Q_KEY_CODE_SHIFT: + return MOD_SHIFT_L; + case Q_KEY_CODE_SHIFT_R: + return MOD_SHIFT_R; + case Q_KEY_CODE_ALT: + return MOD_ALT_L; + case Q_KEY_CODE_ALT_R: + return MOD_ALT_R; + default: + return 0; + } +} + static void ps2_reset_queue(PS2State *s) { PS2Queue *q = &s->queue; @@ -596,11 +625,20 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, InputKeyEvent *key = evt->u.key.data; int qcode; uint16_t keycode; + int mod; qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); assert(evt->type == INPUT_EVENT_KIND_KEY); qcode = qemu_input_key_value_to_qcode(key->key); + mod = ps2_modifier_bit(qcode); + trace_ps2_keyboard_event(s, qcode, key->down, mod, s->modifiers); + if (key->down) { + s->modifiers |= mod; + } else { + s->modifiers &= ~mod; + } + if (s->scancode_set == 1) { if (qcode == Q_KEY_CODE_PAUSE) { if (key->down) { @@ -612,16 +650,42 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, ps2_put_keycode(s, 0xc5); } } else if (qcode == Q_KEY_CODE_PRINT) { - if (key->down) { - ps2_put_keycode(s, 0xe0); - ps2_put_keycode(s, 0x2a); - ps2_put_keycode(s, 0xe0); - ps2_put_keycode(s, 0x37); + if (s->modifiers & MOD_ALT_L) { + if (key->down) { + ps2_put_keycode(s, 0xb8); + ps2_put_keycode(s, 0x38); + ps2_put_keycode(s, 0x54); + } else { + ps2_put_keycode(s, 0xd4); + ps2_put_keycode(s, 0xb8); + ps2_put_keycode(s, 0x38); + } + } else if (s->modifiers & MOD_ALT_R) { + if (key->down) { + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0xb8); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0x38); + ps2_put_keycode(s, 0x54); + } else { + ps2_put_keycode(s, 0xd4); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0xb8); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0x38); + } } else { - ps2_put_keycode(s, 0xe0); - ps2_put_keycode(s, 0xb7); - ps2_put_keycode(s, 0xe0); - ps2_put_keycode(s, 0xaa); + if (key->down) { + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0x2a); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0x37); + } else { + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0xb7); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0xaa); + } } } else { keycode = qcode_to_keycode_set1[qcode]; @@ -651,18 +715,50 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, ps2_put_keycode(s, 0x77); } } else if (qcode == Q_KEY_CODE_PRINT) { - if (key->down) { - ps2_put_keycode(s, 0xe0); - ps2_put_keycode(s, 0x12); - ps2_put_keycode(s, 0xe0); - ps2_put_keycode(s, 0x7c); + if (s->modifiers & MOD_ALT_L) { + if (key->down) { + ps2_put_keycode(s, 0xf0); + ps2_put_keycode(s, 0x11); + ps2_put_keycode(s, 0x11); + ps2_put_keycode(s, 0x84); + } else { + ps2_put_keycode(s, 0xf0); + ps2_put_keycode(s, 0x84); + ps2_put_keycode(s, 0xf0); + ps2_put_keycode(s, 0x11); + ps2_put_keycode(s, 0x11); + } + } else if (s->modifiers & MOD_ALT_R) { + if (key->down) { + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0xf0); + ps2_put_keycode(s, 0x11); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0x11); + ps2_put_keycode(s, 0x84); + } else { + ps2_put_keycode(s, 0xf0); + ps2_put_keycode(s, 0x84); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0xf0); + ps2_put_keycode(s, 0x11); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0x11); + } } else { - ps2_put_keycode(s, 0xe0); - ps2_put_keycode(s, 0xf0); - ps2_put_keycode(s, 0x7c); - ps2_put_keycode(s, 0xe0); - ps2_put_keycode(s, 0xf0); - ps2_put_keycode(s, 0x12); + if (key->down) { + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0x12); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0x7c); + } else { + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0xf0); + ps2_put_keycode(s, 0x7c); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0xf0); + ps2_put_keycode(s, 0x12); + } } } else { keycode = qcode_to_keycode_set2[qcode]; @@ -1125,6 +1221,7 @@ static void ps2_kbd_reset(void *opaque) s->scan_enabled = 0; s->translate = 0; s->scancode_set = 2; + s->modifiers = 0; } static void ps2_mouse_reset(void *opaque) diff --git a/hw/input/trace-events b/hw/input/trace-events index d04132d342..88150ef7a6 100644 --- a/hw/input/trace-events +++ b/hw/input/trace-events @@ -2,6 +2,7 @@ # hw/input/ps2.c ps2_put_keycode(void *opaque, int keycode) "%p keycode 0x%02x" +ps2_keyboard_event(void *opaque, int qcode, int down, unsigned int modifier, unsigned int modifiers) "%p qcode %d down %d modifier 0x%x modifiers 0x%x" ps2_read_data(void *opaque) "%p" ps2_set_ledstate(void *s, int ledstate) "%p ledstate %d" ps2_reset_keyboard(void *s) "%p"