diff options
author | tomaka <pierre.krieger1708@gmail.com> | 2015-03-30 13:32:28 +0200 |
---|---|---|
committer | tomaka <pierre.krieger1708@gmail.com> | 2015-03-30 13:32:28 +0200 |
commit | a1b504d16c6734dd064aff84059f45c803d97eb3 (patch) | |
tree | aa3d6c4ea6d9903a7e7953b808401f1d8cd8c5d8 /src/win32/mod.rs | |
parent | c3470abc8e818c3ba1247df243055f5d1f854f2c (diff) | |
parent | 2089e9c476691b8d81b9bbe8eb83f4c878614774 (diff) | |
download | glutin-a1b504d16c6734dd064aff84059f45c803d97eb3.tar.gz glutin-a1b504d16c6734dd064aff84059f45c803d97eb3.zip |
Merge pull request #328 from tomaka/grab
Cursor grabbing
Diffstat (limited to 'src/win32/mod.rs')
-rw-r--r-- | src/win32/mod.rs | 70 |
1 files changed, 67 insertions, 3 deletions
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 { |