Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/gpu_display/src/gpu_display_win/keyboard_input_manager.rs
5394 views
1
// Copyright 2023 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use base::error;
6
use base::warn;
7
use linux_input_sys::constants::LED_CAPSL;
8
use linux_input_sys::constants::LED_NUML;
9
use linux_input_sys::virtio_input_event;
10
use sync::Mutex;
11
use winapi::shared::minwindef::BYTE;
12
use winapi::shared::minwindef::LPARAM;
13
use winapi::shared::minwindef::WPARAM;
14
use winapi::um::errhandlingapi::GetLastError;
15
use winapi::um::winuser::GetKeyboardState;
16
use winapi::um::winuser::MapVirtualKeyW;
17
use winapi::um::winuser::MAPVK_VK_TO_VSC;
18
use winapi::um::winuser::VK_CAPITAL;
19
use winapi::um::winuser::VK_NUMLOCK;
20
use winapi::um::winuser::VK_SCROLL;
21
22
use super::window::GuiWindow;
23
use super::window_message_dispatcher::DisplayEventDispatcher;
24
use crate::gpu_display_win::window_message_processor::WindowMessage;
25
use crate::keycode_converter::KeycodeTranslator;
26
use crate::keycode_converter::KeycodeTypes;
27
use crate::EventDeviceKind;
28
29
// From linux/include/uapi/linux/input-event-codes.h.
30
const LINUX_CAPS_LOCK_KEY: u16 = 58;
31
const LINUX_NUM_LOCK_KEY: u16 = 69;
32
33
pub struct KeyboardInputManager {
34
display_event_dispatcher: DisplayEventDispatcher,
35
keycode_translator: KeycodeTranslator,
36
guest_key_states: Mutex<KeyStates>,
37
}
38
39
impl KeyboardInputManager {
40
pub fn new(display_event_dispatcher: DisplayEventDispatcher) -> KeyboardInputManager {
41
Self {
42
display_event_dispatcher,
43
keycode_translator: KeycodeTranslator::new(KeycodeTypes::WindowsScancode),
44
guest_key_states: Mutex::new(KeyStates {
45
caps_lock_state: false,
46
num_lock_state: false,
47
}),
48
}
49
}
50
51
pub fn handle_window_message(&self, window: &GuiWindow, message: &WindowMessage) {
52
match message {
53
WindowMessage::WindowActivate { is_activated } => {
54
self.handle_window_activate(window, *is_activated)
55
}
56
WindowMessage::KeyboardFocus => self.sync_key_states(window),
57
WindowMessage::Key {
58
is_sys_key: _,
59
is_down,
60
w_param,
61
l_param,
62
} => self.handle_host_key_event(window, *is_down, *w_param, *l_param),
63
_ => (),
64
}
65
}
66
67
pub fn handle_guest_event(&self, window: &GuiWindow, event: virtio_input_event) {
68
if let Some(numlock_on) = event.get_led_state(LED_NUML) {
69
self.guest_key_states.lock().num_lock_state = numlock_on;
70
self.sync_key_states(window);
71
} else if let Some(capslock_on) = event.get_led_state(LED_CAPSL) {
72
self.guest_key_states.lock().caps_lock_state = capslock_on;
73
self.sync_key_states(window);
74
}
75
}
76
77
#[inline]
78
fn handle_window_activate(&self, window: &GuiWindow, is_activated: bool) {
79
if !is_activated {
80
// To avoid sticky keys, we release keys when our window is deactivated. This prevents
81
// common shortcuts like Alt+Tab from leaving a stuck alt key in the guest.
82
self.release_any_down_keys(window);
83
}
84
// If either caps lock or num lock is set, reflect that change in the guest.
85
self.sync_key_states(window);
86
}
87
88
#[inline]
89
fn handle_host_key_event(
90
&self,
91
window: &GuiWindow,
92
key_down: bool,
93
_w_param: WPARAM,
94
l_param: LPARAM,
95
) {
96
let scancode = win_util::scancode_from_lparam(l_param);
97
let is_repeat = key_down && get_previous_key_down_from_lparam(l_param);
98
if let Some(linux_keycode) = self.keycode_translator.translate(scancode) {
99
self.dispatch_linux_key_event(window, linux_keycode, key_down, is_repeat)
100
} else {
101
error!("Unhandled scancode while handling key event.");
102
}
103
}
104
105
/// Checks if the caps lock and num lock key states differ between the guest & host. If they do,
106
/// send keys to the guest to resync it with the host.
107
fn sync_key_states(&self, window: &GuiWindow) {
108
if let Some(host_key_states) = get_host_key_states() {
109
let mut toggle_caps_lock = false;
110
let mut toggle_num_lock = false;
111
{
112
let states = self.guest_key_states.lock();
113
if states.caps_lock_state != host_key_states.caps_lock_state {
114
toggle_caps_lock = true;
115
}
116
if states.num_lock_state != host_key_states.num_lock_state {
117
toggle_num_lock = true;
118
}
119
}
120
if toggle_caps_lock {
121
self.press_and_release_key(window, LINUX_CAPS_LOCK_KEY);
122
}
123
if toggle_num_lock {
124
self.press_and_release_key(window, LINUX_NUM_LOCK_KEY);
125
}
126
}
127
}
128
129
/// Releases any keys that are down when the surface is no longer active. Should be called when
130
/// the display window becomes inactive to avoid sticky keys.
131
#[inline]
132
fn release_any_down_keys(&self, window: &GuiWindow) {
133
let mut events = Vec::with_capacity(256);
134
let mut keyboard_state: [u8; 256] = [0; 256];
135
// SAFETY:
136
// Safe because `keyboard_state` is guaranteed to exist, and is of the expected size.
137
if unsafe { GetKeyboardState(keyboard_state.as_mut_ptr()) } == 0 {
138
error!(
139
"Failed in GetKeyboardState: {}",
140
// SAFETY: trivially safe
141
unsafe { GetLastError() }
142
);
143
return;
144
}
145
146
for (virtual_keycode, key_state) in keyboard_state.iter().enumerate() {
147
// Safe because virtual_keycode < 256.
148
let virtual_keycode = virtual_keycode as i32;
149
150
// Ignore toggle keys.
151
if virtual_keycode == VK_CAPITAL
152
|| virtual_keycode == VK_NUMLOCK
153
|| virtual_keycode == VK_SCROLL
154
{
155
continue;
156
}
157
if key_state >> 7 == 0u8 {
158
// Key is already up.
159
continue;
160
}
161
162
// SAFETY:
163
// Trivially safe (no pointers or errors to check).
164
let scancode = unsafe { MapVirtualKeyW(virtual_keycode as u32, MAPVK_VK_TO_VSC) };
165
if let Some(linux_keycode) = self.keycode_translator.translate(scancode) {
166
events.push(virtio_input_event::key(linux_keycode, false, false));
167
} else {
168
error!("Failed to translate key while releasing down keys.");
169
}
170
}
171
172
if !events.is_empty() {
173
self.display_event_dispatcher.dispatch(
174
window,
175
events.as_slice(),
176
EventDeviceKind::Keyboard,
177
);
178
}
179
}
180
181
/// Sends a key press and release event to Linux/Android.
182
fn press_and_release_key(&self, window: &GuiWindow, key: u16) {
183
self.dispatch_linux_key_event(
184
window, key, /* key_down= */ true, /* is_repeat= */ false,
185
);
186
self.dispatch_linux_key_event(
187
window, key, /* key_down= */ false, /* is_repeat= */ false,
188
);
189
}
190
191
/// Directly dispatches a Linux input keycode to the guest.
192
fn dispatch_linux_key_event(
193
&self,
194
window: &GuiWindow,
195
linux_keycode: u16,
196
key_down: bool,
197
is_repeat: bool,
198
) {
199
self.display_event_dispatcher.dispatch(
200
window,
201
&[virtio_input_event::key(linux_keycode, key_down, is_repeat)],
202
EventDeviceKind::Keyboard,
203
);
204
}
205
}
206
207
struct KeyStates {
208
caps_lock_state: bool,
209
num_lock_state: bool,
210
}
211
212
/// On success, returns a tuple containing current state of caps lock and num lock keys.
213
fn get_host_key_states() -> Option<KeyStates> {
214
let mut keyboard_state: [BYTE; 256] = [0; 256];
215
// SAFETY:
216
// Safe because `keyboard_state` is guaranteed to exist, and is of the expected size.
217
if unsafe { GetKeyboardState(keyboard_state.as_mut_ptr()) } != 0 {
218
Some(KeyStates {
219
caps_lock_state: toggle_to_bool(keyboard_state[VK_CAPITAL as usize]),
220
num_lock_state: toggle_to_bool(keyboard_state[VK_NUMLOCK as usize]),
221
})
222
} else {
223
warn!(
224
"Failed in GetKeyboardState: {}",
225
// SAFETY: trivially safe
226
unsafe { GetLastError() }
227
);
228
None
229
}
230
}
231
232
/// Returns whether the given toggle key state indicates the key is toggled/on (true).
233
fn toggle_to_bool(key_state: BYTE) -> bool {
234
key_state & 0x1 == 0x1
235
}
236
237
/// Extracts the previous key up/down state from the l_param of a WM_KEY/WM_SYSKEY DOWN event.
238
/// The previous key state is bit #30.
239
fn get_previous_key_down_from_lparam(l_param: isize) -> bool {
240
((l_param >> 30) & 1) == 1
241
}
242
243