master
c 150 lines 3.77 KB
Raw
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 "standard-headers/linux/input-event-codes.h"
9 #include "ui/console.h"
10 #include "ui/input.h"
11 #include "ui/kbd-state.h"
12
13 struct QKbdState {
14 QemuConsole *con;
15 int key_delay_ms;
16 DECLARE_BITMAP(keys, KEY_CNT);
17 DECLARE_BITMAP(mods, QKBD_MOD__MAX);
18 };
19
20 static void qkbd_state_modifier_update(QKbdState *kbd,
21 unsigned int lnx1, unsigned int lnx2,
22 QKbdModifier mod)
23 {
24 if (test_bit(lnx1, kbd->keys) || test_bit(lnx2, kbd->keys)) {
25 set_bit(mod, kbd->mods);
26 } else {
27 clear_bit(mod, kbd->mods);
28 }
29 }
30
31 bool qkbd_state_modifier_get(QKbdState *kbd, QKbdModifier mod)
32 {
33 return test_bit(mod, kbd->mods);
34 }
35
36 bool qkbd_state_key_get(QKbdState *kbd, unsigned int lnx)
37 {
38 return lnx < KEY_CNT && test_bit(lnx, kbd->keys);
39 }
40
41 void qkbd_state_key_event(QKbdState *kbd, unsigned int lnx, bool down)
42 {
43 bool state;
44
45 if (lnx >= KEY_CNT) {
46 return;
47 }
48
49 state = test_bit(lnx, kbd->keys);
50
51 if (down == false /* got key-up event */ &&
52 state == false /* key is not pressed */) {
53 /*
54 * Filter out suspicious key-up events.
55 *
56 * This allows simply sending along all key-up events, and
57 * this function will filter out everything where the
58 * corresponding key-down event wasn't sent to the guest, for
59 * example due to being a host hotkey.
60 *
61 * Note that key-down events on already pressed keys are *not*
62 * suspicious, those are keyboard autorepeat events.
63 */
64 return;
65 }
66
67 /* update key and modifier state */
68 if (down) {
69 set_bit(lnx, kbd->keys);
70 } else {
71 clear_bit(lnx, kbd->keys);
72 }
73 switch (lnx) {
74 case KEY_LEFTSHIFT:
75 case KEY_RIGHTSHIFT:
76 qkbd_state_modifier_update(kbd, KEY_LEFTSHIFT, KEY_RIGHTSHIFT,
77 QKBD_MOD_SHIFT);
78 break;
79 case KEY_LEFTCTRL:
80 case KEY_RIGHTCTRL:
81 qkbd_state_modifier_update(kbd, KEY_LEFTCTRL, KEY_RIGHTCTRL,
82 QKBD_MOD_CTRL);
83 break;
84 case KEY_LEFTALT:
85 qkbd_state_modifier_update(kbd, KEY_LEFTALT, KEY_LEFTALT,
86 QKBD_MOD_ALT);
87 break;
88 case KEY_RIGHTALT:
89 qkbd_state_modifier_update(kbd, KEY_RIGHTALT, KEY_RIGHTALT,
90 QKBD_MOD_ALTGR);
91 break;
92 case KEY_CAPSLOCK:
93 if (down) {
94 change_bit(QKBD_MOD_CAPSLOCK, kbd->mods);
95 }
96 break;
97 case KEY_NUMLOCK:
98 if (down) {
99 change_bit(QKBD_MOD_NUMLOCK, kbd->mods);
100 }
101 break;
102 default:
103 /* keep gcc happy */
104 break;
105 }
106
107 /* send to guest */
108 if (qemu_console_is_graphic(kbd->con)) {
109 qemu_input_event_send_key_linux(kbd->con, lnx, down);
110 if (kbd->key_delay_ms) {
111 qemu_input_event_send_key_delay(kbd->key_delay_ms);
112 }
113 }
114 }
115
116 void qkbd_state_lift_all_keys(QKbdState *kbd)
117 {
118 unsigned int lnx;
119
120 for (lnx = 0; lnx < KEY_CNT; lnx++) {
121 if (test_bit(lnx, kbd->keys)) {
122 qkbd_state_key_event(kbd, lnx, false);
123 }
124 }
125 }
126
127 void qkbd_state_switch_console(QKbdState *kbd, QemuConsole *con)
128 {
129 qkbd_state_lift_all_keys(kbd);
130 kbd->con = con;
131 }
132
133 void qkbd_state_set_delay(QKbdState *kbd, int delay_ms)
134 {
135 kbd->key_delay_ms = delay_ms;
136 }
137
138 void qkbd_state_free(QKbdState *kbd)
139 {
140 g_free(kbd);
141 }
142
143 QKbdState *qkbd_state_init(QemuConsole *con)
144 {
145 QKbdState *kbd = g_new0(QKbdState, 1);
146
147 kbd->con = con;
148
149 return kbd;
150 }