Merge pull request #21 from h4ssi/switch-to-uac-desktop-and-retry-send-input

Retry `SendInput` after switching desktops upon initial failure
This commit is contained in:
htrefil 2023-04-16 11:50:51 +02:00 committed by GitHub
commit 2d45ae6e5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 3 deletions

View file

@ -86,6 +86,7 @@ Regardless, if you want a working and stable solution for crossplatform keyboard
## Limitations
- Only keyboard and relative mouse events work (that is, can be forwarded to clients)
- Clients only are supported on Windows, however, server support will be added in the future
- When Windows UAC is active the client needs elevated privileges to function properly. You may need to run the client in the System account (e.g. `psexec -sid client ...`)
## Project structure
- `server` - server application code

View file

@ -4,7 +4,7 @@ use std::time::{Duration, Instant};
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
use tokio::sync::oneshot::{self, Receiver};
use tokio::time;
use winapi::um::winuser::{self, INPUT};
use winapi::um::winuser::{self, DESKTOP_JOURNALPLAYBACK, INPUT};
pub struct EventWriter {
event_sender: UnboundedSender<Event>,
@ -98,9 +98,41 @@ fn write_raw(events: &mut [INPUT]) -> Result<(), Error> {
)
};
if written != 1 {
if written == 0 {
let original = unsafe {
winuser::GetThreadDesktop(winapi::um::processthreadsapi::GetCurrentThreadId())
};
if original.is_null() {
return Err(Error::last_os_error());
}
let other =
unsafe { winuser::OpenInputDesktop(0 as _, 0 as _, DESKTOP_JOURNALPLAYBACK as _) };
if other.is_null() {
return Err(Error::last_os_error());
}
if unsafe { winuser::SetThreadDesktop(other) } == 0 {
return Err(Error::last_os_error());
}
let written = unsafe {
winuser::SendInput(
events.len() as _,
events.as_mut_ptr(),
std::mem::size_of_val(&events[0]) as _,
)
};
if written == 0 {
return Err(Error::last_os_error());
}
if unsafe { winuser::SetThreadDesktop(original) } == 0 {
return Err(Error::last_os_error());
}
if unsafe { winuser::CloseDesktop(other) } == 0 {
return Err(Error::last_os_error());
}
}
Ok(())
}