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