Merge pull request #328 from tomaka/grab

Cursor grabbing
This commit is contained in:
tomaka 2015-03-30 13:32:28 +02:00
commit a1b504d16c
4 changed files with 97 additions and 4 deletions

View file

@ -42,6 +42,11 @@ fn main() {
.ok().expect("could not grab mouse cursor"); .ok().expect("could not grab mouse cursor");
} }
}, },
a @ Event::MouseMoved(_) => {
println!("{:?}", a);
},
_ => (), _ => (),
} }

View file

@ -1,3 +1,4 @@
use std::mem;
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
@ -176,6 +177,26 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
0 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 => { winapi::WM_SETFOCUS => {
use events::Event::Focused; use events::Event::Focused;
send_event(window, Focused(true)); send_event(window, Focused(true));

View file

@ -15,11 +15,13 @@ use Api;
use BuilderAttribs; use BuilderAttribs;
use CreationError; use CreationError;
use CreationError::OsError; use CreationError::OsError;
use CursorState;
use GlRequest; use GlRequest;
use PixelFormat; use PixelFormat;
use std::ffi::CString; use std::ffi::CString;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use std::sync::Mutex;
use libc; use libc;
use super::gl; use super::gl;
@ -250,6 +252,7 @@ unsafe fn init(title: Vec<u16>, builder: BuilderAttribs<'static>,
gl_library: gl_library, gl_library: gl_library,
events_receiver: events_receiver, events_receiver: events_receiver,
is_closed: AtomicBool::new(false), is_closed: AtomicBool::new(false),
cursor_state: Mutex::new(CursorState::Normal),
}) })
} }
@ -265,7 +268,7 @@ unsafe fn register_window_class() -> Vec<u16> {
cbWndExtra: 0, cbWndExtra: 0,
hInstance: kernel32::GetModuleHandleW(ptr::null()), hInstance: kernel32::GetModuleHandleW(ptr::null()),
hIcon: ptr::null_mut(), 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(), hbrBackground: ptr::null_mut(),
lpszMenuName: ptr::null(), lpszMenuName: ptr::null(),
lpszClassName: class_name.as_ptr(), lpszClassName: class_name.as_ptr(),

View file

@ -1,6 +1,8 @@
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use std::mem;
use std::ptr; use std::ptr;
use std::ffi::CString; use std::ffi::CString;
use std::sync::Mutex;
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
use libc; use libc;
use {CreationError, Event, MouseCursor}; use {CreationError, Event, MouseCursor};
@ -43,6 +45,9 @@ pub struct Window {
/// True if a `Closed` event has been received. /// True if a `Closed` event has been received.
is_closed: AtomicBool, is_closed: AtomicBool,
/// The current cursor state.
cursor_state: Mutex<CursorState>,
} }
unsafe impl Send for Window {} unsafe impl Send for Window {}
@ -148,7 +153,6 @@ impl Window {
/// See the docs in the crate root file. /// See the docs in the crate root file.
pub fn get_inner_size(&self) -> Option<(u32, u32)> { pub fn get_inner_size(&self) -> Option<(u32, u32)> {
use std::mem;
let mut rect: winapi::RECT = unsafe { mem::uninitialized() }; let mut rect: winapi::RECT = unsafe { mem::uninitialized() };
if unsafe { user32::GetClientRect(self.window.0, &mut rect) } == 0 { if unsafe { user32::GetClientRect(self.window.0, &mut rect) } == 0 {
@ -163,7 +167,6 @@ impl Window {
/// See the docs in the crate root file. /// See the docs in the crate root file.
pub fn get_outer_size(&self) -> Option<(u32, u32)> { pub fn get_outer_size(&self) -> Option<(u32, u32)> {
use std::mem;
let mut rect: winapi::RECT = unsafe { mem::uninitialized() }; let mut rect: winapi::RECT = unsafe { mem::uninitialized() };
if unsafe { user32::GetWindowRect(self.window.0, &mut rect) } == 0 { 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> { 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 { pub fn hidpi_factor(&self) -> f32 {