Skip to content

Commit a011e80

Browse files
ngokevindmarcos
authored andcommitted
fix vive-controls button colors (#2772)
* fix vive-controls button colors * allow trackpad touch events, but not color change for vive-controls
1 parent 293368a commit a011e80

File tree

2 files changed

+353
-202
lines changed

2 files changed

+353
-202
lines changed

‎src/components/vive-controls.js‎

Lines changed: 110 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,95 @@
11
var registerComponent = require('../core/component').registerComponent;
2-
var bind = require('../utils/bind');
3-
var checkControllerPresentAndSetup = require('../utils/tracked-controls').checkControllerPresentAndSetup;
4-
var emitIfAxesChanged = require('../utils/tracked-controls').emitIfAxesChanged;
2+
var utils = require('../utils/');
3+
4+
var bind = utils.bind;
5+
var checkControllerPresentAndSetup = utils.trackedControls.checkControllerPresentAndSetup;
6+
var emitIfAxesChanged = utils.trackedControls.emitIfAxesChanged;
57

68
var VIVE_CONTROLLER_MODEL_OBJ_URL = 'https://cdn.aframe.io/controllers/vive/vr_controller_vive.obj';
79
var VIVE_CONTROLLER_MODEL_OBJ_MTL = 'https://cdn.aframe.io/controllers/vive/vr_controller_vive.mtl';
810

911
var GAMEPAD_ID_PREFIX = 'OpenVR ';
1012

1113
/**
12-
* Vive Controls Component
13-
* Interfaces with vive controllers and maps Gamepad events to
14-
* common controller buttons: trackpad, trigger, grip, menu and system
15-
* It loads a controller model and highlights the pressed buttons
14+
* Vive controls.
15+
* Interface with Vive controllers and map Gamepad events to controller buttons:
16+
* trackpad, trigger, grip, menu, system
17+
* Load a controller model and highlight the pressed buttons.
1618
*/
1719
module.exports.Component = registerComponent('vive-controls', {
1820
schema: {
1921
hand: {default: 'left'},
2022
buttonColor: {type: 'color', default: '#FAFAFA'}, // Off-white.
2123
buttonHighlightColor: {type: 'color', default: '#22D1EE'}, // Light blue.
2224
model: {default: true},
23-
rotationOffset: {default: 0} // use -999 as sentinel value to auto-determine based on hand
25+
rotationOffset: {default: 0}
2426
},
2527

26-
// buttonId
27-
// 0 - trackpad
28-
// 1 - trigger ( intensity value from 0.5 to 1 )
29-
// 2 - grip
30-
// 3 - menu ( dispatch but better for menu options )
31-
// 4 - system ( never dispatched on this layer )
28+
/**
29+
* Button IDs:
30+
* 0 - trackpad
31+
* 1 - trigger (intensity value from 0.5 to 1)
32+
* 2 - grip
33+
* 3 - menu (dispatch but better for menu options)
34+
* 4 - system (never dispatched on this layer)
35+
*/
3236
mapping: {
3337
axes: {'trackpad': [0, 1]},
3438
buttons: ['trackpad', 'trigger', 'grip', 'menu', 'system']
3539
},
3640

37-
// Use these labels for detail on axis events such as thumbstickmoved.
38-
// e.g. for thumbstickmoved detail, the first axis returned is labeled x, and the second is labeled y.
41+
/**
42+
* Labels for detail on axis events such as `thumbstickmoved`.
43+
* For example, on `thumbstickmoved` detail, the first axis returned is labeled x, and the
44+
* second is labeled y.
45+
*/
3946
axisLabels: ['x', 'y', 'z', 'w'],
4047

41-
bindMethods: function () {
42-
this.onModelLoaded = bind(this.onModelLoaded, this);
43-
this.onControllersUpdate = bind(this.onControllersUpdate, this);
44-
this.checkIfControllerPresent = bind(this.checkIfControllerPresent, this);
45-
this.removeControllersUpdateListener = bind(this.removeControllersUpdateListener, this);
46-
this.onAxisMoved = bind(this.onAxisMoved, this);
47-
},
48-
4948
init: function () {
5049
var self = this;
5150
this.animationActive = 'pointing';
51+
this.checkControllerPresentAndSetup = checkControllerPresentAndSetup; // To allow mock.
52+
this.controllerPresent = false;
53+
this.emitIfAxesChanged = emitIfAxesChanged; // To allow mock.
54+
this.lastControllerCheck = 0;
5255
this.onButtonChanged = bind(this.onButtonChanged, this);
5356
this.onButtonDown = function (evt) { self.onButtonEvent(evt.detail.id, 'down'); };
5457
this.onButtonUp = function (evt) { self.onButtonEvent(evt.detail.id, 'up'); };
55-
this.onButtonTouchStart = function (evt) { self.onButtonEvent(evt.detail.id, 'touchstart'); };
5658
this.onButtonTouchEnd = function (evt) { self.onButtonEvent(evt.detail.id, 'touchend'); };
59+
this.onButtonTouchStart = function (evt) { self.onButtonEvent(evt.detail.id, 'touchstart'); };
5760
this.onAxisMoved = bind(this.onAxisMoved, this);
58-
this.controllerPresent = false;
59-
this.lastControllerCheck = 0;
6061
this.previousButtonValues = {};
62+
6163
this.bindMethods();
62-
this.checkControllerPresentAndSetup = checkControllerPresentAndSetup; // to allow mock
63-
this.emitIfAxesChanged = emitIfAxesChanged; // to allow mock
64+
},
65+
66+
play: function () {
67+
this.checkIfControllerPresent();
68+
this.addControllersUpdateListener();
69+
// Note that due to gamepadconnected event propagation issues, we don't rely on events.
70+
window.addEventListener('gamepaddisconnected', this.checkIfControllerPresent, false);
71+
},
72+
73+
pause: function () {
74+
this.removeEventListeners();
75+
this.removeControllersUpdateListener();
76+
// Note that due to gamepadconnected event propagation issues, we don't rely on events.
77+
window.removeEventListener('gamepaddisconnected', this.checkIfControllerPresent, false);
78+
},
79+
80+
bindMethods: function () {
81+
this.onModelLoaded = bind(this.onModelLoaded, this);
82+
this.onControllersUpdate = bind(this.onControllersUpdate, this);
83+
this.checkIfControllerPresent = bind(this.checkIfControllerPresent, this);
84+
this.removeControllersUpdateListener = bind(this.removeControllersUpdateListener, this);
85+
this.onAxisMoved = bind(this.onAxisMoved, this);
6486
},
6587

6688
addEventListeners: function () {
6789
var el = this.el;
6890
el.addEventListener('buttonchanged', this.onButtonChanged);
6991
el.addEventListener('buttondown', this.onButtonDown);
7092
el.addEventListener('buttonup', this.onButtonUp);
71-
el.addEventListener('touchstart', this.onButtonTouchStart);
72-
el.addEventListener('touchend', this.onButtonTouchEnd);
7393
el.addEventListener('model-loaded', this.onModelLoaded);
7494
el.addEventListener('axismove', this.onAxisMoved);
7595
},
@@ -79,42 +99,35 @@ module.exports.Component = registerComponent('vive-controls', {
7999
el.removeEventListener('buttonchanged', this.onButtonChanged);
80100
el.removeEventListener('buttondown', this.onButtonDown);
81101
el.removeEventListener('buttonup', this.onButtonUp);
82-
el.removeEventListener('touchstart', this.onButtonTouchStart);
83-
el.removeEventListener('touchend', this.onButtonTouchEnd);
84102
el.removeEventListener('model-loaded', this.onModelLoaded);
85103
el.removeEventListener('axismove', this.onAxisMoved);
86104
},
87105

106+
/**
107+
* Once OpenVR returns correct hand data in supporting browsers, we can use hand property.
108+
* var isPresent = this.checkControllerPresentAndSetup(this.el.sceneEl, GAMEPAD_ID_PREFIX,
109+
{ hand: data.hand });
110+
* Until then, use hardcoded index.
111+
*/
88112
checkIfControllerPresent: function () {
89113
var data = this.data;
90-
// Once OpenVR / SteamVR return correct hand data in the supporting browsers, we can use hand property.
91-
// var isPresent = this.checkControllerPresentAndSetup(this.el.sceneEl, GAMEPAD_ID_PREFIX, { hand: data.hand });
92-
// Until then, use hardcoded index.
93114
var controllerIndex = data.hand === 'right' ? 0 : data.hand === 'left' ? 1 : 2;
94-
this.checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX, { index: controllerIndex });
95-
},
96-
97-
play: function () {
98-
this.checkIfControllerPresent();
99-
this.addControllersUpdateListener();
100-
// Note that due to gamepadconnected event propagation issues, we don't rely on events.
101-
window.addEventListener('gamepaddisconnected', this.checkIfControllerPresent, false);
102-
},
103-
104-
pause: function () {
105-
this.removeEventListeners();
106-
this.removeControllersUpdateListener();
107-
// Note that due to gamepadconnected event propagation issues, we don't rely on events.
108-
window.removeEventListener('gamepaddisconnected', this.checkIfControllerPresent, false);
115+
this.checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX, {index: controllerIndex});
109116
},
110117

111118
injectTrackedControls: function () {
112119
var el = this.el;
113120
var data = this.data;
114-
// handId: 0 - right, 1 - left, 2 - anything else...
115-
var controller = data.hand === 'right' ? 0 : data.hand === 'left' ? 1 : 2;
116-
// if we have an OpenVR Gamepad, use the fixed mapping
117-
el.setAttribute('tracked-controls', {idPrefix: GAMEPAD_ID_PREFIX, controller: controller, rotationOffset: data.rotationOffset});
121+
122+
// If we have an OpenVR Gamepad, use the fixed mapping.
123+
el.setAttribute('tracked-controls', {
124+
idPrefix: GAMEPAD_ID_PREFIX,
125+
// Hand IDs: 0 = right, 1 = left, 2 = anything else.
126+
controller: data.hand === 'right' ? 0 : data.hand === 'left' ? 1 : 2,
127+
rotationOffset: data.rotationOffset
128+
});
129+
130+
// Load model.
118131
if (!this.data.model) { return; }
119132
this.el.setAttribute('obj-model', {
120133
obj: VIVE_CONTROLLER_MODEL_OBJ_URL,
@@ -130,17 +143,23 @@ module.exports.Component = registerComponent('vive-controls', {
130143
this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);
131144
},
132145

133-
onControllersUpdate: function () { this.checkIfControllerPresent(); },
146+
onControllersUpdate: function () {
147+
this.checkIfControllerPresent();
148+
},
134149

150+
/**
151+
* Rotate the trigger button based on how hard the trigger is pressed.
152+
*/
135153
onButtonChanged: function (evt) {
136154
var button = this.mapping.buttons[evt.detail.id];
137155
var buttonMeshes = this.buttonMeshes;
138156
var analogValue;
157+
139158
if (!button) { return; }
140159

141160
if (button === 'trigger') {
142161
analogValue = evt.detail.state.value;
143-
// Update button mesh, if any.
162+
// Update trigger rotation depending on button value.
144163
if (buttonMeshes && buttonMeshes.trigger) {
145164
buttonMeshes.trigger.rotation.x = -analogValue * (Math.PI / 12);
146165
}
@@ -151,9 +170,13 @@ module.exports.Component = registerComponent('vive-controls', {
151170
},
152171

153172
onModelLoaded: function (evt) {
154-
var controllerObject3D = evt.detail.model;
155173
var buttonMeshes;
174+
var controllerObject3D = evt.detail.model;
175+
var self = this;
176+
156177
if (!this.data.model) { return; }
178+
179+
// Store button meshes object to be able to change their colors.
157180
buttonMeshes = this.buttonMeshes = {};
158181
buttonMeshes.grip = {
159182
left: controllerObject3D.getObjectByName('leftgrip'),
@@ -163,41 +186,60 @@ module.exports.Component = registerComponent('vive-controls', {
163186
buttonMeshes.system = controllerObject3D.getObjectByName('systembutton');
164187
buttonMeshes.trackpad = controllerObject3D.getObjectByName('touchpad');
165188
buttonMeshes.trigger = controllerObject3D.getObjectByName('trigger');
166-
// Offset pivot point
189+
190+
// Set default colors.
191+
Object.keys(buttonMeshes).forEach(function (buttonName) {
192+
self.setButtonColor(buttonName, self.data.buttonColor);
193+
});
194+
195+
// Offset pivot point.
167196
controllerObject3D.position.set(0, -0.015, 0.04);
168197
},
169198

170-
onAxisMoved: function (evt) { this.emitIfAxesChanged(this, this.mapping.axes, evt); },
199+
onAxisMoved: function (evt) {
200+
this.emitIfAxesChanged(this, this.mapping.axes, evt);
201+
},
171202

172203
onButtonEvent: function (id, evtName) {
173204
var buttonName = this.mapping.buttons[id];
205+
var color;
174206
var i;
207+
var isTouch = evtName.indexOf('touch') !== -1;
208+
209+
// Only trackpad has touch. Ignore for the rest, even if Gamepad API says touched.
210+
if (isTouch && buttonName !== 'trackpad') { return; }
211+
212+
// Emit events.
175213
if (Array.isArray(buttonName)) {
176214
for (i = 0; i < buttonName.length; i++) {
177215
this.el.emit(buttonName[i] + evtName);
178216
}
179217
} else {
180218
this.el.emit(buttonName + evtName);
181219
}
182-
this.updateModel(buttonName, evtName);
183-
},
184220

185-
updateModel: function (buttonName, evtName) {
186-
var i;
187221
if (!this.data.model) { return; }
222+
223+
// Don't change color for trackpad touch.
224+
if (isTouch) { return; }
225+
226+
// Update colors.
227+
color = evtName === 'up' ? this.data.buttonColor : this.data.buttonHighlightColor;
188228
if (Array.isArray(buttonName)) {
189229
for (i = 0; i < buttonName.length; i++) {
190-
this.updateButtonModel(buttonName[i], evtName);
230+
this.setButtonColor(buttonName[i], color);
191231
}
192232
} else {
193-
this.updateButtonModel(buttonName, evtName);
233+
this.setButtonColor(buttonName, color);
194234
}
195235
},
196236

197-
updateButtonModel: function (buttonName, state) {
198-
var color = state === 'up' ? this.data.buttonColor : this.data.buttonHighlightColor;
237+
setButtonColor: function (buttonName, color) {
199238
var buttonMeshes = this.buttonMeshes;
239+
200240
if (!buttonMeshes) { return; }
241+
242+
// Need to do both left and right sides for grip.
201243
if (buttonName === 'grip') {
202244
buttonMeshes.grip.left.material.color.set(color);
203245
buttonMeshes.grip.right.material.color.set(color);

0 commit comments

Comments
 (0)