1 | /* |
2 | * This work is licensed under the terms of the GNU GPL, version 2 or |
3 | * (at your option) any later version. See the COPYING file in the |
4 | * top-level directory. |
5 | */ |
6 | #include "qemu/osdep.h" |
7 | #include "qemu/bitmap.h" |
8 | #include "ui/console.h" |
9 | #include "ui/input.h" |
10 | #include "ui/kbd-state.h" |
11 | |
12 | struct QKbdState { |
13 | QemuConsole *con; |
14 | int key_delay_ms; |
15 | DECLARE_BITMAP(keys, Q_KEY_CODE__MAX); |
16 | DECLARE_BITMAP(mods, QKBD_MOD__MAX); |
17 | }; |
18 | |
19 | static void qkbd_state_modifier_update(QKbdState *kbd, |
20 | QKeyCode qcode1, QKeyCode qcode2, |
21 | QKbdModifier mod) |
22 | { |
23 | if (test_bit(qcode1, kbd->keys) || test_bit(qcode2, kbd->keys)) { |
24 | set_bit(mod, kbd->mods); |
25 | } else { |
26 | clear_bit(mod, kbd->mods); |
27 | } |
28 | } |
29 | |
30 | bool qkbd_state_modifier_get(QKbdState *kbd, QKbdModifier mod) |
31 | { |
32 | return test_bit(mod, kbd->mods); |
33 | } |
34 | |
35 | bool qkbd_state_key_get(QKbdState *kbd, QKeyCode qcode) |
36 | { |
37 | return test_bit(qcode, kbd->keys); |
38 | } |
39 | |
40 | void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down) |
41 | { |
42 | bool state = test_bit(qcode, kbd->keys); |
43 | |
44 | if (down == false /* got key-up event */ && |
45 | state == false /* key is not pressed */) { |
46 | /* |
47 | * Filter out suspicious key-up events. |
48 | * |
49 | * This allows simply sending along all key-up events, and |
50 | * this function will filter out everything where the |
51 | * corresponding key-down event wasn't sent to the guest, for |
52 | * example due to being a host hotkey. |
53 | * |
54 | * Note that key-down events on already pressed keys are *not* |
55 | * suspicious, those are keyboard autorepeat events. |
56 | */ |
57 | return; |
58 | } |
59 | |
60 | /* update key and modifier state */ |
61 | if (down) { |
62 | set_bit(qcode, kbd->keys); |
63 | } else { |
64 | clear_bit(qcode, kbd->keys); |
65 | } |
66 | switch (qcode) { |
67 | case Q_KEY_CODE_SHIFT: |
68 | case Q_KEY_CODE_SHIFT_R: |
69 | qkbd_state_modifier_update(kbd, Q_KEY_CODE_SHIFT, Q_KEY_CODE_SHIFT_R, |
70 | QKBD_MOD_SHIFT); |
71 | break; |
72 | case Q_KEY_CODE_CTRL: |
73 | case Q_KEY_CODE_CTRL_R: |
74 | qkbd_state_modifier_update(kbd, Q_KEY_CODE_CTRL, Q_KEY_CODE_CTRL_R, |
75 | QKBD_MOD_CTRL); |
76 | break; |
77 | case Q_KEY_CODE_ALT: |
78 | qkbd_state_modifier_update(kbd, Q_KEY_CODE_ALT, Q_KEY_CODE_ALT, |
79 | QKBD_MOD_ALT); |
80 | break; |
81 | case Q_KEY_CODE_ALT_R: |
82 | qkbd_state_modifier_update(kbd, Q_KEY_CODE_ALT_R, Q_KEY_CODE_ALT_R, |
83 | QKBD_MOD_ALTGR); |
84 | break; |
85 | case Q_KEY_CODE_CAPS_LOCK: |
86 | if (down) { |
87 | change_bit(QKBD_MOD_CAPSLOCK, kbd->mods); |
88 | } |
89 | break; |
90 | case Q_KEY_CODE_NUM_LOCK: |
91 | if (down) { |
92 | change_bit(QKBD_MOD_NUMLOCK, kbd->mods); |
93 | } |
94 | break; |
95 | default: |
96 | /* keep gcc happy */ |
97 | break; |
98 | } |
99 | |
100 | /* send to guest */ |
101 | if (qemu_console_is_graphic(kbd->con)) { |
102 | qemu_input_event_send_key_qcode(kbd->con, qcode, down); |
103 | if (kbd->key_delay_ms) { |
104 | qemu_input_event_send_key_delay(kbd->key_delay_ms); |
105 | } |
106 | } |
107 | } |
108 | |
109 | void qkbd_state_lift_all_keys(QKbdState *kbd) |
110 | { |
111 | int qcode; |
112 | |
113 | for (qcode = 0; qcode < Q_KEY_CODE__MAX; qcode++) { |
114 | if (test_bit(qcode, kbd->keys)) { |
115 | qkbd_state_key_event(kbd, qcode, false); |
116 | } |
117 | } |
118 | } |
119 | |
120 | void qkbd_state_set_delay(QKbdState *kbd, int delay_ms) |
121 | { |
122 | kbd->key_delay_ms = delay_ms; |
123 | } |
124 | |
125 | void qkbd_state_free(QKbdState *kbd) |
126 | { |
127 | g_free(kbd); |
128 | } |
129 | |
130 | QKbdState *qkbd_state_init(QemuConsole *con) |
131 | { |
132 | QKbdState *kbd = g_new0(QKbdState, 1); |
133 | |
134 | kbd->con = con; |
135 | |
136 | return kbd; |
137 | } |
138 | |