[PS-1469] Ensure the window is focused when prompting for biometrics (#3534)
This commit is contained in:
parent
8b73658e54
commit
d2736fe035
|
@ -30,6 +30,8 @@ windows = {version = "0.32.0", features = [
|
||||||
"Win32_Foundation",
|
"Win32_Foundation",
|
||||||
"Win32_Security_Credentials",
|
"Win32_Security_Credentials",
|
||||||
"Win32_System_WinRT",
|
"Win32_System_WinRT",
|
||||||
|
"Win32_UI_Input_KeyboardAndMouse",
|
||||||
|
"Win32_UI_WindowsAndMessaging",
|
||||||
]}
|
]}
|
||||||
|
|
||||||
[target.'cfg(windows)'.dev-dependencies]
|
[target.'cfg(windows)'.dev-dependencies]
|
||||||
|
|
|
@ -1,19 +1,33 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use windows::{
|
use windows::{
|
||||||
core::factory, Foundation::IAsyncOperation, Security::Credentials::UI::*,
|
core::{factory, HSTRING},
|
||||||
Win32::Foundation::HWND, Win32::System::WinRT::IUserConsentVerifierInterop,
|
Foundation::IAsyncOperation,
|
||||||
|
Security::Credentials::UI::*,
|
||||||
|
Win32::{
|
||||||
|
Foundation::HWND,
|
||||||
|
System::WinRT::IUserConsentVerifierInterop,
|
||||||
|
UI::{
|
||||||
|
Input::KeyboardAndMouse::{
|
||||||
|
self, keybd_event, GetAsyncKeyState, SetFocus, KEYEVENTF_EXTENDEDKEY,
|
||||||
|
KEYEVENTF_KEYUP, VK_MENU,
|
||||||
|
},
|
||||||
|
WindowsAndMessaging::{self, SetForegroundWindow},
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn prompt(hwnd: Vec<u8>, message: String) -> Result<bool> {
|
pub fn prompt(hwnd: Vec<u8>, message: String) -> Result<bool> {
|
||||||
let interop = factory::<UserConsentVerifier, IUserConsentVerifierInterop>()?;
|
let h = isize::from_le_bytes(hwnd.clone().try_into().unwrap());
|
||||||
|
|
||||||
let h = isize::from_le_bytes(hwnd.try_into().unwrap());
|
|
||||||
let window = HWND(h);
|
let window = HWND(h);
|
||||||
|
|
||||||
let operation: IAsyncOperation<UserConsentVerificationResult> =
|
// The Windows Hello prompt is displayed inside the application window. For best result we
|
||||||
unsafe { interop.RequestVerificationForWindowAsync(window, message)? };
|
// should set the window to the foreground and focus it.
|
||||||
|
set_focus(window);
|
||||||
|
|
||||||
let result: UserConsentVerificationResult = operation.get()?;
|
let interop = factory::<UserConsentVerifier, IUserConsentVerifierInterop>()?;
|
||||||
|
let operation: IAsyncOperation<UserConsentVerificationResult> =
|
||||||
|
unsafe { interop.RequestVerificationForWindowAsync(window, &HSTRING::from(message))? };
|
||||||
|
let result = operation.get()?;
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
UserConsentVerificationResult::Verified => Ok(true),
|
UserConsentVerificationResult::Verified => Ok(true),
|
||||||
|
@ -31,6 +45,31 @@ pub fn available() -> Result<bool> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_focus(window: HWND) {
|
||||||
|
let mut pressed = false;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// Simulate holding down Alt key to bypass windows limitations
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate#return-value
|
||||||
|
// The most significant bit indicates if the key is currently being pressed. This means the
|
||||||
|
// value will be negative if the key is pressed.
|
||||||
|
if GetAsyncKeyState(VK_MENU.0 as i32) >= 0 {
|
||||||
|
pressed = true;
|
||||||
|
keybd_event(VK_MENU.0 as u8, 0, KEYEVENTF_EXTENDEDKEY, 0);
|
||||||
|
}
|
||||||
|
SetForegroundWindow(window);
|
||||||
|
SetFocus(window);
|
||||||
|
if pressed {
|
||||||
|
keybd_event(
|
||||||
|
VK_MENU.0 as u8,
|
||||||
|
0,
|
||||||
|
KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
Loading…
Reference in New Issue