From d2dd82c146729687dde9e264e80905b6d81ca787 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Fri, 1 Dec 2017 15:00:09 +0200 Subject: [PATCH] impl touch events for emscripten (#358) --- CHANGELOG.md | 4 +++ src/platform/emscripten/ffi.rs | 64 ++++++++++++++++++++++++++++++++++ src/platform/emscripten/mod.rs | 42 ++++++++++++++++++++++ 3 files changed, 110 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2d9a629..b1a32dba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased + +- Add support for `Touch` for emscripten backend. + # Version 0.9.0 (2017-12-01) - Added event `WindowEvent::HiDPIFactorChanged`. diff --git a/src/platform/emscripten/ffi.rs b/src/platform/emscripten/ffi.rs index 8f5457cf..65291a92 100644 --- a/src/platform/emscripten/ffi.rs +++ b/src/platform/emscripten/ffi.rs @@ -91,6 +91,11 @@ pub type em_fullscreenchange_callback_func = Option EM_BOOL>; +pub type em_touch_callback_func = Option EM_BOOL>; + #[repr(C)] pub struct EmscriptenFullscreenChangeEvent { pub isFullscreen: c_int, @@ -162,6 +167,45 @@ fn bindgen_test_layout_EmscriptenMouseEvent() { assert_eq!(mem::align_of::(), 8usize); } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct EmscriptenTouchPoint { + pub identifier: c_long, + pub screenX: c_long, + pub screenY: c_long, + pub clientX: c_long, + pub clientY: c_long, + pub pageX: c_long, + pub pageY: c_long, + pub isChanged: c_int, + pub onTarget: c_int, + pub targetX: c_long, + pub targetY: c_long, + pub canvasX: c_long, + pub canvasY: c_long, +} +#[test] +fn bindgen_test_layout_EmscriptenTouchPoint() { + assert_eq!(mem::size_of::(), 96usize); + assert_eq!(mem::align_of::(), 8usize); +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct EmscriptenTouchEvent { + pub numTouches: c_int, + pub ctrlKey: c_int, + pub shiftKey: c_int, + pub altKey: c_int, + pub metaKey: c_int, + pub touches: [EmscriptenTouchPoint; 32usize], +} +#[test] +fn bindgen_test_layout_EmscriptenTouchEvent() { + assert_eq!(mem::size_of::(), 3096usize); + assert_eq!(mem::align_of::(), 8usize); +} + #[repr(C)] pub struct EmscriptenPointerlockChangeEvent { pub isActive: c_int, @@ -238,4 +282,24 @@ extern "C" { func: em_callback_func, fps: c_int, simulate_infinite_loop: EM_BOOL); pub fn emscripten_cancel_main_loop(); + + pub fn emscripten_set_touchstart_callback( + target: *const c_char, userData: *mut c_void, + useCapture: c_int, callback: em_touch_callback_func) + -> EMSCRIPTEN_RESULT; + + pub fn emscripten_set_touchend_callback( + target: *const c_char, userData: *mut c_void, + useCapture: c_int, callback: em_touch_callback_func) + -> EMSCRIPTEN_RESULT; + + pub fn emscripten_set_touchmove_callback( + target: *const c_char, userData: *mut c_void, + useCapture: c_int, callback: em_touch_callback_func) + -> EMSCRIPTEN_RESULT; + + pub fn emscripten_set_touchcancel_callback( + target: *const c_char, userData: *mut c_void, + useCapture: c_int, callback: em_touch_callback_func) + -> EMSCRIPTEN_RESULT; } diff --git a/src/platform/emscripten/mod.rs b/src/platform/emscripten/mod.rs index 268bca9a..9b3bd131 100644 --- a/src/platform/emscripten/mod.rs +++ b/src/platform/emscripten/mod.rs @@ -274,6 +274,40 @@ extern "C" fn keyboard_callback( ffi::EM_FALSE } +extern fn touch_callback( + event_type: c_int, + event: *const ffi::EmscriptenTouchEvent, + event_queue: *mut c_void) -> ffi::EM_BOOL +{ + unsafe { + let queue: &RefCell> = mem::transmute(event_queue); + + let phase = match event_type { + ffi::EMSCRIPTEN_EVENT_TOUCHSTART => ::TouchPhase::Started, + ffi::EMSCRIPTEN_EVENT_TOUCHEND => ::TouchPhase::Ended, + ffi::EMSCRIPTEN_EVENT_TOUCHMOVE => ::TouchPhase::Moved, + ffi::EMSCRIPTEN_EVENT_TOUCHCANCEL => ::TouchPhase::Cancelled, + _ => return ffi::EM_FALSE, + }; + + for touch in 0..(*event).numTouches as usize { + let touch = (*event).touches[touch]; + if touch.isChanged == ffi::EM_TRUE { + queue.borrow_mut().push_back(::Event::WindowEvent { + window_id: ::WindowId(WindowId(0)), + event: ::WindowEvent::Touch(::Touch { + device_id: ::DeviceId(DeviceId), + phase, + id: touch.identifier as u64, + location: (touch.canvasX as f64, touch.canvasY as f64), + }), + }); + } + } + } + ffi::EM_FALSE +} + // In case of fullscreen window this method will request fullscreen on change #[allow(non_snake_case)] unsafe extern "C" fn fullscreen_callback( @@ -335,6 +369,14 @@ impl Window { .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))) .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_touchstart_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(touch_callback))) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_touchend_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(touch_callback))) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_touchmove_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(touch_callback))) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; + em_try(ffi::emscripten_set_touchcancel_callback(DOCUMENT_NAME.as_ptr() as *const c_char, mem::transmute(&*window.window.events), ffi::EM_FALSE, Some(touch_callback))) + .map_err(|e| ::CreationError::OsError(format!("emscripten error: {}", e)))?; } if attribs.fullscreen.is_some() {