From bb418efcc7d5bf38dcb37251ebd1350abb05aba3 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 26 Mar 2015 17:32:40 +0100 Subject: [PATCH 1/4] Partially implement cursor state on win32 --- src/win32/init.rs | 5 +++- src/win32/mod.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/win32/init.rs b/src/win32/init.rs index 08d54c0e..c5e18ccf 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, 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 { 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 41004b35..113bea1a 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, } 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,57 @@ impl Window { } pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> { - unimplemented!(); + let mut current_state = self.cursor_state.lock().unwrap(); + + 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::GetWindowRect(self.window.0, &mut rect) == 0 { + return Err(format!("GetWindowRect failed")); + } + 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!(), + } } pub fn hidpi_factor(&self) -> f32 { From bae1e42b8b27ad2e66fa50c227d4ead0eae80993 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 26 Mar 2015 19:01:27 +0100 Subject: [PATCH 2/4] More work on win32 implementation --- examples/grabbing.rs | 5 +++++ src/win32/mod.rs | 13 +++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/examples/grabbing.rs b/examples/grabbing.rs index 07e38735..80887744 100644 --- a/examples/grabbing.rs +++ b/examples/grabbing.rs @@ -42,6 +42,11 @@ fn main() { .ok().expect("could not grab mouse cursor"); } }, + + a @ Event::MouseMoved(_) => { + println!("{:?}", a); + }, + _ => (), } diff --git a/src/win32/mod.rs b/src/win32/mod.rs index 113bea1a..c0708b8e 100644 --- a/src/win32/mod.rs +++ b/src/win32/mod.rs @@ -262,7 +262,12 @@ impl Window { pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> { let mut current_state = self.cursor_state.lock().unwrap(); - match (state, *current_state) { + 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(()), @@ -310,7 +315,11 @@ impl Window { }, _ => unimplemented!(), - } + }; + + unsafe { user32::AttachThreadInput(foreground_thread_id, current_thread_id, 0) }; + + res } pub fn hidpi_factor(&self) -> f32 { From 9bef21048ef03ecfa8e0ca46ed700cabf95a9f30 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Mon, 30 Mar 2015 12:56:08 +0200 Subject: [PATCH 3/4] Fix wrong grabbing rect --- src/win32/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/win32/mod.rs b/src/win32/mod.rs index c0708b8e..e20d8b7c 100644 --- a/src/win32/mod.rs +++ b/src/win32/mod.rs @@ -292,9 +292,11 @@ impl Window { unsafe { user32::SetCursor(ptr::null_mut()); let mut rect = mem::uninitialized(); - if user32::GetWindowRect(self.window.0, &mut rect) == 0 { + 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")); } From 2089e9c476691b8d81b9bbe8eb83f4c878614774 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Mon, 30 Mar 2015 13:12:37 +0200 Subject: [PATCH 4/4] Add draft for raw input --- src/win32/callback.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/win32/callback.rs b/src/win32/callback.rs index bbf5b553..1cfb640f 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::() as winapi::UINT; + user32::GetRawInputData(mem::transmute(lparam), winapi::RID_INPUT, + mem::transmute(&mut data), &mut data_size, + mem::size_of::() 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));