diff --git a/CHANGELOG.md b/CHANGELOG.md index 57e0bf1f..74e9b1fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - `WindowEvent`s `MouseMoved`, `MouseEntered`, and `MouseLeft` have been renamed to `CursorMoved`, `CursorEntered`, and `CursorLeft`. - New `DeviceEvent`s added, `MouseMotion` and `MouseWheel`. +- Impl `ModifiersState`, `MouseMove`, `MouseInput`, `MouseMotion` for emscripten backend. # Version 0.8.3 (2017-10-11) diff --git a/src/platform/emscripten/ffi.rs b/src/platform/emscripten/ffi.rs index c54e8a40..8f5457cf 100644 --- a/src/platform/emscripten/ffi.rs +++ b/src/platform/emscripten/ffi.rs @@ -2,7 +2,7 @@ #![allow(non_snake_case)] #![allow(non_camel_case_types)] -use std::os::raw::{c_int, c_char, c_void, c_ulong, c_double}; +use std::os::raw::{c_int, c_char, c_void, c_ulong, c_double, c_long, c_ushort}; pub type EM_BOOL = c_int; pub type EM_UTF8 = c_char; @@ -76,6 +76,11 @@ pub type em_key_callback_func = Option EM_BOOL>; +pub type em_mouse_callback_func = Option EM_BOOL>; + pub type em_pointerlockchange_callback_func = Option Self { *self } } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct EmscriptenMouseEvent { + pub timestamp: f64, + pub screenX: c_long, + pub screenY: c_long, + pub clientX: c_long, + pub clientY: c_long, + pub ctrlKey: c_int, + pub shiftKey: c_int, + pub altKey: c_int, + pub metaKey: c_int, + pub button: c_ushort, + pub buttons: c_ushort, + pub movementX: c_long, + pub movementY: c_long, + pub targetX: c_long, + pub targetY: c_long, + pub canvasX: c_long, + pub canvasY: c_long, + pub padding: c_long, +} +#[test] +fn bindgen_test_layout_EmscriptenMouseEvent() { + assert_eq!(mem::size_of::(), 120usize); + assert_eq!(mem::align_of::(), 8usize); +} + #[repr(C)] pub struct EmscriptenPointerlockChangeEvent { pub isActive: c_int, @@ -172,6 +205,21 @@ extern "C" { useCapture: EM_BOOL, callback: em_key_callback_func) -> EMSCRIPTEN_RESULT; + pub fn emscripten_set_mousemove_callback( + target: *const c_char, user_data: *mut c_void, + use_capture: EM_BOOL, callback: em_mouse_callback_func) + -> EMSCRIPTEN_RESULT; + + pub fn emscripten_set_mousedown_callback( + target: *const c_char, user_data: *mut c_void, + use_capture: EM_BOOL, callback: em_mouse_callback_func) + -> EMSCRIPTEN_RESULT; + + pub fn emscripten_set_mouseup_callback( + target: *const c_char, user_data: *mut c_void, + use_capture: EM_BOOL, callback: em_mouse_callback_func) + -> EMSCRIPTEN_RESULT; + pub fn emscripten_hide_mouse(); pub fn emscripten_get_device_pixel_ratio() -> f64; diff --git a/src/platform/emscripten/mod.rs b/src/platform/emscripten/mod.rs index 0e458469..268bca9a 100644 --- a/src/platform/emscripten/mod.rs +++ b/src/platform/emscripten/mod.rs @@ -170,6 +170,59 @@ fn show_mouse() { } } +extern "C" fn mouse_callback( + event_type: c_int, + event: *const ffi::EmscriptenMouseEvent, + event_queue: *mut c_void) -> ffi::EM_BOOL +{ + unsafe { + let queue: &RefCell> = mem::transmute(event_queue); + + match event_type { + ffi::EMSCRIPTEN_EVENT_MOUSEMOVE => { + queue.borrow_mut().push_back(::Event::WindowEvent { + window_id: ::WindowId(WindowId(0)), + event: ::WindowEvent::CursorMoved { + device_id: ::DeviceId(DeviceId), + position: ((*event).canvasX as f64, (*event).canvasY as f64), + } + }); + queue.borrow_mut().push_back(::Event::DeviceEvent { + device_id: ::DeviceId(DeviceId), + event: ::DeviceEvent::MouseMotion { + delta: ((*event).movementX as f64, (*event).movementY as f64), + } + }); + }, + mouse_input @ ffi::EMSCRIPTEN_EVENT_MOUSEDOWN | + mouse_input @ ffi::EMSCRIPTEN_EVENT_MOUSEUP => { + let button = match (*event).button { + 0 => ::MouseButton::Left, + 1 => ::MouseButton::Middle, + 2 => ::MouseButton::Right, + other => ::MouseButton::Other(other as u8), + }; + let state = match mouse_input { + ffi::EMSCRIPTEN_EVENT_MOUSEDOWN => ::ElementState::Pressed, + ffi::EMSCRIPTEN_EVENT_MOUSEUP => ::ElementState::Released, + _ => unreachable!(), + }; + queue.borrow_mut().push_back(::Event::WindowEvent { + window_id: ::WindowId(WindowId(0)), + event: ::WindowEvent::MouseInput { + device_id: ::DeviceId(DeviceId), + state, + button, + } + }) + }, + _ => { + } + } + } + ffi::EM_FALSE +} + extern "C" fn keyboard_callback( event_type: c_int, event: *const ffi::EmscriptenKeyboardEvent, @@ -177,6 +230,14 @@ extern "C" fn keyboard_callback( { unsafe { let queue: &RefCell> = mem::transmute(event_queue); + + let modifiers = ::ModifiersState { + shift: (*event).shiftKey == ffi::EM_TRUE, + ctrl: (*event).ctrlKey == ffi::EM_TRUE, + alt: (*event).altKey == ffi::EM_TRUE, + logo: (*event).metaKey == ffi::EM_TRUE, + }; + match event_type { ffi::EMSCRIPTEN_EVENT_KEYDOWN => { queue.borrow_mut().push_back(::Event::WindowEvent { @@ -187,8 +248,8 @@ extern "C" fn keyboard_callback( scancode: key_translate((*event).key) as u32, state: ::ElementState::Pressed, virtual_keycode: key_translate_virt((*event).key, (*event).location), - modifiers: ::ModifiersState::default() // TODO: - }, + modifiers, + }, }, }); }, @@ -201,7 +262,7 @@ extern "C" fn keyboard_callback( scancode: key_translate((*event).key) as u32, state: ::ElementState::Released, virtual_keycode: key_translate_virt((*event).key, (*event).location), - modifiers: ::ModifiersState::default() // TODO: + modifiers, }, }, }); @@ -264,6 +325,12 @@ impl Window { // TODO: set up more event callbacks unsafe { + em_try(ffi::emscripten_set_mousemove_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(mouse_callback))) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_mousedown_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(mouse_callback))) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_mouseup_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(mouse_callback))) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; em_try(ffi::emscripten_set_keydown_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(keyboard_callback))) .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; em_try(ffi::emscripten_set_keyup_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(keyboard_callback)))