Skip to content

Commit d3921f8

Browse files
authored
Merge pull request #19 from fernandojsg/behaviours
Basic implementation of activators and behaviours
2 parents 14d6e31 + 2ebf16a commit d3921f8

File tree

10 files changed

+344
-77
lines changed

10 files changed

+344
-77
lines changed

‎examples/basic/index.html‎

Lines changed: 64 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,12 @@
5656
changeTask: { label: 'Change task' },
5757
logdefault: { label: 'Test Log' },
5858
logtask1: { label: 'Test Log Task 1' },
59+
logtask2: { label: 'Test Log Task 2' },
5960
lefthand: { label: 'Left hand' },
6061
righthand: { label: 'Right hand' },
62+
longpress: { label: 'Long press' },
63+
doubletouch: { label: 'Double touch' },
64+
doublepress: { label: 'Double press' }
6165
},
6266
task2: {
6367
changeTask: { label: 'Change task' },
@@ -69,41 +73,55 @@
6973

7074
// Could be defined by default by the app or the user, custom UI, external request, etc.
7175
var mappings = {
72-
task1: {
73-
common: {
74-
triggerdown: {left: 'lefthand', right: 'righthand'}
75-
},
76-
'vive-controls': {
77-
gripdown: 'changeTask',
78-
trackpaddown: 'logdefault'
79-
},
80-
'oculus-touch-controls': {
81-
abuttondown: 'changeTask'
82-
},
83-
'windows-motion-controls': {
84-
gripdown: 'changeTask'
85-
},
86-
keyboard: {
87-
't_up': 'logdefault',
88-
'c_up': 'changeTask'
76+
behaviours: {
77+
default: {
78+
'vive-controls': {
79+
trackpad: 'dpad'
80+
}
8981
}
9082
},
91-
task2: {
92-
'vive-controls': {
93-
triggerdown: 'logtask2',
94-
gripdown: 'changeTask'
95-
},
96-
'oculus-touch-controls': {
97-
triggerdown: 'logtask2',
98-
abuttondown: 'changeTask'
83+
mappings: {
84+
task1: {
85+
common: {
86+
triggerdown: {left: 'lefthand', right: 'righthand'}
87+
},
88+
'vive-controls': {
89+
'grip.down': 'changeTask',
90+
'trackpad.down': 'logtask1',
91+
'trackpad.doubletouch': 'doubletouch',
92+
'trackpad.doublepress': 'doublepress',
93+
// Activators for down, up, touchstart and touchend are optionals you can just write the event without the .
94+
'trackpaddpadleftdown': 'dpadleft',
95+
'trackpaddpadright.longpress': 'dpadrightlong'
96+
},
97+
'oculus-touch-controls': {
98+
'abutton.down': 'changeTask'
99+
},
100+
'windows-motion-controls': {
101+
'grip.down': 'changeTask'
102+
},
103+
keyboard: {
104+
't_up': 'logdefault',
105+
'c_up': 'changeTask'
106+
}
99107
},
100-
'windows-motion-controls': {
101-
triggerdown: 'logtask2',
102-
gripdown: 'changeTask'
103-
},
104-
keyboard: {
105-
'y_up': 'logtask2',
106-
'c_up': 'changeTask'
108+
task2: {
109+
'vive-controls': {
110+
'trigger.down': 'logtask2',
111+
'grip.down': 'changeTask'
112+
},
113+
'oculus-touch-controls': {
114+
'trigger.down': 'logtask2',
115+
'abutton.down': 'changeTask'
116+
},
117+
'windows-motion-controls': {
118+
'trigger.down': 'logtask2',
119+
'grip.down': 'changeTask'
120+
},
121+
keyboard: {
122+
'y_up': 'logtask2',
123+
'c_up': 'changeTask'
124+
}
107125
}
108126
}
109127
};
@@ -124,27 +142,31 @@
124142

125143
function init()
126144
{
127-
function logEvent(evt) {
128-
var text = AFRAME.inputActions[AFRAME.currentInputMapping][evt.type].label;
145+
function logEvent (event) {
146+
var type = event.type;
147+
var currentMappingActions = AFRAME.inputActions[AFRAME.currentInputMapping];
148+
var text = currentMappingActions[type] ? currentMappingActions[type].label : type;
149+
129150
console.log(text);
130151
drawText(text);
131152
}
132-
153+
133154
mappingText.setAttribute('text', {value: 'Current mapping: ' + AFRAME.currentInputMapping});
134-
135155
var keys = Object.keys(inputActions);
136156
scene.addEventListener('changeTask', function(evt) {
137157
var next = (keys.indexOf(AFRAME.currentInputMapping) + 1) % keys.length;
138158
AFRAME.currentInputMapping = keys[next];
139159
mappingText.setAttribute('text', {value: 'Current mapping: ' + AFRAME.currentInputMapping});
140-
logEvent(evt);
160+
logEvent(event);
141161
});
142162

143-
scene.addEventListener('logtask1', function(evt) { logEvent(evt); });
144-
scene.addEventListener('logtask2', function(evt) { logEvent(evt); });
145-
scene.addEventListener('logdefault', function(evt) { logEvent(evt); });
146-
scene.addEventListener('righthand', function(evt) { logEvent(evt); });
147-
scene.addEventListener('lefthand', function(evt) { logEvent(evt); });
163+
var events = ['dpadleft', 'dpadrightlong', 'dpad', 'logtask1', 'logtask2', 'logdefault', 'righthand', 'lefthand', 'doubletouch', 'doublepress', 'longpress'];
164+
for (var i = 0; i < events.length; i++) {
165+
scene.addEventListener(events[i], function(event) {
166+
logEvent(event);
167+
});
168+
}
148169
}
170+
149171
</script>
150172
</html>

‎package.json‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
"name": "aframe-input-mapping-component",
33
"version": "0.1.2",
44
"description": "A Input Mapping component for A-Frame.",
5-
"main": "index.js",
5+
"main": "src/index.js",
66
"unpkg": "dist/aframe-input-mapping-component.min.js",
77
"scripts": {
8-
"dev": "budo index.js:dist/aframe-input-mapping-component.min.js --port 7000 --live --open",
9-
"dist": "webpack index.js dist/aframe-input-mapping-component.js && webpack -p index.js dist/aframe-input-mapping-component.min.js",
8+
"dev": "budo src/index.js:dist/aframe-input-mapping-component.min.js --port 7000 --live --open",
9+
"dist": "webpack src/index.js dist/aframe-input-mapping-component.js && webpack -p src/index.js dist/aframe-input-mapping-component.min.js",
1010
"lint": "semistandard -v | snazzy",
1111
"prepublish": "npm run dist",
1212
"ghpages": "ghpages",

‎src/activators/doublepress.js‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
function DoublePress (el, button, onActivate) {
2+
this.lastTime = 0;
3+
this.timeOut = 250;
4+
this.eventName = button + 'down';
5+
this.el = el;
6+
this.onActivate = onActivate;
7+
8+
this.onButtonDown = this.onButtonDown.bind(this);
9+
10+
el.addEventListener(this.eventName, this.onButtonDown);
11+
}
12+
13+
DoublePress.prototype = {
14+
onButtonDown (event) {
15+
var time = performance.now();
16+
if (time - this.lastTime < this.timeOut) {
17+
this.onActivate(event.detail);
18+
} else {
19+
this.lastTime = time;
20+
}
21+
},
22+
23+
removeListeners () {
24+
this.el.removeEventListener(this.eventName, this.onButtonDown);
25+
}
26+
}
27+
28+
AFRAME.registerInputActivator('doublepress', DoublePress);

‎src/activators/doubletouch.js‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
function DoubleTouch (el, button, onActivate) {
2+
this.lastTime = 0;
3+
this.timeOut = 250;
4+
this.eventName = button + 'touchstart';
5+
this.el = el;
6+
this.onActivate = onActivate;
7+
8+
this.onButtonDown = this.onButtonDown.bind(this);
9+
10+
el.addEventListener(this.eventName, this.onButtonDown);
11+
}
12+
13+
DoubleTouch.prototype = {
14+
onButtonDown (event) {
15+
var time = performance.now();
16+
if (time - this.lastTime < this.timeOut) {
17+
this.onActivate(event.detail);
18+
} else {
19+
this.lastTime = time;
20+
}
21+
},
22+
23+
removeListeners () {
24+
this.el.removeEventListener(this.eventName, this.onButtonDown);
25+
}
26+
}
27+
28+
AFRAME.registerInputActivator('doubletouch', DoubleTouch);

‎src/activators/index.js‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
AFRAME.inputActivators = {};
2+
3+
AFRAME.registerInputActivator = function (name, definition) {
4+
AFRAME.inputActivators[name] = definition;
5+
};
6+
7+
require('./longpress.js');
8+
require('./doubletouch.js');
9+
require('./doublepress.js');
10+
require('./simpleactivator.js');

‎src/activators/longpress.js‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
function LongPress (el, button, onActivate) {
2+
this.lastTime = 0;
3+
this.timeOut = 250;
4+
this.eventNameDown = button + 'down';
5+
this.eventNameUp = button + 'up';
6+
7+
this.el = el;
8+
this.onActivate = onActivate;
9+
10+
this.onButtonDown = this.onButtonDown.bind(this);
11+
this.onButtonUp = this.onButtonUp.bind(this);
12+
13+
el.addEventListener(this.eventNameDown, this.onButtonDown);
14+
el.addEventListener(this.eventNameUp, this.onButtonUp);
15+
}
16+
17+
LongPress.prototype = {
18+
onButtonDown (event) {
19+
var self = this;
20+
this.pressTimer = window.setTimeout(function () {
21+
self.onActivate(event);
22+
}, 1000);
23+
},
24+
25+
onButtonUp (event) {
26+
clearTimeout(this.pressTimer);
27+
},
28+
29+
removeListeners () {
30+
this.el.removeEventListener(this.eventNameDown, this.onButtonDown);
31+
this.el.removeEventListener(this.eventNameUp, this.onButtonUp);
32+
}
33+
}
34+
35+
AFRAME.registerInputActivator('longpress', LongPress);

‎src/activators/simpleactivator.js‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
function createSimpleActivator(suffix) {
2+
return function (el, button, onActivate) {
3+
el.addEventListener(button + suffix, onActivate);
4+
}
5+
}
6+
7+
AFRAME.registerInputActivator('down', createSimpleActivator('down'));
8+
AFRAME.registerInputActivator('up', createSimpleActivator('up'));
9+
AFRAME.registerInputActivator('touchstart', createSimpleActivator('touchstart'));
10+
AFRAME.registerInputActivator('touchend', createSimpleActivator('touchend'));

‎src/behaviours/dpad.js‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
function DPad (el, buttonName) {
2+
this.buttonName = buttonName;
3+
this.onButtonPresed = this.onButtonPresed.bind(this);
4+
this.onAxisMove = this.onAxisMove.bind(this);
5+
el.addEventListener('trackpaddown', this.onButtonPresed);
6+
el.addEventListener('trackpadup', this.onButtonPresed);
7+
el.addEventListener('axismove', this.onAxisMove);
8+
this.lastPos = [0,0];
9+
this.el = el;
10+
};
11+
12+
DPad.prototype = {
13+
onAxisMove: function(event) {
14+
this.lastPos = event.detail.axis;
15+
},
16+
17+
onButtonPresed: function (event) {
18+
const [x, y] = this.lastPos;
19+
const state = 'trackpadup'.includes(event.type) ? "up" : "down";
20+
var centerZone = 0.5;
21+
const direction =
22+
state === "up" && this.lastDirection // Always trigger the up event for the last down event
23+
? this.lastDirection
24+
: x * x + y * y < centerZone * centerZone // If within center zone angle does not matter
25+
? "center"
26+
: angleToDirection(Math.atan2(x, y));
27+
28+
this.el.emit(`${this.buttonName}dpad${direction}${state}`);
29+
30+
if (state === "down") {
31+
this.lastDirection = direction;
32+
} else {
33+
delete this.lastDirection;
34+
}
35+
},
36+
37+
removeListeners: function () {
38+
el.removeEventListener('trackpaddown', this.onButtonPresed);
39+
el.removeEventListener('trackpadup', this.onButtonPresed);
40+
el.removeEventListener('axismove', this.onAxisMove);
41+
}
42+
};
43+
44+
const angleToDirection = function (angle) {
45+
angle = (angle * THREE.Math.RAD2DEG + 180 + 45) % 360;
46+
if (angle > 0 && angle < 90) {
47+
return "down";
48+
} else if (angle >= 90 && angle < 180) {
49+
return "left";
50+
} else if (angle >= 180 && angle < 270) {
51+
return "up";
52+
} else {
53+
return "right";
54+
}
55+
};
56+
57+
AFRAME.registerInputBehaviour('dpad', DPad);

‎src/behaviours/index.js‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
AFRAME.inputBehaviours = {};
2+
3+
AFRAME.registerInputBehaviour = function (name, definition) {
4+
AFRAME.inputBehaviours[name] = definition;
5+
};
6+
7+
require('./dpad.js');

0 commit comments

Comments
 (0)