summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--hw/input/ps2.c137
-rw-r--r--hw/input/trace-events1
2 files changed, 118 insertions, 20 deletions
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"