summaryrefslogtreecommitdiff
path: root/hw/input/ps2.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/input/ps2.c')
-rw-r--r--hw/input/ps2.c137
1 files changed, 117 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)