Skip to content

Commit b8f20d9

Browse files
committed
Multi touch support
1 parent fe87317 commit b8f20d9

File tree

5 files changed

+555
-285
lines changed

5 files changed

+555
-285
lines changed

Build/webxr.js

Lines changed: 111 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,32 @@
1414
this.handRight = new XRHandData();
1515
this.viewerHitTestPose = new XRHitPoseData();
1616
this.frameNumber = 0;
17-
this.handHeldMove = false;
18-
this.xrData = null;
17+
this.touchIDs = [];
18+
this.touches = [];
19+
this.CreateTouch = function (pageElement, xPercentage, yPercentage) {
20+
let touchID = 0;
21+
while (this.touchIDs.includes(touchID))
22+
{
23+
touchID++;
24+
}
25+
let touch = new XRTouch(touchID, pageElement, xPercentage, yPercentage);
26+
this.touchIDs.push(touchID);
27+
this.touches.push(touch);
28+
return touch;
29+
}
30+
this.RemoveTouch = function (touch) {
31+
touch.ended = true;
32+
this.touchIDs = this.touchIDs.filter(function(item) {
33+
return item !== touch.identifier
34+
});
35+
this.touches = this.touches.filter(function(item) {
36+
return item !== touch
37+
});
38+
}
39+
this.SendTouchEvent = function(JSEventsObject, eventID, eventName, target, changedTouches) {
40+
let touchEvent = new XRTouchEvent(eventName, target, this.touches, this.touches, changedTouches);
41+
JSEventsObject.eventHandlers[eventID].eventListenerFunc(touchEvent);
42+
}
1943
}
2044

2145
function XRControllerData() {
@@ -77,9 +101,10 @@
77101
return start + (end - start) * percentage;
78102
}
79103

80-
function XRMouseEvent(eventName, pageElement, xPercentage, yPercentage, buttonNumber) {
104+
function XRTouch(touchID, pageElement, xPercentage, yPercentage) {
105+
this.identifier = touchID;
106+
this.ended = false;
81107
let rect = pageElement.getBoundingClientRect();
82-
this.type = eventName;
83108
// It was pageElement.size / window.devicePixelRatio, but now we treat devicePixelRatio in XR session as 1
84109
this.clientX = lerp(rect.left, rect.left + pageElement.width / 1, xPercentage);
85110
this.clientY = lerp(rect.top, rect.top + pageElement.height / 1, yPercentage);
@@ -95,32 +120,45 @@
95120
this.screenY = this.clientY;
96121
this.movementX = 0; // diff between movements
97122
this.movementY = 0; // diff between movements
98-
this.button = 0; // 0 none or main, 1 middle, 2 secondary
99-
this.buttons = 0; // 0 none, 1 main, 4 middle, 2 secondary
100-
switch (buttonNumber)
101-
{
102-
case -1:
103-
this.button = 0;
104-
this.buttons = 0;
105-
break;
106-
case 0:
107-
this.button = 0;
108-
this.buttons = 1;
109-
break;
110-
case 1:
111-
this.button = 1;
112-
this.buttons = 4;
113-
break;
114-
case 2:
115-
this.button = 2;
116-
this.buttons = 2;
117-
break;
123+
this.UpdateTouch = function (pageElement, xPercentage, yPercentage) {
124+
let rect = pageElement.getBoundingClientRect();
125+
let newClientX = lerp(rect.left, rect.left + pageElement.width / 1, xPercentage);
126+
let newClientY = lerp(rect.top, rect.top + pageElement.height / 1, yPercentage);
127+
this.movementX = newClientX-this.clientX;
128+
this.movementY = newClientY-this.clientY;
129+
this.clientX = newClientX;
130+
this.clientY = newClientY;
131+
this.layerX = this.clientX;
132+
this.layerY = this.clientY;
133+
this.offsetX = this.clientX;
134+
this.offsetY = this.clientY;
135+
this.pageX = this.clientX;
136+
this.pageY = this.clientY;
137+
this.x = this.clientX;
138+
this.y = this.clientY;
139+
this.screenX = this.clientX;
140+
this.screenY = this.clientY;
141+
}
142+
this.HasMovement = function () {
143+
return (this.movementX != 0 || this.movementY != 0);
144+
}
145+
this.ResetMovement = function () {
146+
this.movementX = 0;
147+
this.movementY = 0;
118148
}
149+
}
150+
151+
function XRTouchEvent(eventName, target, touches, targetTouchs, changedTouches) {
152+
this.type = eventName;
153+
this.target = target;
154+
this.touches = touches;
155+
this.targetTouches = targetTouchs;
156+
this.changedTouches = changedTouches;
119157
this.ctrlKey = false;
120158
this.altKey = false;
121159
this.metaKey = false;
122160
this.shiftKey = false;
123-
this.detail = 0;
161+
this.preventDefault = function () {};
124162
}
125163

126164
function XRManager() {
@@ -259,6 +297,8 @@
259297
this.viewerHitTestSource.cancel();
260298
this.viewerHitTestSource = null;
261299
}
300+
301+
this.removeRemainingTouches();
262302

263303
this.xrData.controllerA.enabled = 0;
264304
this.xrData.controllerB.enabled = 0;
@@ -295,6 +335,15 @@
295335
});
296336
}
297337

338+
XRManager.prototype.removeRemainingTouches = function () {
339+
while (this.xrData.touches.length > 0)
340+
{
341+
let touch = this.xrData.touches[0];
342+
this.xrData.RemoveTouch(touch);
343+
this.xrData.SendTouchEvent(this.JSEventsObject, 8, "touchend", this.canvas, [touch]);
344+
}
345+
}
346+
298347
XRManager.prototype.onInputSourceEvent = function (xrInputSourceEvent) {
299348
if (xrInputSourceEvent.type && xrInputSourceEvent.inputSource
300349
&& xrInputSourceEvent.inputSource.handedness != 'none') {
@@ -345,29 +394,27 @@
345394
} else {
346395
let xPercentage = 0.5;
347396
let yPercentage = 0.5;
348-
if (xrInputSourceEvent.inputSource &&
349-
xrInputSourceEvent.inputSource.gamepad &&
350-
xrInputSourceEvent.inputSource.gamepad.axes) {
351-
xPercentage = (xrInputSourceEvent.inputSource.gamepad.axes[0] + 1.0) * 0.5;
352-
yPercentage = (xrInputSourceEvent.inputSource.gamepad.axes[1] + 1.0) * 0.5;
353-
}
354-
switch (xrInputSourceEvent.type) {
355-
case "select": // mousemove 5
356-
this.JSEventsObject.eventHandlers[5].eventListenerFunc(
357-
new XRMouseEvent("mousemove", this.canvas, xPercentage, yPercentage, 0));
358-
break;
359-
case "selectstart": // mousedown 4
360-
this.xrData.handHeldMove = true;
361-
this.JSEventsObject.eventHandlers[5].eventListenerFunc(
362-
new XRMouseEvent("mousemove", this.canvas, xPercentage, yPercentage, 0));
363-
this.JSEventsObject.eventHandlers[4].eventListenerFunc(
364-
new XRMouseEvent("mousedown", this.canvas, xPercentage, yPercentage, 0));
365-
break;
366-
case "selectend": // mouseup 3
367-
this.xrData.handHeldMove = false;
368-
this.JSEventsObject.eventHandlers[3].eventListenerFunc(
369-
new XRMouseEvent("mouseup", this.canvas, xPercentage, yPercentage, 0));
370-
break;
397+
let inputSource = xrInputSourceEvent.inputSource;
398+
if (inputSource) {
399+
if (inputSource.gamepad &&
400+
inputSource.gamepad.axes) {
401+
xPercentage = (inputSource.gamepad.axes[0] + 1.0) * 0.5;
402+
yPercentage = (inputSource.gamepad.axes[1] + 1.0) * 0.5;
403+
}
404+
switch (xrInputSourceEvent.type) {
405+
case "select": // 9 touchmove
406+
// no need to call touchmove here
407+
break;
408+
case "selectstart": // 7 touchstart
409+
inputSource.xrTouchObject = this.xrData.CreateTouch(this.canvas, xPercentage, yPercentage);
410+
this.xrData.SendTouchEvent(this.JSEventsObject, 7, "touchstart", this.canvas, [inputSource.xrTouchObject])
411+
break;
412+
case "selectend": // 8 touchend
413+
this.xrData.RemoveTouch(inputSource.xrTouchObject);
414+
this.xrData.SendTouchEvent(this.JSEventsObject, 8, "touchend", this.canvas, [inputSource.xrTouchObject]);
415+
inputSource.xrTouchObject = null;
416+
break;
417+
}
371418
}
372419
}
373420
}
@@ -506,9 +553,11 @@
506553
xrData.handRight.frame = xrData.frameNumber;
507554
xrData.controllerA.frame = xrData.frameNumber;
508555
xrData.controllerB.frame = xrData.frameNumber;
509-
if (!inputSources || !inputSources.length) {
556+
if (!inputSources || !inputSources.length || inputSources.length == 0) {
557+
this.removeRemainingTouches();
510558
return;
511559
}
560+
let touchesToSend = [];
512561
for (var i = 0; i < inputSources.length; i++) {
513562
let inputSource = inputSources[i];
514563
// Show the input source if it has a grip space
@@ -635,14 +684,19 @@
635684
xrData.controllerB = controller;
636685
}
637686
}
638-
} else if (xrData.handHeldMove && inputSource.gamepad && inputSource.gamepad.axes) {
639-
if (xrData.handHeldMove)
640-
{
641-
this.JSEventsObject.eventHandlers[5].eventListenerFunc(
642-
new XRMouseEvent("mousemove", this.canvas,
643-
(inputSource.gamepad.axes[0] + 1.0) * 0.5,
644-
(inputSource.gamepad.axes[1] + 1.0) * 0.5, 0));
645-
}
687+
} else if (inputSource.xrTouchObject && !inputSource.xrTouchObject.ended && inputSource.gamepad && inputSource.gamepad.axes) {
688+
inputSource.xrTouchObject.UpdateTouch( this.canvas,
689+
(inputSource.gamepad.axes[0] + 1.0) * 0.5,
690+
(inputSource.gamepad.axes[1] + 1.0) * 0.5);
691+
if (inputSource.xrTouchObject.HasMovement()) {
692+
touchesToSend.push(inputSource.xrTouchObject);
693+
}
694+
}
695+
}
696+
if (touchesToSend.length > 0) {
697+
this.xrData.SendTouchEvent(this.JSEventsObject, 9, "touchmove", this.canvas, touchesToSend);
698+
for (var i = 0; i < touchesToSend.length; i++) {
699+
touchesToSend[i].ResetMovement();
646700
}
647701
}
648702
}

0 commit comments

Comments
 (0)