This commit is contained in:
Todd Martin 2022-09-15 10:17:51 -04:00
commit 722c73580b
2 changed files with 49 additions and 8 deletions

View File

@ -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]

View File

@ -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::*;