Skip to content

Commit a82ff05

Browse files
committed
use new oculus touch compatible hand models; TODO: emit events for animations/poses
change processAnimation() to animate() and simplify flow, and remove superfluous comment, per discussion on aframevr#2132 system button never seen/sent; move menu button mapping per discussion on aframevr#2132 change member idPrefix to const (and also model URLs) per discussion on aframevr#2132 move model selection into addModel per discussion on aframevr#2132 refactor to use utils function isControllerPresent per discussion on aframevr#2132 emit hand events like original version did original vive-specific events used gripclose/open, not gripup/down remove tracked-controls dependency, since that can apparently cause blank tracked-controls which won't work; synthesize fake touch events for Oculus Touch trigger and grip, since current browser builds appear to have them stuck touched; make hand-controls process and use trigger and grip touches refactor systems/tracked-controls so rebuildControllerList() is available outside tick; explicitly rebuildControllerList if none in isControllerPresent() to avoid race where gamepadconnected event triggers isControllerPresent() before tick rebuilds list add support for Vive touchpad touchstart/end remove enumerateControllers and change enumerateGamepads to getGamepadsByPrefix per discussion on aframevr#2132 remove obsoleted lines per discussion on aframevr#2132 use models from a-frame cdn once aframevr/assets#4 is merged remove obsoleted comment various code cleanup as requested per discussion on aframevr#2132 one more bit of cleanup per discussion on aframevr#2132 another round of code cleanup per discussion on aframevr#2132 accommodate renaming in aframevr/assets@66314f8 additional code cleanup per discussion on aframevr#2132 clean up animation usage remove oculus-touch namespace prefix from Oculus Touch-specific buttons/events refactor into gestures with animation and legacy event mappings, and some cleanup per discussion on aframevr#2132 for capacitive tracking, don't use menu button label, use B-or-Y, since at some point we will hopefully get access to the true menu buttons explicitly listen for A, B, X and Y touch events separately (gesture handling still uses AorX and BorY internally) remove A-or-X and B-or-Y event mapping move persisting gesture and change detection into handleButton; animateGesture and emitGestureEvents are now explicitly passed arguments minor code cleanup per discussion on aframevr#2132 one-liner cleanup code cleanup as per discussion on aframevr#2132 code cleanup and fake touch simplification whitespace cleanup
1 parent df84e6c commit a82ff05

File tree

5 files changed

+324
-184
lines changed

5 files changed

+324
-184
lines changed

‎src/components/hand-controls.js‎

Lines changed: 123 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var registerComponent = require('../core/component').registerComponent;
22

3-
var LEFT_HAND_MODEL_URL = 'https://cdn.aframe.io/controllers/hands/leftHand.json';
4-
var RIGHT_HAND_MODEL_URL = 'https://cdn.aframe.io/controllers/hands/rightHand.json';
3+
var OCULUS_LEFT_HAND_MODEL_URL = 'https://cdn.aframe.io/controllers/oculus-hands/leftHand.json';
4+
var OCULUS_RIGHT_HAND_MODEL_URL = 'https://cdn.aframe.io/controllers/oculus-hands/rightHand.json';
55

66
/**
77
*
@@ -20,12 +20,28 @@ module.exports.Component = registerComponent('hand-controls', {
2020

2121
init: function () {
2222
var self = this;
23+
this.touchedButtons = {};
24+
this.pressedButtons = {};
2325
this.onGripDown = function () { self.handleButton('grip', 'down'); };
2426
this.onGripUp = function () { self.handleButton('grip', 'up'); };
2527
this.onTrackpadDown = function () { self.handleButton('trackpad', 'down'); };
2628
this.onTrackpadUp = function () { self.handleButton('trackpad', 'up'); };
29+
this.onTrackpadTouchStart = function () { self.handleButton('trackpad', 'touchstart'); };
30+
this.onTrackpadTouchEnd = function () { self.handleButton('trackpad', 'touchend'); };
2731
this.onTriggerDown = function () { self.handleButton('trigger', 'down'); };
2832
this.onTriggerUp = function () { self.handleButton('trigger', 'up'); };
33+
this.onTriggerTouchStart = function () { self.handleButton('trigger', 'touchstart'); };
34+
this.onTriggerTouchEnd = function () { self.handleButton('trigger', 'touchend'); };
35+
this.onGripTouchStart = function () { self.handleButton('grip', 'touchstart'); };
36+
this.onGripTouchEnd = function () { self.handleButton('grip', 'touchend'); };
37+
this.onThumbstickDown = function () { self.handleButton('thumbstick', 'down'); };
38+
this.onThumbstickUp = function () { self.handleButton('thumbstick', 'up'); };
39+
this.onAorXTouchStart = function () { self.handleButton('AorX', 'touchstart'); };
40+
this.onAorXTouchEnd = function () { self.handleButton('AorX', 'touchend'); };
41+
this.onBorYTouchStart = function () { self.handleButton('BorY', 'touchstart'); };
42+
this.onBorYTouchEnd = function () { self.handleButton('BorY', 'touchend'); };
43+
this.onSurfaceTouchStart = function () { self.handleButton('surface', 'touchstart'); };
44+
this.onSurfaceTouchEnd = function () { self.handleButton('surface', 'touchend'); };
2945
},
3046

3147
play: function () {
@@ -42,8 +58,26 @@ module.exports.Component = registerComponent('hand-controls', {
4258
el.addEventListener('gripup', this.onGripUp);
4359
el.addEventListener('trackpaddown', this.onTrackpadDown);
4460
el.addEventListener('trackpadup', this.onTrackpadUp);
61+
el.addEventListener('trackpadtouchstart', this.onTrackpadTouchStart);
62+
el.addEventListener('trackpadtouchend', this.onTrackpadTouchEnd);
4563
el.addEventListener('triggerdown', this.onTriggerDown);
4664
el.addEventListener('triggerup', this.onTriggerUp);
65+
el.addEventListener('triggertouchstart', this.onTriggerTouchStart);
66+
el.addEventListener('triggertouchend', this.onTriggerTouchEnd);
67+
el.addEventListener('griptouchstart', this.onGripTouchStart);
68+
el.addEventListener('griptouchend', this.onGripTouchEnd);
69+
el.addEventListener('thumbstickdown', this.onThumbstickDown);
70+
el.addEventListener('thumbstickup', this.onThumbstickUp);
71+
el.addEventListener('Atouchstart', this.onAorXTouchStart);
72+
el.addEventListener('Atouchend', this.onAorXTouchEnd);
73+
el.addEventListener('Btouchstart', this.onBorYTouchStart);
74+
el.addEventListener('Btouchend', this.onBorYTouchEnd);
75+
el.addEventListener('Xtouchstart', this.onAorXTouchStart);
76+
el.addEventListener('Xtouchend', this.onAorXTouchEnd);
77+
el.addEventListener('Ytouchstart', this.onBorYTouchStart);
78+
el.addEventListener('Ytouchend', this.onBorYTouchEnd);
79+
el.addEventListener('surfacetouchstart', this.onSurfaceTouchStart);
80+
el.addEventListener('surfacetouchend', this.onSurfaceTouchEnd);
4781
},
4882

4983
removeEventListeners: function () {
@@ -52,30 +86,44 @@ module.exports.Component = registerComponent('hand-controls', {
5286
el.removeEventListener('gripup', this.onGripUp);
5387
el.removeEventListener('trackpaddown', this.onTrackpadDown);
5488
el.removeEventListener('trackpadup', this.onTrackpadUp);
89+
el.removeEventListener('trackpadtouchstart', this.onTrackpadTouchStart);
90+
el.removeEventListener('trackpadtouchend', this.onTrackpadTouchEnd);
5591
el.removeEventListener('triggerdown', this.onTriggerDown);
5692
el.removeEventListener('triggerup', this.onTriggerUp);
93+
el.removeEventListener('triggertouchstart', this.onTriggerTouchStart);
94+
el.removeEventListener('triggertouchend', this.onTriggerTouchEnd);
95+
el.removeEventListener('griptouchstart', this.onGripTouchStart);
96+
el.removeEventListener('griptouchend', this.onGripTouchEnd);
97+
el.removeEventListener('thumbstickdown', this.onThumbstickDown);
98+
el.removeEventListener('thumbstickup', this.onThumbstickUp);
99+
el.removeEventListener('Atouchstart', this.onAorXTouchStart);
100+
el.removeEventListener('Atouchend', this.onAorXTouchEnd);
101+
el.removeEventListener('Btouchstart', this.onBorYTouchStart);
102+
el.removeEventListener('Btouchend', this.onBorYTouchEnd);
103+
el.removeEventListener('Xtouchstart', this.onAorXTouchStart);
104+
el.removeEventListener('Xtouchend', this.onAorXTouchEnd);
105+
el.removeEventListener('Ytouchstart', this.onBorYTouchStart);
106+
el.removeEventListener('Ytouchend', this.onBorYTouchEnd);
107+
el.removeEventListener('surfacetouchstart', this.onSurfaceTouchStart);
108+
el.removeEventListener('surfacetouchend', this.onSurfaceTouchEnd);
57109
},
58110

59111
update: function () {
60112
var el = this.el;
61113
var hand = this.data;
62-
var modelUrl;
63-
if (hand === 'left') {
64-
modelUrl = 'url(' + LEFT_HAND_MODEL_URL + ')';
65-
} else {
66-
// NOTE: in theory some controllers may not only 'left' or 'right'
67-
// ... but as we only have two models, here we will use right hand
68-
modelUrl = 'url(' + RIGHT_HAND_MODEL_URL + ')';
69-
}
70-
71114
var controlConfiguration = {
72115
hand: hand,
73116
model: false,
74117
rotationOffset: hand === 'left' ? 90 : -90
75118
};
119+
var modelUrl;
120+
if (hand === 'left') {
121+
modelUrl = 'url(' + OCULUS_LEFT_HAND_MODEL_URL + ')';
122+
} else {
123+
modelUrl = 'url(' + OCULUS_RIGHT_HAND_MODEL_URL + ')';
124+
}
76125
el.setAttribute('vive-controls', controlConfiguration);
77126
el.setAttribute('oculus-touch-controls', controlConfiguration);
78-
79127
el.setAttribute('blend-character-model', modelUrl);
80128
},
81129

@@ -85,34 +133,73 @@ module.exports.Component = registerComponent('hand-controls', {
85133
* @param {string} evt the event associated to the button
86134
*/
87135
handleButton: function (button, evt) {
88-
var el = this.el;
89136
var isPressed = evt === 'down';
90-
switch (button) {
91-
case 'trackpad':
92-
if (isPressed === this.trackpadPressed) { return; }
93-
this.trackpadPressed = isPressed;
94-
this.playAnimation('thumb', !isPressed);
95-
evt = isPressed ? 'thumbup' : 'thumbdown';
96-
el.emit(evt);
97-
break;
98-
case 'trigger':
99-
if (isPressed === this.triggerPressed) { return; }
100-
this.triggerPressed = isPressed;
101-
this.playAnimation('pointing', !isPressed);
102-
evt = isPressed ? 'pointup' : 'pointdown';
103-
el.emit(evt);
104-
break;
105-
case 'grip':
106-
if (isPressed === this.gripPressed) { return; }
107-
this.gripPressed = isPressed;
108-
this.playAnimation('close', !isPressed);
109-
evt = isPressed ? 'gripclose' : 'gripopen';
110-
el.emit(evt);
111-
break;
137+
var isTouched = evt === 'touchstart';
138+
var lastGesture;
139+
if (evt.indexOf('touch') === 0) {
140+
if (isTouched === this.touchedButtons[button]) { return; }
141+
this.touchedButtons[button] = isTouched;
142+
} else {
143+
if (isPressed === this.pressedButtons[button]) { return; }
144+
this.pressedButtons[button] = isPressed;
112145
}
146+
lastGesture = this.gesture;
147+
this.gesture = this.determineGesture();
148+
if (this.gesture === lastGesture) { return; }
149+
this.animateGesture(this.gesture);
150+
this.emitGestureEvents(this.gesture, lastGesture);
113151
},
114152

115-
/**
153+
determineGesture: function () {
154+
var gesture;
155+
var isGripActive = this.pressedButtons['grip'];
156+
var isSurfaceActive = this.pressedButtons['surface'] || this.touchedButtons['surface'];
157+
var isTrackpadActive = this.pressedButtons['trackpad'] || this.touchedButtons['trackpad'];
158+
var isTriggerActive = this.pressedButtons['trigger'] || this.touchedButtons['trigger'];
159+
var isABXYActive = this.touchedButtons['AorX'] || this.touchedButtons['BorY'];
160+
if (isGripActive) {
161+
if (isSurfaceActive || isABXYActive || isTrackpadActive) {
162+
gesture = isTriggerActive ? 'fist' : 'pointing';
163+
} else {
164+
gesture = isTriggerActive ? 'thumb' : 'pistol';
165+
}
166+
} else
167+
if (isTriggerActive) { gesture = 'touch'; } // else no gesture
168+
return gesture;
169+
},
170+
171+
gestureAnimationMapping: {
172+
'pointing': 'pointing',
173+
'pistol': 'pistol',
174+
'fist': 'press',
175+
'touch': 'touch',
176+
'thumb': 'thumb'
177+
},
178+
179+
animateGesture: function (gesture) {
180+
var animation = this.gestureAnimationMapping[gesture || ''];
181+
this.playAnimation(animation || 'touch', !animation);
182+
},
183+
184+
// map to old vive-specific event names for now
185+
gestureEventMapping: {
186+
'fist': 'grip', // e.g. grip button down
187+
'touch': 'point', // e.g. trigger button down
188+
'thumb': 'thumb' // e.g. thumbs up pose - grip button down, trackpad / surface buttons up
189+
},
190+
191+
emitGestureEvents: function (gesture, lastGesture) {
192+
var el = this.el;
193+
var eventName;
194+
if (lastGesture !== gesture) {
195+
eventName = this.gestureEventMapping[lastGesture || ''];
196+
if (eventName) { el.emit(eventName + (eventName === 'grip' ? 'open' : 'down')); }
197+
eventName = this.gestureEventMapping[gesture || ''];
198+
if (eventName) { el.emit(eventName + (eventName === 'grip' ? 'close' : 'up')); }
199+
}
200+
},
201+
202+
/**
116203
* Play the hand animations based on button state.
117204
*
118205
* @param {string} animation - the name of the animation.

0 commit comments

Comments
 (0)