diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/win32/callback.rs | 21 | ||||
-rw-r--r-- | src/win32/init.rs | 5 | ||||
-rw-r--r-- | src/win32/mod.rs | 70 |
3 files changed, 92 insertions, 4 deletions
diff --git a/src/win32/callback.rs b/src/win32/callback.rs index bbf5b55..1cfb640 100644 --- a/src/win32/callback.rs +++ b/src/win32/callback.rs @@ -1,3 +1,4 @@ +use std::mem; use std::rc::Rc; use std::cell::RefCell; use std::sync::mpsc::Sender; @@ -176,6 +177,26 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT, 0 }, + winapi::WM_INPUT => { + let mut data: winapi::RAWINPUT = mem::uninitialized(); + let mut data_size = mem::size_of::<winapi::RAWINPUT>() as winapi::UINT; + user32::GetRawInputData(mem::transmute(lparam), winapi::RID_INPUT, + mem::transmute(&mut data), &mut data_size, + mem::size_of::<winapi::RAWINPUTHEADER>() as winapi::UINT); + + if data.header.dwType == winapi::RIM_TYPEMOUSE { + let _x = data.mouse.lLastX; // FIXME: this is not always the relative movement + let _y = data.mouse.lLastY; + // TODO: + //send_event(window, Event::MouseRawMovement { x: x, y: y }); + + 0 + + } else { + user32::DefWindowProcW(window, msg, wparam, lparam) + } + }, + winapi::WM_SETFOCUS => { use events::Event::Focused; send_event(window, Focused(true)); diff --git a/src/win32/init.rs b/src/win32/init.rs index 08d54c0..c5e18cc 100644 --- a/src/win32/init.rs +++ b/src/win32/init.rs @@ -15,11 +15,13 @@ use Api; use BuilderAttribs; use CreationError; use CreationError::OsError; +use CursorState; use GlRequest; use PixelFormat; use std::ffi::CString; use std::sync::mpsc::channel; +use std::sync::Mutex; use libc; use super::gl; @@ -250,6 +252,7 @@ unsafe fn init(title: Vec<u16>, builder: BuilderAttribs<'static>, gl_library: gl_library, events_receiver: events_receiver, is_closed: AtomicBool::new(false), + cursor_state: Mutex::new(CursorState::Normal), }) } @@ -265,7 +268,7 @@ unsafe fn register_window_class() -> Vec<u16> { cbWndExtra: 0, hInstance: kernel32::GetModuleHandleW(ptr::null()), hIcon: ptr::null_mut(), - hCursor: ptr::null_mut(), + hCursor: ptr::null_mut(), // must be null in order for cursor state to work properly hbrBackground: ptr::null_mut(), lpszMenuName: ptr::null(), lpszClassName: class_name.as_ptr(), diff --git a/src/win32/mod.rs b/src/win32/mod.rs index 41004b3..e20d8b7 100644 --- a/src/win32/mod.rs +++ b/src/win32/mod.rs @@ -1,6 +1,8 @@ use std::sync::atomic::AtomicBool; +use std::mem; use std::ptr; use std::ffi::CString; +use std::sync::Mutex; use std::sync::mpsc::Receiver; use libc; use {CreationError, Event, MouseCursor}; @@ -43,6 +45,9 @@ pub struct Window { /// True if a `Closed` event has been received. is_closed: AtomicBool, + + /// The current cursor state. + cursor_state: Mutex<CursorState>, } unsafe impl Send for Window {} @@ -148,7 +153,6 @@ impl Window { /// See the docs in the crate root file. pub fn get_inner_size(&self) -> Option<(u32, u32)> { - use std::mem; let mut rect: winapi::RECT = unsafe { mem::uninitialized() }; if unsafe { user32::GetClientRect(self.window.0, &mut rect) } == 0 { @@ -163,7 +167,6 @@ impl Window { /// See the docs in the crate root file. pub fn get_outer_size(&self) -> Option<(u32, u32)> { - use std::mem; let mut rect: winapi::RECT = unsafe { mem::uninitialized() }; if unsafe { user32::GetWindowRect(self.window.0, &mut rect) } == 0 { @@ -257,7 +260,68 @@ impl Window { } pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> { - unimplemented!(); + let mut current_state = self.cursor_state.lock().unwrap(); + + let foreground_thread_id = unsafe { user32::GetWindowThreadProcessId(self.window.0, ptr::null_mut()) }; + let current_thread_id = unsafe { kernel32::GetCurrentThreadId() }; + + unsafe { user32::AttachThreadInput(foreground_thread_id, current_thread_id, 1) }; + + let res = match (state, *current_state) { + (CursorState::Normal, CursorState::Normal) => Ok(()), + (CursorState::Hide, CursorState::Hide) => Ok(()), + (CursorState::Grab, CursorState::Grab) => Ok(()), + + (CursorState::Hide, CursorState::Normal) => { + unsafe { + user32::SetCursor(ptr::null_mut()); + *current_state = CursorState::Hide; + Ok(()) + } + }, + + (CursorState::Normal, CursorState::Hide) => { + unsafe { + user32::SetCursor(user32::LoadCursorW(ptr::null_mut(), winapi::IDC_ARROW)); + *current_state = CursorState::Normal; + Ok(()) + } + }, + + (CursorState::Grab, CursorState::Normal) => { + unsafe { + user32::SetCursor(ptr::null_mut()); + let mut rect = mem::uninitialized(); + if user32::GetClientRect(self.window.0, &mut rect) == 0 { + return Err(format!("GetWindowRect failed")); + } + user32::ClientToScreen(self.window.0, mem::transmute(&mut rect.left)); + user32::ClientToScreen(self.window.0, mem::transmute(&mut rect.right)); + if user32::ClipCursor(&rect) == 0 { + return Err(format!("ClipCursor failed")); + } + *current_state = CursorState::Grab; + Ok(()) + } + }, + + (CursorState::Normal, CursorState::Grab) => { + unsafe { + user32::SetCursor(user32::LoadCursorW(ptr::null_mut(), winapi::IDC_ARROW)); + if user32::ClipCursor(ptr::null()) == 0 { + return Err(format!("ClipCursor failed")); + } + *current_state = CursorState::Normal; + Ok(()) + } + }, + + _ => unimplemented!(), + }; + + unsafe { user32::AttachThreadInput(foreground_thread_id, current_thread_id, 0) }; + + res } pub fn hidpi_factor(&self) -> f32 { |