Skip to content

Instantly share code, notes, and snippets.

@ykon
Created May 6, 2019 13:27
Show Gist options
  • Save ykon/b6d87b86715e5da7fb8ebd0f41ee1764 to your computer and use it in GitHub Desktop.
Save ykon/b6d87b86715e5da7fb8ebd0f41ee1764 to your computer and use it in GitHub Desktop.
RawInput in Rust
/*
[dependencies]
widestring = "0.4.0"
lazy_static = "1.3.0"
[dependencies.winapi]
version = "0.3.7"
features = ["winuser", "winbase", "libloaderapi", "hidusage"]
*/
#[macro_use] extern crate lazy_static;
use std::mem;
use std::ptr;
use std::alloc::{alloc, dealloc, Layout};
use winapi::{
um::{
winuser::{
RegisterRawInputDevices, DefWindowProcW, RegisterWindowMessageW, GetRawInputData,
WNDCLASSEXW, RAWINPUTHEADER, RAWINPUTDEVICE,
WM_INPUT, WM_QUERYENDSESSION, RID_INPUT, HRAWINPUT, RAWINPUT, RIM_TYPEMOUSE, MOUSE_MOVE_RELATIVE,
RIDEV_INPUTSINK, RegisterClassExW, CreateWindowExW, ChangeWindowMessageFilterEx,
GetMessageW, TranslateMessage, DispatchMessageW, MSG, LPMSG
},
libloaderapi::{ GetModuleHandleW },
},
shared::{
windef::{ HWND },
minwindef::{ UINT, WPARAM, LPARAM, LRESULT, LPVOID, DWORD, PUINT, HINSTANCE },
hidusage::{
HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_MOUSE
}
},
};
use widestring::U16CString;
const MSGFLT_ALLOW: DWORD = 1;
lazy_static! {
static ref WM_TASKBAR_CREATED: UINT = unsafe {
RegisterWindowMessageW(U16CString::from_str("TaskbarCreated").unwrap().as_ptr())
};
static ref CB_SIZE_HEADER: UINT = mem::size_of::<RAWINPUTHEADER>() as UINT;
static ref CLASS_NAME: U16CString = U16CString::from_str("W10Wheel/R_WM").unwrap();
}
unsafe fn proc_raw_input(l_param: LPARAM) -> bool {
let mut pcb_size = 0;
let is_mouse_move_relative = |ri: RAWINPUT| {
ri.header.dwType == RIM_TYPEMOUSE && ri.data.mouse().usFlags == MOUSE_MOVE_RELATIVE
};
let get_raw_input_data = |data: LPVOID, size: PUINT| {
GetRawInputData(l_param as HRAWINPUT, RID_INPUT, data, size, *CB_SIZE_HEADER)
};
if get_raw_input_data(ptr::null_mut(), &mut pcb_size) == 0 {
let layout = Layout::from_size_align(pcb_size as usize, 1).unwrap();
let data = alloc(layout);
let mut res = false;
if get_raw_input_data(data as LPVOID, &mut pcb_size) == pcb_size {
let ri = std::ptr::read(data as *const RAWINPUT);
if is_mouse_move_relative(ri) {
let mouse = ri.data.mouse();
println!("{}, {}", mouse.lLastX, mouse.lLastY);
res = true;
}
}
dealloc(data, layout);
return res;
}
false
}
unsafe extern "system" fn window_proc(hwnd: HWND, msg: UINT, w_param: WPARAM, l_param: LPARAM) -> LRESULT {
match msg {
WM_INPUT => {
if proc_raw_input(l_param) {
return 0;
}
},
WM_QUERYENDSESSION => {
return 0;
},
_ => {
if msg == *WM_TASKBAR_CREATED {
return 0;
}
},
};
DefWindowProcW(hwnd, msg, w_param, l_param)
}
unsafe fn message_loop(msg: LPMSG) {
loop {
if GetMessageW(msg, ptr::null_mut(), 0, 0) == 0 {
return;
}
TranslateMessage(msg);
DispatchMessageW(msg);
}
}
fn make_window_class(h_instance: HINSTANCE) -> WNDCLASSEXW {
WNDCLASSEXW {
cbSize: (mem::size_of::<WNDCLASSEXW>()) as UINT,
cbClsExtra: 0,
cbWndExtra: 0,
hbrBackground: ptr::null_mut(),
hCursor: ptr::null_mut(),
hIcon: ptr::null_mut(),
hIconSm: ptr::null_mut(),
hInstance: h_instance,
lpfnWndProc: Some(window_proc),
lpszClassName: CLASS_NAME.as_ptr(),
lpszMenuName: ptr::null_mut(),
style: 0,
}
}
fn make_raw_input_device(hwnd: HWND) -> RAWINPUTDEVICE {
RAWINPUTDEVICE {
usUsagePage: HID_USAGE_PAGE_GENERIC,
usUsage: HID_USAGE_GENERIC_MOUSE,
dwFlags: RIDEV_INPUTSINK,
hwndTarget: hwnd,
}
}
fn main() {
unsafe {
let h_instance = GetModuleHandleW(ptr::null());
let window_class = make_window_class(h_instance);
if RegisterClassExW(&window_class) != 0 {
let hwnd = CreateWindowExW(0, CLASS_NAME.as_ptr(), ptr::null_mut(), 0, 0, 0, 0, 0, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), ptr::null_mut());
ChangeWindowMessageFilterEx(hwnd, *WM_TASKBAR_CREATED, MSGFLT_ALLOW, ptr::null_mut());
let rid = make_raw_input_device(hwnd);
let mut rid_array = vec![rid];
RegisterRawInputDevices(rid_array.as_mut_ptr(), 1, mem::size_of::<RAWINPUTDEVICE>() as UINT);
let layout = Layout::new::<MSG>();
let msg = alloc(layout);
message_loop(msg as LPMSG);
dealloc(msg, layout);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment