Make the Touch events more robust

This commit is contained in:
Joshua Granick
2015-08-19 16:04:57 -07:00
parent cb95b5bdfc
commit c666477b58
12 changed files with 401 additions and 177 deletions

View File

@@ -16,6 +16,7 @@ import lime.graphics.Renderer;
import lime.ui.Keyboard;
import lime.ui.KeyCode;
import lime.ui.KeyModifier;
import lime.ui.Touch;
import lime.ui.Window;
@:access(lime.app.Application)
@@ -26,8 +27,10 @@ class FlashApplication {
private var cacheTime:Int;
private var currentTouches = new Map<Int, Touch> ();
private var mouseLeft:Bool;
private var parent:Application;
private var unusedTouchesPool = new List<Touch> ();
public function new (parent:Application):Void {
@@ -160,9 +163,9 @@ class FlashApplication {
Lib.current.stage.addEventListener (Event.RESIZE, handleWindowEvent);
cacheTime = Lib.getTimer ();
handleUpdateEvent (null);
handleApplicationEvent (null);
Lib.current.stage.addEventListener (Event.ENTER_FRAME, handleUpdateEvent);
Lib.current.stage.addEventListener (Event.ENTER_FRAME, handleApplicationEvent);
return 0;
@@ -176,6 +179,24 @@ class FlashApplication {
}
private function handleApplicationEvent (event:Event):Void {
var currentTime = Lib.getTimer ();
var deltaTime = currentTime - cacheTime;
cacheTime = currentTime;
parent.onUpdate.dispatch (deltaTime);
if (parent.renderer != null) {
parent.renderer.onRender.dispatch ();
parent.renderer.flip ();
}
}
private function handleKeyEvent (event:KeyboardEvent):Void {
var keyCode = convertKeyCode (event.keyCode);
@@ -250,7 +271,6 @@ class FlashApplication {
if (parent.window != null) {
var id = 0;
var x = event.stageX;
var y = event.stageY;
@@ -258,38 +278,89 @@ class FlashApplication {
case TouchEvent.TOUCH_BEGIN:
parent.window.onTouchStart.dispatch (x / parent.window.width, y / parent.window.height, id);
var touch = unusedTouchesPool.pop ();
if (touch == null) {
touch = new Touch (x / parent.window.width, y / parent.window.height, event.touchPointID, 0, 0, event.pressure, 0);
} else {
touch.x = x / parent.window.width;
touch.y = y / parent.window.height;
touch.id = event.touchPointID;
touch.dx = 0;
touch.dy = 0;
touch.pressure = event.pressure;
touch.device = 0;
}
currentTouches.set (event.touchPointID, touch);
Touch.onStart.dispatch (touch);
if (event.isPrimaryTouchPoint) {
parent.window.onMouseDown.dispatch (x, y, 0);
case TouchEvent.TOUCH_MOVE:
parent.window.onTouchMove.dispatch (x / parent.window.width, y / parent.window.height, id);
parent.window.onMouseMove.dispatch (x, y);
}
case TouchEvent.TOUCH_END:
parent.window.onTouchEnd.dispatch (x / parent.window.width, y / parent.window.height, id);
var touch = currentTouches.get (event.touchPointID);
if (touch != null) {
var cacheX = touch.x;
var cacheY = touch.y;
touch.x = x / parent.window.width;
touch.y = y / parent.window.height;
touch.dx = touch.x - cacheX;
touch.dy = touch.y - cacheY;
touch.pressure = event.pressure;
Touch.onEnd.dispatch (touch);
currentTouches.remove (event.touchPointID);
unusedTouchesPool.add (touch);
if (event.isPrimaryTouchPoint) {
parent.window.onMouseUp.dispatch (x, y, 0);
}
}
case TouchEvent.TOUCH_MOVE:
var touch = currentTouches.get (event.touchPointID);
if (touch != null) {
var cacheX = touch.x;
var cacheY = touch.y;
touch.x = x / parent.window.width;
touch.y = y / parent.window.height;
touch.dx = touch.x - cacheX;
touch.dy = touch.y - cacheY;
touch.pressure = event.pressure;
Touch.onMove.dispatch (touch);
if (event.isPrimaryTouchPoint) {
parent.window.onMouseMove.dispatch (x, y);
}
}
private function handleUpdateEvent (event:Event):Void {
var currentTime = Lib.getTimer ();
var deltaTime = currentTime - cacheTime;
cacheTime = currentTime;
parent.onUpdate.dispatch (deltaTime);
if (parent.renderer != null) {
parent.renderer.onRender.dispatch ();
parent.renderer.flip ();
}
}

View File

@@ -167,7 +167,7 @@ class HTML5Application {
lastUpdate = Date.now ().getTime ();
handleUpdateEvent ();
handleApplicationEvent ();
return 0;
@@ -193,38 +193,7 @@ class HTML5Application {
}
private function handleKeyEvent (event:KeyboardEvent):Void {
if (parent.window != null) {
// space and arrow keys
// switch (event.keyCode) {
// case 32, 37, 38, 39, 40: event.preventDefault ();
// }
var keyCode = cast convertKeyCode (event.keyCode != null ? event.keyCode : event.which);
var modifier = (event.shiftKey ? (KeyModifier.SHIFT) : 0) | (event.ctrlKey ? (KeyModifier.CTRL) : 0) | (event.altKey ? (KeyModifier.ALT) : 0) | (event.metaKey ? (KeyModifier.META) : 0);
if (event.type == "keydown") {
Keyboard.onKeyDown.dispatch (keyCode, modifier);
} else {
Keyboard.onKeyUp.dispatch (keyCode, modifier);
}
}
}
private function handleUpdateEvent (?__):Void {
private function handleApplicationEvent (?__):Void {
currentUpdate = Date.now ().getTime ();
@@ -271,7 +240,38 @@ class HTML5Application {
}
Browser.window.requestAnimationFrame (cast handleUpdateEvent);
Browser.window.requestAnimationFrame (cast handleApplicationEvent);
}
private function handleKeyEvent (event:KeyboardEvent):Void {
if (parent.window != null) {
// space and arrow keys
// switch (event.keyCode) {
// case 32, 37, 38, 39, 40: event.preventDefault ();
// }
var keyCode = cast convertKeyCode (event.keyCode != null ? event.keyCode : event.which);
var modifier = (event.shiftKey ? (KeyModifier.SHIFT) : 0) | (event.ctrlKey ? (KeyModifier.CTRL) : 0) | (event.altKey ? (KeyModifier.ALT) : 0) | (event.metaKey ? (KeyModifier.META) : 0);
if (event.type == "keydown") {
Keyboard.onKeyDown.dispatch (keyCode, modifier);
} else {
Keyboard.onKeyUp.dispatch (keyCode, modifier);
}
}
}

View File

@@ -19,6 +19,7 @@ import lime.app.Application;
import lime.graphics.Image;
import lime.system.Display;
import lime.system.System;
import lime.ui.Touch;
import lime.ui.Window;
#if (haxe_ver < 3.2)
@@ -43,10 +44,12 @@ class HTML5Window {
public var stats:Dynamic;
#end
private var currentTouches = new Map<Int, Touch> ();
private var enableTextEvents:Bool;
private var parent:Window;
private var setHeight:Int;
private var setWidth:Int;
private var unusedTouchesPool = new List<Touch> ();
public function new (parent:Window) {
@@ -366,39 +369,40 @@ class HTML5Window {
event.preventDefault ();
var touch = event.changedTouches[0];
var id = touch.identifier;
var x = 0.0;
var y = 0.0;
var rect = null;
if (element != null) {
if (canvas != null) {
var rect = canvas.getBoundingClientRect ();
x = (touch.clientX - rect.left) * (parent.width / rect.width);
y = (touch.clientY - rect.top) * (parent.height / rect.height);
rect = canvas.getBoundingClientRect ();
} else if (div != null) {
var rect = div.getBoundingClientRect ();
//eventInfo.x = (event.clientX - rect.left) * (window.div.style.width / rect.width);
x = (touch.clientX - rect.left);
//eventInfo.y = (event.clientY - rect.top) * (window.div.style.height / rect.height);
y = (touch.clientY - rect.top);
rect = div.getBoundingClientRect ();
} else {
var rect = element.getBoundingClientRect ();
x = (touch.clientX - rect.left) * (parent.width / rect.width);
y = (touch.clientY - rect.top) * (parent.height / rect.height);
rect = element.getBoundingClientRect ();
}
}
for (data in event.changedTouches) {
var x = 0.0;
var y = 0.0;
if (rect != null) {
x = (data.clientX - rect.left) * (parent.width / rect.width);
y = (data.clientY - rect.top) * (parent.height / rect.height);
} else {
x = touch.clientX;
y = touch.clientY;
x = data.clientX;
y = data.clientY;
}
@@ -406,25 +410,95 @@ class HTML5Window {
case "touchstart":
parent.onTouchStart.dispatch (x / setWidth, y / setHeight, id);
var touch = unusedTouchesPool.pop ();
if (touch == null) {
touch = new Touch (x / setWidth, y / setHeight, data.identifier, 0, 0, data.force, parent.id);
} else {
touch.x = x / setWidth;
touch.y = y / setHeight;
touch.id = data.identifier;
touch.dx = 0;
touch.dy = 0;
touch.pressure = data.force;
touch.device = parent.id;
}
currentTouches.set (data.identifier, touch);
Touch.onStart.dispatch (touch);
if (data == event.touches[0]) {
parent.onMouseDown.dispatch (x, y, 0);
case "touchmove":
parent.onTouchMove.dispatch (x / setWidth, y / setHeight, id);
parent.onMouseMove.dispatch (x, y);
}
case "touchend":
parent.onTouchEnd.dispatch (x / setWidth, y / setHeight, id);
var touch = currentTouches.get (data.identifier);
if (touch != null) {
var cacheX = touch.x;
var cacheY = touch.y;
touch.x = x / setWidth;
touch.y = y / setHeight;
touch.dx = touch.x - cacheX;
touch.dy = touch.y - cacheY;
touch.pressure = data.force;
Touch.onEnd.dispatch (touch);
currentTouches.remove (data.identifier);
unusedTouchesPool.add (touch);
if (data == event.touches[0]) {
parent.onMouseUp.dispatch (x, y, 0);
}
}
case "touchmove":
var touch = currentTouches.get (data.identifier);
if (touch != null) {
var cacheX = touch.x;
var cacheY = touch.y;
touch.x = x / setWidth;
touch.y = y / setHeight;
touch.dx = touch.x - cacheX;
touch.dy = touch.y - cacheY;
touch.pressure = data.force;
Touch.onMove.dispatch (touch);
if (data == event.touches[0]) {
parent.onMouseMove.dispatch (x, y);
}
}
default:
}
}
}
public function move (x:Int, y:Int):Void {

View File

@@ -15,6 +15,7 @@ import lime.system.DisplayMode;
import lime.system.System;
import lime.ui.Gamepad;
import lime.ui.Keyboard;
import lime.ui.Touch;
import lime.ui.Window;
@:access(haxe.Timer)
@@ -29,12 +30,14 @@ class NativeApplication {
private var applicationEventInfo = new ApplicationEventInfo (UPDATE);
private var currentTouches = new Map<Int, Touch> ();
private var gamepadEventInfo = new GamepadEventInfo ();
private var keyEventInfo = new KeyEventInfo ();
private var mouseEventInfo = new MouseEventInfo ();
private var renderEventInfo = new RenderEventInfo (RENDER);
private var textEventInfo = new TextEventInfo ();
private var touchEventInfo = new TouchEventInfo ();
private var unusedTouchesPool = new List<Touch> ();
private var windowEventInfo = new WindowEventInfo ();
public var handle:Dynamic;
@@ -314,29 +317,69 @@ class NativeApplication {
private function handleTouchEvent ():Void {
//var window = parent.windows.get (touchEventInfo.windowID);
var window = parent.window;
if (window != null) {
switch (touchEventInfo.type) {
case TOUCH_START:
window.onTouchStart.dispatch (touchEventInfo.x, touchEventInfo.y, touchEventInfo.id);
var touch = unusedTouchesPool.pop ();
if (touch == null) {
touch = new Touch (touchEventInfo.x, touchEventInfo.x, touchEventInfo.id, touchEventInfo.dx, touchEventInfo.dy, touchEventInfo.pressure, touchEventInfo.device);
} else {
touch.x = touchEventInfo.x;
touch.y = touchEventInfo.y;
touch.id = touchEventInfo.id;
touch.dx = touchEventInfo.dx;
touch.dy = touchEventInfo.dy;
touch.pressure = touchEventInfo.pressure;
touch.device = touchEventInfo.device;
}
currentTouches.set (touch.id, touch);
Touch.onStart.dispatch (touch);
case TOUCH_END:
window.onTouchEnd.dispatch (touchEventInfo.x, touchEventInfo.y, touchEventInfo.id);
var touch = currentTouches.get (touchEventInfo.id);
if (touch != null) {
touch.x = touchEventInfo.x;
touch.y = touchEventInfo.y;
touch.dx = touchEventInfo.dx;
touch.dy = touchEventInfo.dy;
touch.pressure = touchEventInfo.pressure;
Touch.onEnd.dispatch (touch);
currentTouches.remove (touchEventInfo.id);
unusedTouchesPool.add (touch);
}
case TOUCH_MOVE:
window.onTouchMove.dispatch (touchEventInfo.x, touchEventInfo.y, touchEventInfo.id);
var touch = currentTouches.get (touchEventInfo.id);
default:
if (touch != null) {
touch.x = touchEventInfo.x;
touch.y = touchEventInfo.y;
touch.dx = touchEventInfo.dx;
touch.dy = touchEventInfo.dy;
touch.pressure = touchEventInfo.pressure;
Touch.onMove.dispatch (touch);
}
default:
}
}
@@ -716,27 +759,33 @@ private class TextEventInfo {
private class TouchEventInfo {
public var device:Int;
public var dx:Float;
public var dy:Float;
public var id:Int;
public var pressure:Float;
public var type:TouchEventType;
public var windowID:Int;
public var x:Float;
public var y:Float;
public function new (type:TouchEventType = null, windowID:Int = 0, x:Float = 0, y:Float = 0, id:Int = 0) {
public function new (type:TouchEventType = null, x:Float = 0, y:Float = 0, id:Int = 0, dx:Float = 0, dy:Float = 0, pressure:Float = 0, device:Int = 0) {
this.type = type;
this.windowID = windowID;
this.x = x;
this.y = y;
this.id = id;
this.dx = dx;
this.dy = dy;
this.pressure = pressure;
this.device = device;
}
public function clone ():TouchEventInfo {
return new TouchEventInfo (type, windowID, x, y, id);
return new TouchEventInfo (type, x, y, id, dx, dy, pressure, device);
}

View File

@@ -9,6 +9,7 @@ import lime.ui.GamepadButton;
import lime.ui.Keyboard;
import lime.ui.KeyCode;
import lime.ui.KeyModifier;
import lime.ui.Touch;
import lime.ui.Window;
@@ -63,6 +64,9 @@ class Application extends Module {
Gamepad.onConnect.add (onGamepadConnect);
Keyboard.onKeyDown.add (onKeyDown);
Keyboard.onKeyUp.add (onKeyUp);
Touch.onStart.add (onTouchStart);
Touch.onMove.add (onTouchMove);
Touch.onEnd.add (onTouchEnd);
}
@@ -139,9 +143,6 @@ class Application extends Module {
window.onRestore.add (onWindowRestore.bind (window));
window.onTextEdit.add (onTextEdit.bind (window));
window.onTextInput.add (onTextInput.bind (window));
window.onTouchStart.add (onTouchStart.bind (window));
window.onTouchMove.add (onTouchMove.bind (window));
window.onTouchEnd.add (onTouchEnd.bind (window));
window.create (this);
windows.set (window.id, window);
@@ -410,33 +411,33 @@ class Application extends Module {
}
public override function onTouchEnd (window:Window, x:Float, y:Float, id:Int):Void {
public override function onTouchEnd (touch:Touch):Void {
for (module in modules) {
module.onTouchEnd (window, x, y, id);
module.onTouchEnd (touch);
}
}
public override function onTouchMove (window:Window, x:Float, y:Float, id:Int):Void {
public override function onTouchMove (touch:Touch):Void {
for (module in modules) {
module.onTouchMove (window, x, y, id);
module.onTouchMove (touch);
}
}
public override function onTouchStart (window:Window, x:Float, y:Float, id:Int):Void {
public override function onTouchStart (touch:Touch):Void {
for (module in modules) {
module.onTouchStart (window, x, y, id);
module.onTouchStart (touch);
}

View File

@@ -8,6 +8,7 @@ import lime.ui.GamepadAxis;
import lime.ui.GamepadButton;
import lime.ui.KeyCode;
import lime.ui.KeyModifier;
import lime.ui.Touch;
import lime.ui.Window;
@@ -180,32 +181,23 @@ interface IModule {
/**
* Called when a touch end event is fired
* @param window The window dispatching the event
* @param x The current x coordinate of the touch point
* @param y The current y coordinate of the touch point
* @param id The ID of the touch point
* @param touch The current touch object
*/
public function onTouchEnd (window:Window, x:Float, y:Float, id:Int):Void;
public function onTouchEnd (touch:Touch):Void;
/**
* Called when a touch move event is fired
* @param window The window dispatching the event
* @param x The current x coordinate of the touch point
* @param y The current y coordinate of the touch point
* @param id The ID of the touch point
* @param touch The current touch object
*/
public function onTouchMove (window:Window, x:Float, y:Float, id:Int):Void;
public function onTouchMove (touch:Touch):Void;
/**
* Called when a touch start event is fired
* @param window The window dispatching the event
* @param x The current x coordinate of the touch point
* @param y The current y coordinate of the touch point
* @param id The ID of the touch point
* @param touch The current touch object
*/
public function onTouchStart (window:Window, x:Float, y:Float, id:Int):Void;
public function onTouchStart (touch:Touch):Void;
/**

View File

@@ -8,6 +8,7 @@ import lime.ui.GamepadAxis;
import lime.ui.GamepadButton;
import lime.ui.KeyCode;
import lime.ui.KeyModifier;
import lime.ui.Touch;
import lime.ui.Window;
@@ -193,32 +194,23 @@ class Module implements IModule {
/**
* Called when a touch end event is fired
* @param window The window dispatching the event
* @param x The current x coordinate of the touch point
* @param y The current y coordinate of the touch point
* @param id The ID of the touch point
* @param touch The current touch object
*/
public function onTouchEnd (window:Window, x:Float, y:Float, id:Int):Void { }
public function onTouchEnd (touch:Touch):Void { }
/**
* Called when a touch move event is fired
* @param window The window dispatching the event
* @param x The current x coordinate of the touch point
* @param y The current y coordinate of the touch point
* @param id The ID of the touch point
* @param touch The current touch object
*/
public function onTouchMove (window:Window, x:Float, y:Float, id:Int):Void { }
public function onTouchMove (touch:Touch):Void { }
/**
* Called when a touch start event is fired
* @param window The window dispatching the event
* @param x The current x coordinate of the touch point
* @param y The current y coordinate of the touch point
* @param id The ID of the touch point
* @param touch The current touch object
*/
public function onTouchStart (window:Window, x:Float, y:Float, id:Int):Void { }
public function onTouchStart (touch:Touch):Void { }
/**

36
lime/ui/Touch.hx Normal file
View File

@@ -0,0 +1,36 @@
package lime.ui;
import lime.app.Event;
class Touch {
public static var onEnd = new Event<Touch->Void> ();
public static var onMove = new Event<Touch->Void> ();
public static var onStart = new Event<Touch->Void> ();
public var device:Int;
public var dx:Float;
public var dy:Float;
public var id:Int;
public var pressure:Float;
public var x:Float;
public var y:Float;
public function new (x:Float, y:Float, id:Int, dx:Float, dy:Float, pressure:Float, device:Int) {
this.x = x;
this.y = y;
this.id = id;
this.dx = dx;
this.dy = dy;
this.pressure = pressure;
this.device = device;
}
}

View File

@@ -40,9 +40,6 @@ class Window {
public var onRestore = new Event<Void->Void> ();
public var onTextEdit = new Event<String->Int->Int->Void> ();
public var onTextInput = new Event<String->Void> ();
public var onTouchEnd = new Event<Float->Float->Int->Void> ();
public var onTouchMove = new Event<Float->Float->Int->Void> ();
public var onTouchStart = new Event<Float->Float->Int->Void> ();
public var title (get, set):String;
public var width (get, set):Int;
public var x (get, set):Int;

View File

@@ -3,7 +3,6 @@
#include <hx/CFFI.h>
#include <stdint.h>
namespace lime {
@@ -29,11 +28,14 @@ namespace lime {
static void Dispatch (TouchEvent* event);
int device;
float dx;
float dy;
int id;
float pressure;
TouchEventType type;
uint32_t windowID;
double x;
double y;
float x;
float y;
};

View File

@@ -429,30 +429,28 @@ namespace lime {
case SDL_FINGERMOTION:
touchEvent.type = TOUCH_MOVE;
touchEvent.x = event->tfinger.x;
touchEvent.y = event->tfinger.y;
touchEvent.id = event->tfinger.fingerId;
break;
case SDL_FINGERDOWN:
touchEvent.type = TOUCH_START;
touchEvent.x = event->tfinger.x;
touchEvent.y = event->tfinger.y;
touchEvent.id = event->tfinger.fingerId;
break;
case SDL_FINGERUP:
touchEvent.type = TOUCH_END;
touchEvent.x = event->tfinger.x;
touchEvent.y = event->tfinger.y;
touchEvent.id = event->tfinger.fingerId;
break;
}
//touchEvent.windowID = event->tfinger.windowID;
touchEvent.x = event->tfinger.x;
touchEvent.y = event->tfinger.y;
touchEvent.id = event->tfinger.fingerId;
touchEvent.dx = event->tfinger.dx;
touchEvent.dy = event->tfinger.dy;
touchEvent.pressure = event->tfinger.pressure;
touchEvent.device = event->tfinger.touchId;
TouchEvent::Dispatch (&touchEvent);
}

View File

@@ -8,9 +8,12 @@ namespace lime {
AutoGCRoot* TouchEvent::callback = 0;
AutoGCRoot* TouchEvent::eventObject = 0;
static int id_device;
static int id_dx;
static int id_dy;
static int id_id;
static int id_pressure;
static int id_type;
static int id_windowID;
static int id_x;
static int id_y;
static bool init = false;
@@ -18,11 +21,14 @@ namespace lime {
TouchEvent::TouchEvent () {
id = 0;
type = TOUCH_START;
windowID = 0;
x = 0;
y = 0;
id = 0;
dx = 0;
dy = 0;
pressure = 0;
device = 0;
}
@@ -33,9 +39,12 @@ namespace lime {
if (!init) {
id_device = val_id ("device");
id_dx = val_id ("dx");
id_dy = val_id ("dy");
id_id = val_id ("id");
id_pressure = val_id ("pressure");
id_type = val_id ("type");
id_windowID = val_id ("windowID");
id_x = val_id ("x");
id_y = val_id ("y");
init = true;
@@ -44,9 +53,12 @@ namespace lime {
value object = (TouchEvent::eventObject ? TouchEvent::eventObject->get () : alloc_empty_object ());
alloc_field (object, id_device, alloc_int (event->device));
alloc_field (object, id_dx, alloc_float (event->dx));
alloc_field (object, id_dy, alloc_float (event->dy));
alloc_field (object, id_id, alloc_int (event->id));
alloc_field (object, id_pressure, alloc_float (event->pressure));
alloc_field (object, id_type, alloc_int (event->type));
alloc_field (object, id_windowID, alloc_int (event->windowID));
alloc_field (object, id_x, alloc_float (event->x));
alloc_field (object, id_y, alloc_float (event->y));