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 Workerpub 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 Workerpub 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 Workerfn 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