Support scrolling in Magic Leap Servo

This commit is contained in:
Alan Jeffrey 2018-10-31 17:59:14 -05:00
parent 95bfaa0a77
commit 3970c4ffbe
3 changed files with 101 additions and 16 deletions

View file

@ -33,8 +33,12 @@ use servo::gl::Gl;
use servo::gl::GlesFns; use servo::gl::GlesFns;
use servo::msg::constellation_msg::TraversalDirection; use servo::msg::constellation_msg::TraversalDirection;
use servo::script_traits::MouseButton; use servo::script_traits::MouseButton;
use servo::script_traits::TouchEventType;
use servo::servo_url::ServoUrl; use servo::servo_url::ServoUrl;
use servo::webrender_api::DevicePixel;
use servo::webrender_api::DevicePoint; use servo::webrender_api::DevicePoint;
use servo::webrender_api::LayoutPixel;
use servo::webrender_api::ScrollLocation;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::ffi::CStr; use std::ffi::CStr;
use std::ffi::CString; use std::ffi::CString;
@ -113,6 +117,8 @@ pub unsafe extern "C" fn init_servo(ctxt: EGLContext,
app: app, app: app,
browser_id: browser_id, browser_id: browser_id,
history_update: history_update, history_update: history_update,
scroll_state: ScrollState::TriggerUp,
scroll_scale: TypedScale::new(SCROLL_SCALE / hidpi),
servo: servo, servo: servo,
}); });
Box::into_raw(result) Box::into_raw(result)
@ -176,17 +182,84 @@ pub unsafe extern "C" fn heartbeat_servo(servo: *mut ServoInstance) {
} }
} }
// Some magic numbers.
// How far does the cursor have to move for it to count as a drag rather than a click?
// (In device pixels squared, to avoid taking a sqrt when calculating move distance.)
const DRAG_CUTOFF_SQUARED: f32 = 100.0;
// How much should we scale scrolling by?
const SCROLL_SCALE: f32 = 3.0;
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn cursor_servo(servo: *mut ServoInstance, x: f32, y: f32, trigger: bool) { pub unsafe extern "C" fn move_servo(servo: *mut ServoInstance, x: f32, y: f32) {
// Servo's cursor was moved
if let Some(servo) = servo.as_mut() {
let point = DevicePoint::new(x, y);
let (new_state, window_event) = match servo.scroll_state {
ScrollState::TriggerUp => (
ScrollState::TriggerUp,
WindowEvent::MouseWindowMoveEventClass(point),
),
ScrollState::TriggerDown(start) if (start - point).square_length() < DRAG_CUTOFF_SQUARED => return,
ScrollState::TriggerDown(start) => (
ScrollState::TriggerDragging(start, point),
WindowEvent::Scroll(
ScrollLocation::Delta((point - start) * servo.scroll_scale),
start.to_i32(),
TouchEventType::Down
),
),
ScrollState::TriggerDragging(start, prev) => (
ScrollState::TriggerDragging(start, point),
WindowEvent::Scroll(
ScrollLocation::Delta((point - prev) * servo.scroll_scale),
start.to_i32(),
TouchEventType::Move
),
),
};
servo.scroll_state = new_state;
servo.servo.handle_events(vec![window_event]);
}
}
#[no_mangle]
pub unsafe extern "C" fn trigger_servo(servo: *mut ServoInstance, x: f32, y: f32, down: bool) {
// Servo was triggered // Servo was triggered
if let Some(servo) = servo.as_mut() { if let Some(servo) = servo.as_mut() {
let point = DevicePoint::new(x, y); let point = DevicePoint::new(x, y);
let window_event = if trigger { let (new_state, window_events) = match servo.scroll_state {
WindowEvent::MouseWindowEventClass(MouseWindowEvent::Click(MouseButton::Left, point)) ScrollState::TriggerUp if down => (
} else { ScrollState::TriggerDown(point),
WindowEvent::MouseWindowMoveEventClass(point) vec![
WindowEvent::MouseWindowEventClass(MouseWindowEvent::MouseDown(MouseButton::Left, point)),
],
),
ScrollState::TriggerDown(start) if !down => (
ScrollState::TriggerUp,
vec![
WindowEvent::MouseWindowEventClass(MouseWindowEvent::MouseUp(MouseButton::Left, start)),
WindowEvent::MouseWindowEventClass(MouseWindowEvent::Click(MouseButton::Left, start)),
WindowEvent::MouseWindowMoveEventClass(point),
],
),
ScrollState::TriggerDragging(start, prev) if !down => (
ScrollState::TriggerUp,
vec![
WindowEvent::Scroll(
ScrollLocation::Delta((point - prev) * servo.scroll_scale),
start.to_i32(),
TouchEventType::Up
),
WindowEvent::MouseWindowEventClass(MouseWindowEvent::MouseUp(MouseButton::Left, point)),
WindowEvent::MouseWindowMoveEventClass(point),
],
),
_ => return,
}; };
servo.servo.handle_events(vec![window_event]); servo.scroll_state = new_state;
servo.servo.handle_events(window_events);
} }
} }
@ -234,6 +307,8 @@ pub struct ServoInstance {
browser_id: BrowserId, browser_id: BrowserId,
history_update: MLHistoryUpdate, history_update: MLHistoryUpdate,
servo: Servo<WindowInstance>, servo: Servo<WindowInstance>,
scroll_state: ScrollState,
scroll_scale: TypedScale<f32, DevicePixel, LayoutPixel>,
} }
struct WindowInstance { struct WindowInstance {
@ -246,6 +321,13 @@ struct WindowInstance {
hidpi: f32, hidpi: f32,
} }
#[derive(Clone, Copy)]
enum ScrollState {
TriggerUp,
TriggerDown(DevicePoint),
TriggerDragging(DevicePoint, DevicePoint),
}
impl WindowMethods for WindowInstance { impl WindowMethods for WindowInstance {
fn present(&self) { fn present(&self) {
SwapBuffers(self.disp, self.surf); SwapBuffers(self.disp, self.surf);

View file

@ -5,6 +5,7 @@
#include <lumin/LandscapeApp.h> #include <lumin/LandscapeApp.h>
#include <lumin/Prism.h> #include <lumin/Prism.h>
#include <lumin/event/ServerEvent.h> #include <lumin/event/ServerEvent.h>
#include <lumin/event/GestureInputEventData.h>
#include <lumin/event/KeyInputEventData.h> #include <lumin/event/KeyInputEventData.h>
#include <lumin/event/ControlTouchPadInputEventData.h> #include <lumin/event/ControlTouchPadInputEventData.h>
#include <lumin/node/QuadNode.h> #include <lumin/node/QuadNode.h>
@ -100,8 +101,8 @@ protected:
*/ */
virtual bool eventListener(lumin::ServerEvent* event) override; virtual bool eventListener(lumin::ServerEvent* event) override;
bool touchpadEventListener(lumin::ControlTouchPadInputEventData* event); bool touchpadEventListener(lumin::ControlTouchPadInputEventData* event);
bool keyEventListener(lumin::KeyInputEventData* event);
void urlBarEventListener(); void urlBarEventListener();
bool gestureEventListener(lumin::GestureInputEventData* event);
/** /**
* Get the current cursor position, with respect to the viewport. * Get the current cursor position, with respect to the viewport.

View file

@ -45,7 +45,8 @@ extern "C" ServoInstance* init_servo(EGLContext, EGLSurface, EGLDisplay,
Servo2D*, MLLogger, MLHistoryUpdate, Servo2D*, MLLogger, MLHistoryUpdate,
const char* url, int width, int height, float hidpi); const char* url, int width, int height, float hidpi);
extern "C" void heartbeat_servo(ServoInstance*); extern "C" void heartbeat_servo(ServoInstance*);
extern "C" void cursor_servo(ServoInstance*, float x, float y, bool triggered); extern "C" void trigger_servo(ServoInstance*, float x, float y, bool down);
extern "C" void move_servo(ServoInstance*, float x, float y);
extern "C" void traverse_servo(ServoInstance*, int delta); extern "C" void traverse_servo(ServoInstance*, int delta);
extern "C" void navigate_servo(ServoInstance*, const char* text); extern "C" void navigate_servo(ServoInstance*, const char* text);
extern "C" void discard_servo(ServoInstance*); extern "C" void discard_servo(ServoInstance*);
@ -220,8 +221,8 @@ bool Servo2D::eventListener(lumin::ServerEvent* event) {
switch (event->getServerEventType()) { switch (event->getServerEventType()) {
case lumin::ServerEventType::kControlTouchPadInputEvent: case lumin::ServerEventType::kControlTouchPadInputEvent:
return touchpadEventListener(static_cast<lumin::ControlTouchPadInputEventData*>(event)); return touchpadEventListener(static_cast<lumin::ControlTouchPadInputEventData*>(event));
case lumin::ServerEventType::kKeyInputEvent: case lumin::ServerEventType::kGestureInputEvent:
return keyEventListener(static_cast<lumin::KeyInputEventData*>(event)); return gestureEventListener(static_cast<lumin::GestureInputEventData*>(event));
default: default:
return false; return false;
} }
@ -257,14 +258,15 @@ bool Servo2D::touchpadEventListener(lumin::ControlTouchPadInputEventData* event)
return false; return false;
} }
// Inform Servo of the trigger // Inform Servo of the move
cursor_servo(servo_, pos.x, pos.y, false); move_servo(servo_, pos.x, pos.y);
return true; return true;
} }
bool Servo2D::keyEventListener(lumin::KeyInputEventData* event) { bool Servo2D::gestureEventListener(lumin::GestureInputEventData* event) {
// Only respond to trigger keys // Only respond to trigger up or down
if (event->keyCode() != lumin::input::KeyCodes::AKEYCODE_EX_TRIGGER) { lumin::input::GestureType typ = event->getGesture();
if (typ != lumin::input::GestureType::TriggerDown && typ != lumin::input::GestureType::TriggerUp) {
return false; return false;
} }
@ -280,7 +282,7 @@ bool Servo2D::keyEventListener(lumin::KeyInputEventData* event) {
} }
// Inform Servo of the trigger // Inform Servo of the trigger
cursor_servo(servo_, pos.x, pos.y, true); trigger_servo(servo_, pos.x, pos.y, typ == lumin::input::GestureType::TriggerDown);
return true; return true;
} }