diff options
author | Michael Bishop <mbtyke@gmail.com> | 2013-10-18 11:04:08 -0400 |
---|---|---|
committer | Jukka Jylänki <jujjyl@gmail.com> | 2014-04-13 16:57:12 +0300 |
commit | 248be33550961ffa88130f8815616cf61701ff1e (patch) | |
tree | b615e3bb138ad986ede61ee182077aaf63d19e0c /src | |
parent | ce58885c11947bc4fb511646989c7d88212f69fa (diff) |
Added preliminary support for the SDL2 touch api. Missing items:
1. Timestamps
2. TouchID (the Device ID)
As inline with the SDL spec, we will pass a touch ID of
`SDL_TOUCH_MOUSEID` for touch events that are simulated by the
mouse so games can rely solely on touch events if they like.
Includes the SDL2 Copyright notice on the headers that contain SDL2
content.
Includes a fix to SDL_PeepEvents.
Diffstat (limited to 'src')
-rw-r--r-- | src/library_browser.js | 46 | ||||
-rw-r--r-- | src/library_sdl.js | 217 | ||||
-rw-r--r-- | src/struct_info.json | 23 |
3 files changed, 218 insertions, 68 deletions
diff --git a/src/library_browser.js b/src/library_browser.js index 0808b9f0..9f4bed5c 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -482,6 +482,8 @@ mergeInto(LibraryManager.library, { mouseY: 0, mouseMovementX: 0, mouseMovementY: 0, + touches: {}, + lastTouches: {}, calculateMouseEvent: function(event) { // event should be mousemove, mousedown or mouseup if (Browser.pointerLock) { @@ -510,8 +512,9 @@ mergeInto(LibraryManager.library, { // Otherwise, calculate the movement based on the changes // in the coordinates. var rect = Module["canvas"].getBoundingClientRect(); - var x, y; - + var cw = Module["canvas"].width; + var ch = Module["canvas"].height; + // Neither .scrollX or .pageXOffset are defined in a spec, but // we prefer .scrollX because it is currently in a spec draft. // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/) @@ -522,26 +525,37 @@ mergeInto(LibraryManager.library, { // and we have no viable fallback. assert((typeof scrollX !== 'undefined') && (typeof scrollY !== 'undefined'), 'Unable to retrieve scroll position, mouse positions likely broken.'); #endif - if (event.type == 'touchstart' || - event.type == 'touchend' || - event.type == 'touchmove') { - var t = event.touches.item(0); - if (t) { - x = t.pageX - (scrollX + rect.left); - y = t.pageY - (scrollY + rect.top); - } else { - return; + + if (event.type === 'touchstart' || event.type === 'touchend' || event.type === 'touchmove') { + var touch = event.touch; + if (touch === undefined) { + return; // the "touch" property is only defined in SDL + } - } else { - x = event.pageX - (scrollX + rect.left); - y = event.pageY - (scrollY + rect.top); + var adjustedX = touch.pageX - (scrollX + rect.left); + var adjustedY = touch.pageY - (scrollY + rect.top); + + adjustedX = adjustedX * (cw / rect.width); + adjustedY = adjustedY * (ch / rect.height); + + var coords = {x: adjustedX, y: adjustedY}; + + if (event.type === 'touchstart') { + Browser.lastTouches[touch.identifier] = coords; + Browser.touches[touch.identifier] = coords; + } else if (event.type === 'touchend' || event.type === 'touchmove') { + Browser.lastTouches[touch.identifier] = Browser.touches[touch.identifier]; + Browser.touches[touch.identifier] = { x: adjustedX, y: adjustedY }; + } + return; } + var x = event.pageX - (scrollX + rect.left); + var y = event.pageY - (scrollY + rect.top); + // the canvas might be CSS-scaled compared to its backbuffer; // SDL-using content will want mouse coordinates in terms // of backbuffer units. - var cw = Module["canvas"].width; - var ch = Module["canvas"].height; x = x * (cw / rect.width); y = y * (ch / rect.height); diff --git a/src/library_sdl.js b/src/library_sdl.js index d90484ad..ffa2b2a5 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -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', - button: 0, - pageX: touchX, - pageY: touchY + + 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; }; - 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', + 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.events.push(mouseEvent); + + for (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 (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,30 @@ 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, '0', 'i32') }}}; // XXX michaeljbishop - Unimplemented for now + {{{ 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') }}}; + {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.pressure, 'touch.force', 'float') }}}; + break; + } case 'unload': { {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}; break; @@ -948,14 +1056,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 +1136,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 +1587,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; } diff --git a/src/struct_info.json b/src/struct_info.json index 2a2b4c64..f762bf2b 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -948,11 +948,10 @@ ], "SDL_MouseMotionEvent": [ "type", + "timestamp", "windowID", + "which", "state", - "padding1", - "padding2", - "padding3", "x", "y", "xrel", @@ -960,7 +959,9 @@ ], "SDL_MouseButtonEvent": [ "type", + "timestamp", "windowID", + "which", "button", "state", "padding1", @@ -983,6 +984,17 @@ "state", "padding1" ], + "SDL_TouchFingerEvent": [ + "type", + "timestamp", + "touchId", + "fingerId", + "x", + "y", + "dx", + "dy", + "pressure" + ], "SDL_ResizeEvent": [ "type", "w", @@ -991,6 +1003,11 @@ } }, { + "file": "SDL/SDL_touch.h", + "defines": ["SDL_TOUCH_MOUSEID"], + "structs": {} + }, + { "file": "SDL/SDL_audio.h", "defines": [ "SDL_AUDIO_MASK_BITSIZE", |