Created
May 6, 2019 13:27
-
-
Save ykon/b6d87b86715e5da7fb8ebd0f41ee1764 to your computer and use it in GitHub Desktop.
RawInput in Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
[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