|
10 | 10 | // or otherwise).
|
11 | 11 |
|
12 | 12 | var LibrarySDL = {
|
13 |
| - $SDL__deps: ['$FS', '$PATH', '$Browser'], |
| 13 | + $SDL__deps: ['$FS', '$PATH', '$Browser', 'SDL_GetTicks'], |
14 | 14 | $SDL: {
|
15 | 15 | defaults: {
|
16 | 16 | width: 320,
|
@@ -82,6 +82,8 @@ var LibrarySDL = {
|
82 | 82 |
|
83 | 83 | DOMEventToSDLEvent: {},
|
84 | 84 |
|
| 85 | + TOUCH_DEFAULT_ID: 0, // Our default deviceID for touch events (we get nothing from the browser) |
| 86 | + |
85 | 87 | keyCodes: { // DOM code ==> SDL code. See https://developer.mozilla.org/en/Document_Object_Model_%28DOM%29/KeyboardEvent and SDL_keycode.h
|
86 | 88 | // For keys that don't have unicode value, we map DOM codes with the corresponding scan codes + 1024 (using "| 1 << 10")
|
87 | 89 | 16: 225 | 1<<10, // shift
|
@@ -417,50 +419,104 @@ var LibrarySDL = {
|
417 | 419 | }
|
418 | 420 | },
|
419 | 421 |
|
420 |
| - touchX: 0, touchY: 0, |
| 422 | + // the browser sends out touchstart events with the whole group of touches |
| 423 | + // even if we received a previous touchstart for a specific touch identifier. |
| 424 | + // You can test this by pressing one finger to the screen, then another. You'll |
| 425 | + // receive two touchstart events, the first with a touches count of 1 the second |
| 426 | + // with a touches count of two. |
| 427 | + // SDL sends out a new touchstart event for only each newly started touch so to |
| 428 | + // emulate this, we keep track of previously started touches. |
| 429 | + downFingers: {}, |
421 | 430 | savedKeydown: null,
|
422 | 431 |
|
423 | 432 | receiveEvent: function(event) {
|
424 | 433 | switch(event.type) {
|
425 |
| - case 'touchstart': |
| 434 | + case 'touchstart': case 'touchmove': { |
426 | 435 | event.preventDefault();
|
427 |
| - var touch = event.touches[0]; |
428 |
| - touchX = touch.pageX; |
429 |
| - touchY = touch.pageY; |
430 |
| - var event = { |
431 |
| - type: 'mousedown', |
| 436 | + |
| 437 | + var touches = []; |
| 438 | + |
| 439 | + // Clear out any touchstart events that we've already processed |
| 440 | + if (event.type === 'touchstart') { |
| 441 | + for (var i = 0; i < event.touches.length; i++) { |
| 442 | + var touch = event.touches[i]; |
| 443 | + if (SDL.downFingers[touch.identifier] != true) { |
| 444 | + SDL.downFingers[touch.identifier] = true; |
| 445 | + touches.push(touch); |
| 446 | + } |
| 447 | + } |
| 448 | + } else { |
| 449 | + touches = event.touches; |
| 450 | + } |
| 451 | + |
| 452 | + var firstTouch = touches[0]; |
| 453 | + if (event.type == 'touchstart') { |
| 454 | + SDL.DOMButtons[0] = 1; |
| 455 | + } |
| 456 | + var mouseEventType; |
| 457 | + switch(event.type) { |
| 458 | + case 'touchstart': mouseEventType = 'mousedown'; break; |
| 459 | + case 'touchmove': mouseEventType = 'mousemove'; break; |
| 460 | + } |
| 461 | + var mouseEvent = { |
| 462 | + type: mouseEventType, |
432 | 463 | button: 0,
|
433 |
| - pageX: touchX, |
434 |
| - pageY: touchY |
| 464 | + pageX: firstTouch.clientX, |
| 465 | + pageY: firstTouch.clientY |
435 | 466 | };
|
436 |
| - SDL.DOMButtons[0] = 1; |
437 |
| - SDL.events.push(event); |
438 |
| - break; |
439 |
| - case 'touchmove': |
440 |
| - event.preventDefault(); |
441 |
| - var touch = event.touches[0]; |
442 |
| - touchX = touch.pageX; |
443 |
| - touchY = touch.pageY; |
444 |
| - event = { |
445 |
| - type: 'mousemove', |
446 |
| - button: 0, |
447 |
| - pageX: touchX, |
448 |
| - pageY: touchY |
| 467 | + SDL.events.push(mouseEvent); |
| 468 | + |
| 469 | + for (var i = 0; i < touches.length; i++) { |
| 470 | + var touch = touches[i]; |
| 471 | + SDL.events.push({ |
| 472 | + type: event.type, |
| 473 | + touch: touch |
| 474 | + }); |
449 | 475 | };
|
450 |
| - SDL.events.push(event); |
451 | 476 | break;
|
452 |
| - case 'touchend': |
| 477 | + } |
| 478 | + case 'touchend': { |
453 | 479 | event.preventDefault();
|
454 |
| - event = { |
| 480 | + |
| 481 | + // Remove the entry in the SDL.downFingers hash |
| 482 | + // because the finger is no longer down. |
| 483 | + for(var i = 0; i < event.changedTouches.length; i++) { |
| 484 | + var touch = event.changedTouches[i]; |
| 485 | + if (SDL.downFingers[touch.identifier] === true) { |
| 486 | + delete SDL.downFingers[touch.identifier]; |
| 487 | + } |
| 488 | + } |
| 489 | + |
| 490 | + var mouseEvent = { |
455 | 491 | type: 'mouseup',
|
456 | 492 | button: 0,
|
457 |
| - pageX: touchX, |
458 |
| - pageY: touchY |
| 493 | + pageX: event.changedTouches[0].clientX, |
| 494 | + pageY: event.changedTouches[0].clientY |
459 | 495 | };
|
460 | 496 | SDL.DOMButtons[0] = 0;
|
461 |
| - SDL.events.push(event); |
| 497 | + SDL.events.push(mouseEvent); |
| 498 | + |
| 499 | + for (var i = 0; i < event.changedTouches.length; i++) { |
| 500 | + var touch = event.changedTouches[i]; |
| 501 | + SDL.events.push({ |
| 502 | + type: 'touchend', |
| 503 | + touch: touch |
| 504 | + }); |
| 505 | + }; |
462 | 506 | break;
|
| 507 | + } |
463 | 508 | case 'mousemove':
|
| 509 | + if (SDL.DOMButtons[0] === 1) { |
| 510 | + SDL.events.push({ |
| 511 | + type: 'touchmove', |
| 512 | + touch: { |
| 513 | + identifier: 0, |
| 514 | + deviceID: {{{ cDefine('SDL_TOUCH_MOUSEID') }}}, |
| 515 | + pageX: event.pageX, |
| 516 | + pageY: event.pageY |
| 517 | + } |
| 518 | + }); |
| 519 | + } |
464 | 520 | if (Browser.pointerLock) {
|
465 | 521 | // workaround for firefox bug 750111
|
466 | 522 | if ('mozMovementX' in event) {
|
@@ -502,13 +558,31 @@ var LibrarySDL = {
|
502 | 558 | };
|
503 | 559 | } else if (event.type == 'mousedown') {
|
504 | 560 | SDL.DOMButtons[event.button] = 1;
|
| 561 | + SDL.events.push({ |
| 562 | + type: 'touchstart', |
| 563 | + touch: { |
| 564 | + identifier: 0, |
| 565 | + deviceID: {{{ cDefine('SDL_TOUCH_MOUSEID') }}}, |
| 566 | + pageX: event.pageX, |
| 567 | + pageY: event.pageY |
| 568 | + } |
| 569 | + }); |
505 | 570 | } else if (event.type == 'mouseup') {
|
506 | 571 | // ignore extra ups, can happen if we leave the canvas while pressing down, then return,
|
507 | 572 | // since we add a mouseup in that case
|
508 | 573 | if (!SDL.DOMButtons[event.button]) {
|
509 | 574 | return;
|
510 | 575 | }
|
511 | 576 |
|
| 577 | + SDL.events.push({ |
| 578 | + type: 'touchend', |
| 579 | + touch: { |
| 580 | + identifier: 0, |
| 581 | + deviceID: {{{ cDefine('SDL_TOUCH_MOUSEID') }}}, |
| 582 | + pageX: event.pageX, |
| 583 | + pageY: event.pageY |
| 584 | + } |
| 585 | + }); |
512 | 586 | SDL.DOMButtons[event.button] = 0;
|
513 | 587 | }
|
514 | 588 |
|
@@ -600,6 +674,10 @@ var LibrarySDL = {
|
600 | 674 | event.handled = true;
|
601 | 675 |
|
602 | 676 | switch (event.type) {
|
| 677 | + case 'touchstart': case 'touchend': case 'touchmove': { |
| 678 | + Browser.calculateMouseEvent(event); |
| 679 | + break; |
| 680 | + } |
603 | 681 | case 'keydown': case 'keyup': {
|
604 | 682 | var down = event.type === 'keydown';
|
605 | 683 | var code = event.keyCode;
|
@@ -690,20 +768,53 @@ var LibrarySDL = {
|
690 | 768 | if (event.type != 'mousemove') {
|
691 | 769 | var down = event.type === 'mousedown';
|
692 | 770 | {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
|
| 771 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.timestamp, '0', 'i32') }}}; |
| 772 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.windowID, '0', 'i32') }}}; |
| 773 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.which, '0', 'i32') }}}; |
693 | 774 | {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.button, 'event.button+1', 'i8') }}}; // DOM buttons are 0-2, SDL 1-3
|
694 | 775 | {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.state, 'down ? 1 : 0', 'i8') }}};
|
695 | 776 | {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.x, 'Browser.mouseX', 'i32') }}};
|
696 | 777 | {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.y, 'Browser.mouseY', 'i32') }}};
|
697 | 778 | } else {
|
698 | 779 | {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
|
699 |
| - {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.state, 'SDL.buttonState', 'i8') }}}; |
| 780 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.timestamp, '0', 'i32') }}}; |
| 781 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.windowID, '0', 'i32') }}}; |
| 782 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.which, '0', 'i32') }}}; |
| 783 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.state, 'SDL.buttonState', 'i32') }}}; |
700 | 784 | {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.x, 'Browser.mouseX', 'i32') }}};
|
701 | 785 | {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.y, 'Browser.mouseY', 'i32') }}};
|
702 | 786 | {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.xrel, 'Browser.mouseMovementX', 'i32') }}};
|
703 | 787 | {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.yrel, 'Browser.mouseMovementY', 'i32') }}};
|
704 | 788 | }
|
705 | 789 | break;
|
706 | 790 | }
|
| 791 | + case 'touchstart': case 'touchend': case 'touchmove': { |
| 792 | + var touch = event.touch; |
| 793 | + var w = Module['canvas'].width; |
| 794 | + var h = Module['canvas'].height; |
| 795 | + var x = Browser.touches[touch.identifier].x / w; |
| 796 | + var y = Browser.touches[touch.identifier].y / h; |
| 797 | + var lx = Browser.lastTouches[touch.identifier].x / w; |
| 798 | + var ly = Browser.lastTouches[touch.identifier].y / h; |
| 799 | + var dx = x - lx; |
| 800 | + var dy = y - ly; |
| 801 | + if (touch['deviceID'] === undefined) touch.deviceID = SDL.TOUCH_DEFAULT_ID; |
| 802 | + if (dx === 0 && dy === 0 && event.type === 'touchmove') return; // don't send these if nothing happened |
| 803 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}; |
| 804 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.timestamp, '_SDL_GetTicks()', 'i32') }}}; |
| 805 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.touchId, 'touch.deviceID', 'i64') }}}; |
| 806 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.fingerId, 'touch.identifier', 'i64') }}}; |
| 807 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.x, 'x', 'float') }}}; |
| 808 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.y, 'y', 'float') }}}; |
| 809 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.dx, 'dx', 'float') }}}; |
| 810 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.dy, 'dy', 'float') }}}; |
| 811 | + if (touch.force !== undefined) { |
| 812 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.pressure, 'touch.force', 'float') }}}; |
| 813 | + } else { // No pressure data, send a digital 0/1 pressure. |
| 814 | + {{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.pressure, 'event.type == "touchend" ? 0 : 1', 'float') }}}; |
| 815 | + } |
| 816 | + break; |
| 817 | + } |
707 | 818 | case 'unload': {
|
708 | 819 | {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
|
709 | 820 | break;
|
@@ -948,14 +1059,17 @@ var LibrarySDL = {
|
948 | 1059 | SDL.keyboardState = _malloc(0x10000); // Our SDL needs 512, but 64K is safe for older SDLs
|
949 | 1060 | _memset(SDL.keyboardState, 0, 0x10000);
|
950 | 1061 | // Initialize this structure carefully for closure
|
951 |
| - SDL.DOMEventToSDLEvent['keydown'] = 0x300 /* SDL_KEYDOWN */; |
952 |
| - SDL.DOMEventToSDLEvent['keyup'] = 0x301 /* SDL_KEYUP */; |
953 |
| - SDL.DOMEventToSDLEvent['keypress'] = 0x303 /* SDL_TEXTINPUT */; |
954 |
| - SDL.DOMEventToSDLEvent['mousedown'] = 0x401 /* SDL_MOUSEBUTTONDOWN */; |
955 |
| - SDL.DOMEventToSDLEvent['mouseup'] = 0x402 /* SDL_MOUSEBUTTONUP */; |
956 |
| - SDL.DOMEventToSDLEvent['mousemove'] = 0x400 /* SDL_MOUSEMOTION */; |
957 |
| - SDL.DOMEventToSDLEvent['unload'] = 0x100 /* SDL_QUIT */; |
958 |
| - SDL.DOMEventToSDLEvent['resize'] = 0x7001 /* SDL_VIDEORESIZE/SDL_EVENT_COMPAT2 */; |
| 1062 | + SDL.DOMEventToSDLEvent['keydown'] = 0x300 /* SDL_KEYDOWN */; |
| 1063 | + SDL.DOMEventToSDLEvent['keyup'] = 0x301 /* SDL_KEYUP */; |
| 1064 | + SDL.DOMEventToSDLEvent['keypress'] = 0x303 /* SDL_TEXTINPUT */; |
| 1065 | + SDL.DOMEventToSDLEvent['mousedown'] = 0x401 /* SDL_MOUSEBUTTONDOWN */; |
| 1066 | + SDL.DOMEventToSDLEvent['mouseup'] = 0x402 /* SDL_MOUSEBUTTONUP */; |
| 1067 | + SDL.DOMEventToSDLEvent['mousemove'] = 0x400 /* SDL_MOUSEMOTION */; |
| 1068 | + SDL.DOMEventToSDLEvent['touchstart'] = 0x700 /* SDL_FINGERDOWN */; |
| 1069 | + SDL.DOMEventToSDLEvent['touchend'] = 0x701 /* SDL_FINGERUP */; |
| 1070 | + SDL.DOMEventToSDLEvent['touchmove'] = 0x702 /* SDL_FINGERMOTION */; |
| 1071 | + SDL.DOMEventToSDLEvent['unload'] = 0x100 /* SDL_QUIT */; |
| 1072 | + SDL.DOMEventToSDLEvent['resize'] = 0x7001 /* SDL_VIDEORESIZE/SDL_EVENT_COMPAT2 */; |
959 | 1073 | // These are not technically DOM events; the HTML gamepad API is poll-based.
|
960 | 1074 | // However, we define them here, as the rest of the SDL code assumes that
|
961 | 1075 | // all SDL events originate as DOM events.
|
@@ -1025,7 +1139,7 @@ var LibrarySDL = {
|
1025 | 1139 | },
|
1026 | 1140 |
|
1027 | 1141 | SDL_SetVideoMode: function(width, height, depth, flags) {
|
1028 |
| - ['mousedown', 'mouseup', 'mousemove', 'DOMMouseScroll', 'mousewheel', 'mouseout'].forEach(function(event) { |
| 1142 | + ['touchstart', 'touchend', 'touchmove', 'mousedown', 'mouseup', 'mousemove', 'DOMMouseScroll', 'mousewheel', 'mouseout'].forEach(function(event) { |
1029 | 1143 | Module['canvas'].addEventListener(event, SDL.receiveEvent, true);
|
1030 | 1144 | });
|
1031 | 1145 |
|
@@ -1476,20 +1590,28 @@ var LibrarySDL = {
|
1476 | 1590 | return 0;
|
1477 | 1591 | },
|
1478 | 1592 |
|
1479 |
| - SDL_PeepEvents: function(events, numEvents, action, from, to) { |
| 1593 | + SDL_PeepEvents: function(events, requestedEventCount, action, from, to) { |
1480 | 1594 | switch(action) {
|
1481 | 1595 | case 2: { // SDL_GETEVENT
|
1482 |
| - assert(numEvents == 1); |
1483 |
| - var got = 0; |
1484 |
| - while (SDL.events.length > 0 && numEvents > 0) { |
1485 |
| - var type = SDL.DOMEventToSDLEvent[SDL.events[0].type]; |
1486 |
| - if (type < from || type > to) break; |
1487 |
| - SDL.makeCEvent(SDL.events.shift(), events); |
1488 |
| - got++; |
1489 |
| - numEvents--; |
1490 |
| - // events += sizeof(..) |
| 1596 | + // We only handle 1 event right now |
| 1597 | + assert(requestedEventCount == 1); |
| 1598 | + |
| 1599 | + var index = 0; |
| 1600 | + var retrievedEventCount = 0; |
| 1601 | + // this should look through the entire queue until it has filled up the events |
| 1602 | + // array |
| 1603 | + while (index < SDL.events.length && retrievedEventCount < requestedEventCount) { |
| 1604 | + var event = SDL.events[index]; |
| 1605 | + var type = SDL.DOMEventToSDLEvent[event.type]; |
| 1606 | + if (from <= type && type <= to) { |
| 1607 | + SDL.makeCEvent(event, events); |
| 1608 | + SDL.events.splice(index, 1); |
| 1609 | + retrievedEventCount++; |
| 1610 | + } else { |
| 1611 | + index++; |
| 1612 | + } |
1491 | 1613 | }
|
1492 |
| - return got; |
| 1614 | + return retrievedEventCount; |
1493 | 1615 | }
|
1494 | 1616 | default: throw 'SDL_PeepEvents does not yet support that action: ' + action;
|
1495 | 1617 | }
|
|
0 commit comments