aboutsummaryrefslogtreecommitdiff
path: root/src/library_sdl.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/library_sdl.js')
-rw-r--r--src/library_sdl.js222
1 files changed, 172 insertions, 50 deletions
diff --git a/src/library_sdl.js b/src/library_sdl.js
index d90484ad..eedb8c48 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -10,7 +10,7 @@
// or otherwise).
var LibrarySDL = {
- $SDL__deps: ['$FS', '$PATH', '$Browser'],
+ $SDL__deps: ['$FS', '$PATH', '$Browser', 'SDL_GetTicks'],
$SDL: {
defaults: {
width: 320,
@@ -82,6 +82,8 @@ var LibrarySDL = {
DOMEventToSDLEvent: {},
+ TOUCH_DEFAULT_ID: 0, // Our default deviceID for touch events (we get nothing from the browser)
+
keyCodes: { // DOM code ==> SDL code. See https://developer.mozilla.org/en/Document_Object_Model_%28DOM%29/KeyboardEvent and SDL_keycode.h
// For keys that don't have unicode value, we map DOM codes with the corresponding scan codes + 1024 (using "| 1 << 10")
16: 225 | 1<<10, // shift
@@ -417,50 +419,104 @@ var LibrarySDL = {
}
},
- touchX: 0, touchY: 0,
+ // the browser sends out touchstart events with the whole group of touches
+ // even if we received a previous touchstart for a specific touch identifier.
+ // You can test this by pressing one finger to the screen, then another. You'll
+ // receive two touchstart events, the first with a touches count of 1 the second
+ // with a touches count of two.
+ // SDL sends out a new touchstart event for only each newly started touch so to
+ // emulate this, we keep track of previously started touches.
+ downFingers: {},
savedKeydown: null,
receiveEvent: function(event) {
switch(event.type) {
- case 'touchstart':
+ case 'touchstart': case 'touchmove': {
event.preventDefault();
- var touch = event.touches[0];
- touchX = touch.pageX;
- touchY = touch.pageY;
- var event = {
- type: 'mousedown',
+
+ var touches = [];
+
+ // Clear out any touchstart events that we've already processed
+ if (event.type === 'touchstart') {
+ for (var i = 0; i < event.touches.length; i++) {
+ var touch = event.touches[i];
+ if (SDL.downFingers[touch.identifier] != true) {
+ SDL.downFingers[touch.identifier] = true;
+ touches.push(touch);
+ }
+ }
+ } else {
+ touches = event.touches;
+ }
+
+ var firstTouch = touches[0];
+ if (event.type == 'touchstart') {
+ SDL.DOMButtons[0] = 1;
+ }
+ var mouseEventType;
+ switch(event.type) {
+ case 'touchstart': mouseEventType = 'mousedown'; break;
+ case 'touchmove': mouseEventType = 'mousemove'; break;
+ }
+ var mouseEvent = {
+ type: mouseEventType,
button: 0,
- pageX: touchX,
- pageY: touchY
+ pageX: firstTouch.clientX,
+ pageY: firstTouch.clientY
};
- SDL.DOMButtons[0] = 1;
- SDL.events.push(event);
- break;
- case 'touchmove':
- event.preventDefault();
- var touch = event.touches[0];
- touchX = touch.pageX;
- touchY = touch.pageY;
- event = {
- type: 'mousemove',
- button: 0,
- pageX: touchX,
- pageY: touchY
+ SDL.events.push(mouseEvent);
+
+ for (var i = 0; i < touches.length; i++) {
+ var touch = touches[i];
+ SDL.events.push({
+ type: event.type,
+ touch: touch
+ });
};
- SDL.events.push(event);
break;
- case 'touchend':
+ }
+ case 'touchend': {
event.preventDefault();
- event = {
+
+ // Remove the entry in the SDL.downFingers hash
+ // because the finger is no longer down.
+ for(var i = 0; i < event.changedTouches.length; i++) {
+ var touch = event.changedTouches[i];
+ if (SDL.downFingers[touch.identifier] === true) {
+ delete SDL.downFingers[touch.identifier];
+ }
+ }
+
+ var mouseEvent = {
type: 'mouseup',
button: 0,
- pageX: touchX,
- pageY: touchY
+ pageX: event.changedTouches[0].clientX,
+ pageY: event.changedTouches[0].clientY
};
SDL.DOMButtons[0] = 0;
- SDL.events.push(event);
+ SDL.events.push(mouseEvent);
+
+ for (var i = 0; i < event.changedTouches.length; i++) {
+ var touch = event.changedTouches[i];
+ SDL.events.push({
+ type: 'touchend',
+ touch: touch
+ });
+ };
break;
+ }
case 'mousemove':
+ if (SDL.DOMButtons[0] === 1) {
+ SDL.events.push({
+ type: 'touchmove',
+ touch: {
+ identifier: 0,
+ deviceID: {{{ cDefine('SDL_TOUCH_MOUSEID') }}},
+ pageX: event.pageX,
+ pageY: event.pageY
+ }
+ });
+ }
if (Browser.pointerLock) {
// workaround for firefox bug 750111
if ('mozMovementX' in event) {
@@ -502,6 +558,15 @@ var LibrarySDL = {
};
} else if (event.type == 'mousedown') {
SDL.DOMButtons[event.button] = 1;
+ SDL.events.push({
+ type: 'touchstart',
+ touch: {
+ identifier: 0,
+ deviceID: {{{ cDefine('SDL_TOUCH_MOUSEID') }}},
+ pageX: event.pageX,
+ pageY: event.pageY
+ }
+ });
} else if (event.type == 'mouseup') {
// ignore extra ups, can happen if we leave the canvas while pressing down, then return,
// since we add a mouseup in that case
@@ -509,6 +574,15 @@ var LibrarySDL = {
return;
}
+ SDL.events.push({
+ type: 'touchend',
+ touch: {
+ identifier: 0,
+ deviceID: {{{ cDefine('SDL_TOUCH_MOUSEID') }}},
+ pageX: event.pageX,
+ pageY: event.pageY
+ }
+ });
SDL.DOMButtons[event.button] = 0;
}
@@ -600,6 +674,10 @@ var LibrarySDL = {
event.handled = true;
switch (event.type) {
+ case 'touchstart': case 'touchend': case 'touchmove': {
+ Browser.calculateMouseEvent(event);
+ break;
+ }
case 'keydown': case 'keyup': {
var down = event.type === 'keydown';
var code = event.keyCode;
@@ -690,13 +768,19 @@ var LibrarySDL = {
if (event.type != 'mousemove') {
var down = event.type === 'mousedown';
{{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.timestamp, '0', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.windowID, '0', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.which, '0', 'i32') }}};
{{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.button, 'event.button+1', 'i8') }}}; // DOM buttons are 0-2, SDL 1-3
{{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.state, 'down ? 1 : 0', 'i8') }}};
{{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.x, 'Browser.mouseX', 'i32') }}};
{{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.y, 'Browser.mouseY', 'i32') }}};
} else {
{{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.state, 'SDL.buttonState', 'i8') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.timestamp, '0', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.windowID, '0', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.which, '0', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.state, 'SDL.buttonState', 'i32') }}};
{{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.x, 'Browser.mouseX', 'i32') }}};
{{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.y, 'Browser.mouseY', 'i32') }}};
{{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.xrel, 'Browser.mouseMovementX', 'i32') }}};
@@ -704,6 +788,33 @@ var LibrarySDL = {
}
break;
}
+ case 'touchstart': case 'touchend': case 'touchmove': {
+ var touch = event.touch;
+ var w = Module['canvas'].width;
+ var h = Module['canvas'].height;
+ var x = Browser.touches[touch.identifier].x / w;
+ var y = Browser.touches[touch.identifier].y / h;
+ var lx = Browser.lastTouches[touch.identifier].x / w;
+ var ly = Browser.lastTouches[touch.identifier].y / h;
+ var dx = x - lx;
+ var dy = y - ly;
+ if (touch['deviceID'] === undefined) touch.deviceID = SDL.TOUCH_DEFAULT_ID;
+ if (dx === 0 && dy === 0 && event.type === 'touchmove') return; // don't send these if nothing happened
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.timestamp, '_SDL_GetTicks()', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.touchId, 'touch.deviceID', 'i64') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.fingerId, 'touch.identifier', 'i64') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.x, 'x', 'float') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.y, 'y', 'float') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.dx, 'dx', 'float') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.dy, 'dy', 'float') }}};
+ if (touch.force !== undefined) {
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.pressure, 'touch.force', 'float') }}};
+ } else { // No pressure data, send a digital 0/1 pressure.
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.pressure, 'event.type == "touchend" ? 0 : 1', 'float') }}};
+ }
+ break;
+ }
case 'unload': {
{{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
break;
@@ -948,14 +1059,17 @@ var LibrarySDL = {
SDL.keyboardState = _malloc(0x10000); // Our SDL needs 512, but 64K is safe for older SDLs
_memset(SDL.keyboardState, 0, 0x10000);
// Initialize this structure carefully for closure
- SDL.DOMEventToSDLEvent['keydown'] = 0x300 /* SDL_KEYDOWN */;
- SDL.DOMEventToSDLEvent['keyup'] = 0x301 /* SDL_KEYUP */;
- SDL.DOMEventToSDLEvent['keypress'] = 0x303 /* SDL_TEXTINPUT */;
- SDL.DOMEventToSDLEvent['mousedown'] = 0x401 /* SDL_MOUSEBUTTONDOWN */;
- SDL.DOMEventToSDLEvent['mouseup'] = 0x402 /* SDL_MOUSEBUTTONUP */;
- SDL.DOMEventToSDLEvent['mousemove'] = 0x400 /* SDL_MOUSEMOTION */;
- SDL.DOMEventToSDLEvent['unload'] = 0x100 /* SDL_QUIT */;
- SDL.DOMEventToSDLEvent['resize'] = 0x7001 /* SDL_VIDEORESIZE/SDL_EVENT_COMPAT2 */;
+ SDL.DOMEventToSDLEvent['keydown'] = 0x300 /* SDL_KEYDOWN */;
+ SDL.DOMEventToSDLEvent['keyup'] = 0x301 /* SDL_KEYUP */;
+ SDL.DOMEventToSDLEvent['keypress'] = 0x303 /* SDL_TEXTINPUT */;
+ SDL.DOMEventToSDLEvent['mousedown'] = 0x401 /* SDL_MOUSEBUTTONDOWN */;
+ SDL.DOMEventToSDLEvent['mouseup'] = 0x402 /* SDL_MOUSEBUTTONUP */;
+ SDL.DOMEventToSDLEvent['mousemove'] = 0x400 /* SDL_MOUSEMOTION */;
+ SDL.DOMEventToSDLEvent['touchstart'] = 0x700 /* SDL_FINGERDOWN */;
+ SDL.DOMEventToSDLEvent['touchend'] = 0x701 /* SDL_FINGERUP */;
+ SDL.DOMEventToSDLEvent['touchmove'] = 0x702 /* SDL_FINGERMOTION */;
+ SDL.DOMEventToSDLEvent['unload'] = 0x100 /* SDL_QUIT */;
+ SDL.DOMEventToSDLEvent['resize'] = 0x7001 /* SDL_VIDEORESIZE/SDL_EVENT_COMPAT2 */;
// These are not technically DOM events; the HTML gamepad API is poll-based.
// However, we define them here, as the rest of the SDL code assumes that
// all SDL events originate as DOM events.
@@ -1025,7 +1139,7 @@ var LibrarySDL = {
},
SDL_SetVideoMode: function(width, height, depth, flags) {
- ['mousedown', 'mouseup', 'mousemove', 'DOMMouseScroll', 'mousewheel', 'mouseout'].forEach(function(event) {
+ ['touchstart', 'touchend', 'touchmove', 'mousedown', 'mouseup', 'mousemove', 'DOMMouseScroll', 'mousewheel', 'mouseout'].forEach(function(event) {
Module['canvas'].addEventListener(event, SDL.receiveEvent, true);
});
@@ -1476,20 +1590,28 @@ var LibrarySDL = {
return 0;
},
- SDL_PeepEvents: function(events, numEvents, action, from, to) {
+ SDL_PeepEvents: function(events, requestedEventCount, action, from, to) {
switch(action) {
case 2: { // SDL_GETEVENT
- assert(numEvents == 1);
- var got = 0;
- while (SDL.events.length > 0 && numEvents > 0) {
- var type = SDL.DOMEventToSDLEvent[SDL.events[0].type];
- if (type < from || type > to) break;
- SDL.makeCEvent(SDL.events.shift(), events);
- got++;
- numEvents--;
- // events += sizeof(..)
+ // We only handle 1 event right now
+ assert(requestedEventCount == 1);
+
+ var index = 0;
+ var retrievedEventCount = 0;
+ // this should look through the entire queue until it has filled up the events
+ // array
+ while (index < SDL.events.length && retrievedEventCount < requestedEventCount) {
+ var event = SDL.events[index];
+ var type = SDL.DOMEventToSDLEvent[event.type];
+ if (from <= type && type <= to) {
+ SDL.makeCEvent(event, events);
+ SDL.events.splice(index, 1);
+ retrievedEventCount++;
+ } else {
+ index++;
+ }
}
- return got;
+ return retrievedEventCount;
}
default: throw 'SDL_PeepEvents does not yet support that action: ' + action;
}