xref: /aosp_15_r20/external/crosvm/win_util/src/keyboard.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 windows::Win32::UI::Input::KeyboardAndMouse::GetKeyState;
6 
7 /// Extracts the scancode (scancode set #1 / IBM PC XT) from the l_param of a WM_KEY/WM_SYSKEY
8 /// event.
scancode_from_lparam(l_param: isize) -> u329 pub fn scancode_from_lparam(l_param: isize) -> u32 {
10     // Bits 16 - 23 of l_param contain the lower 8 bits of the scancode.
11     // https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-keyup
12     //
13     // Note: conversion from isize to u32 is safe because the bitwise &.
14     let lower_scancode = (l_param as u32 >> 16) & 0xFF;
15 
16     let is_extended_key = (l_param as u32 >> 24) & 1 == 1;
17     if is_extended_key {
18         // Extended keys have 16 bit scancodes of the form 0xe0YY, where YY is the
19         // lower_scancode extracted above.
20         lower_scancode | 0xe000
21     } else {
22         // Regular keys only use the lower 8 bits of the scancode.
23         lower_scancode
24     }
25 }
26 
27 /// Similar to keys_state, but returns false if any of the specified keys are up.
28 #[inline]
keys_down(keys: &[i32]) -> bool29 pub fn keys_down(keys: &[i32]) -> bool {
30     keys_state(keys).unwrap_or(false)
31 }
32 
33 /// Returns whether a list of keys are all down or all up, or None if they do not match.
34 /// Note that this does NOT work for toggle keys like the caps lock.
35 #[inline]
keys_state(keys: &[i32]) -> Option<bool>36 fn keys_state(keys: &[i32]) -> Option<bool> {
37     let mut all_down: Option<bool> = None;
38     for key in keys {
39         // If the high order bit is set, the key is down
40         // SAFETY: Trivially safe (no pointers, return code is checked).
41         let key_down = unsafe { GetKeyState(*key) } >> 15 & 0x1 == 0x1;
42         match all_down {
43             Some(other_keys_down) => {
44                 if other_keys_down != key_down {
45                     return None;
46                 }
47             }
48             None => all_down = Some(key_down),
49         }
50     }
51     all_down
52 }
53