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