]>
Commit | Line | Data |
---|---|---|
c509e6d9 SM |
1 | var assert = chai.assert; |
2 | var expect = chai.expect; | |
3 | ||
0aaf59c2 SM |
4 | import sinon from '../vendor/sinon.js'; |
5 | ||
c509e6d9 SM |
6 | import Mouse from '../core/input/mouse.js'; |
7 | import * as eventUtils from '../core/util/events.js'; | |
8 | ||
c509e6d9 SM |
9 | describe('Mouse Event Handling', function() { |
10 | "use strict"; | |
11 | ||
12 | sinon.stub(eventUtils, 'setCapture'); | |
13 | // This function is only used on target (the canvas) | |
14 | // and for these tests we can assume that the canvas is 100x100 | |
15 | // located at coordinates 10x10 | |
16 | sinon.stub(Element.prototype, 'getBoundingClientRect').returns( | |
17 | {left: 10, right: 110, top: 10, bottom: 110, width: 100, height: 100}); | |
18 | var target = document.createElement('canvas'); | |
19 | ||
20 | // The real constructors might not work everywhere we | |
21 | // want to run these tests | |
22 | var mouseevent, touchevent; | |
23 | mouseevent = touchevent = function(typeArg, MouseEventInit) { | |
24 | var e = { type: typeArg }; | |
25 | for (var key in MouseEventInit) { | |
26 | e[key] = MouseEventInit[key]; | |
27 | } | |
28 | e.stopPropagation = sinon.spy(); | |
29 | e.preventDefault = sinon.spy(); | |
30 | return e; | |
31 | }; | |
32 | ||
33 | describe('Decode Mouse Events', function() { | |
34 | it('should decode mousedown events', function(done) { | |
747b4623 PO |
35 | var mouse = new Mouse(target); |
36 | mouse.onmousebutton = function(x, y, down, bmask) { | |
37 | expect(bmask).to.be.equal(0x01); | |
38 | expect(down).to.be.equal(1); | |
39 | done(); | |
40 | }; | |
c509e6d9 SM |
41 | mouse._handleMouseDown(mouseevent('mousedown', { button: '0x01' })); |
42 | }); | |
43 | it('should decode mouseup events', function(done) { | |
44 | var calls = 0; | |
747b4623 PO |
45 | var mouse = new Mouse(target); |
46 | mouse.onmousebutton = function(x, y, down, bmask) { | |
47 | expect(bmask).to.be.equal(0x01); | |
48 | if (calls++ === 1) { | |
49 | expect(down).to.not.be.equal(1); | |
50 | done(); | |
3d7bb020 | 51 | } |
747b4623 | 52 | }; |
c509e6d9 SM |
53 | mouse._handleMouseDown(mouseevent('mousedown', { button: '0x01' })); |
54 | mouse._handleMouseUp(mouseevent('mouseup', { button: '0x01' })); | |
55 | }); | |
56 | it('should decode mousemove events', function(done) { | |
747b4623 PO |
57 | var mouse = new Mouse(target); |
58 | mouse.onmousemove = function(x, y) { | |
59 | // Note that target relative coordinates are sent | |
60 | expect(x).to.be.equal(40); | |
61 | expect(y).to.be.equal(10); | |
62 | done(); | |
63 | }; | |
c509e6d9 SM |
64 | mouse._handleMouseMove(mouseevent('mousemove', |
65 | { clientX: 50, clientY: 20 })); | |
66 | }); | |
67 | it('should decode mousewheel events', function(done) { | |
68 | var calls = 0; | |
747b4623 PO |
69 | var mouse = new Mouse(target); |
70 | mouse.onmousebutton = function(x, y, down, bmask) { | |
71 | calls++; | |
72 | expect(bmask).to.be.equal(1<<6); | |
73 | if (calls === 1) { | |
74 | expect(down).to.be.equal(1); | |
75 | } else if (calls === 2) { | |
76 | expect(down).to.not.be.equal(1); | |
77 | done(); | |
3d7bb020 | 78 | } |
747b4623 | 79 | }; |
c509e6d9 SM |
80 | mouse._handleMouseWheel(mouseevent('mousewheel', |
81 | { deltaX: 50, deltaY: 0, | |
82 | deltaMode: 0})); | |
83 | }); | |
84 | }); | |
85 | ||
86 | describe('Double-click for Touch', function() { | |
87 | ||
88 | beforeEach(function () { this.clock = sinon.useFakeTimers(); }); | |
89 | afterEach(function () { this.clock.restore(); }); | |
90 | ||
91 | it('should use same pos for 2nd tap if close enough', function(done) { | |
92 | var calls = 0; | |
747b4623 PO |
93 | var mouse = new Mouse(target); |
94 | mouse.onmousebutton = function(x, y, down, bmask) { | |
95 | calls++; | |
96 | if (calls === 1) { | |
97 | expect(down).to.be.equal(1); | |
98 | expect(x).to.be.equal(68); | |
99 | expect(y).to.be.equal(36); | |
100 | } else if (calls === 3) { | |
101 | expect(down).to.be.equal(1); | |
102 | expect(x).to.be.equal(68); | |
103 | expect(y).to.be.equal(36); | |
104 | done(); | |
3d7bb020 | 105 | } |
747b4623 | 106 | }; |
c509e6d9 SM |
107 | // touch events are sent in an array of events |
108 | // with one item for each touch point | |
109 | mouse._handleMouseDown(touchevent( | |
110 | 'touchstart', { touches: [{ clientX: 78, clientY: 46 }]})); | |
111 | this.clock.tick(10); | |
112 | mouse._handleMouseUp(touchevent( | |
113 | 'touchend', { touches: [{ clientX: 79, clientY: 45 }]})); | |
114 | this.clock.tick(200); | |
115 | mouse._handleMouseDown(touchevent( | |
116 | 'touchstart', { touches: [{ clientX: 67, clientY: 35 }]})); | |
117 | this.clock.tick(10); | |
118 | mouse._handleMouseUp(touchevent( | |
119 | 'touchend', { touches: [{ clientX: 66, clientY: 36 }]})); | |
120 | }); | |
121 | ||
122 | it('should not modify 2nd tap pos if far apart', function(done) { | |
123 | var calls = 0; | |
747b4623 PO |
124 | var mouse = new Mouse(target); |
125 | mouse.onmousebutton = function(x, y, down, bmask) { | |
126 | calls++; | |
127 | if (calls === 1) { | |
128 | expect(down).to.be.equal(1); | |
129 | expect(x).to.be.equal(68); | |
130 | expect(y).to.be.equal(36); | |
131 | } else if (calls === 3) { | |
132 | expect(down).to.be.equal(1); | |
133 | expect(x).to.not.be.equal(68); | |
134 | expect(y).to.not.be.equal(36); | |
135 | done(); | |
3d7bb020 | 136 | } |
747b4623 | 137 | }; |
c509e6d9 SM |
138 | mouse._handleMouseDown(touchevent( |
139 | 'touchstart', { touches: [{ clientX: 78, clientY: 46 }]})); | |
140 | this.clock.tick(10); | |
141 | mouse._handleMouseUp(touchevent( | |
142 | 'touchend', { touches: [{ clientX: 79, clientY: 45 }]})); | |
143 | this.clock.tick(200); | |
144 | mouse._handleMouseDown(touchevent( | |
145 | 'touchstart', { touches: [{ clientX: 57, clientY: 35 }]})); | |
146 | this.clock.tick(10); | |
147 | mouse._handleMouseUp(touchevent( | |
148 | 'touchend', { touches: [{ clientX: 56, clientY: 36 }]})); | |
149 | }); | |
150 | ||
151 | it('should not modify 2nd tap pos if not soon enough', function(done) { | |
152 | var calls = 0; | |
747b4623 PO |
153 | var mouse = new Mouse(target); |
154 | mouse.onmousebutton = function(x, y, down, bmask) { | |
155 | calls++; | |
156 | if (calls === 1) { | |
157 | expect(down).to.be.equal(1); | |
158 | expect(x).to.be.equal(68); | |
159 | expect(y).to.be.equal(36); | |
160 | } else if (calls === 3) { | |
161 | expect(down).to.be.equal(1); | |
162 | expect(x).to.not.be.equal(68); | |
163 | expect(y).to.not.be.equal(36); | |
164 | done(); | |
3d7bb020 | 165 | } |
747b4623 | 166 | }; |
c509e6d9 SM |
167 | mouse._handleMouseDown(touchevent( |
168 | 'touchstart', { touches: [{ clientX: 78, clientY: 46 }]})); | |
169 | this.clock.tick(10); | |
170 | mouse._handleMouseUp(touchevent( | |
171 | 'touchend', { touches: [{ clientX: 79, clientY: 45 }]})); | |
172 | this.clock.tick(500); | |
173 | mouse._handleMouseDown(touchevent( | |
174 | 'touchstart', { touches: [{ clientX: 67, clientY: 35 }]})); | |
175 | this.clock.tick(10); | |
176 | mouse._handleMouseUp(touchevent( | |
177 | 'touchend', { touches: [{ clientX: 66, clientY: 36 }]})); | |
178 | }); | |
179 | ||
180 | it('should not modify 2nd tap pos if not touch', function(done) { | |
181 | var calls = 0; | |
747b4623 PO |
182 | var mouse = new Mouse(target); |
183 | mouse.onmousebutton = function(x, y, down, bmask) { | |
184 | calls++; | |
185 | if (calls === 1) { | |
186 | expect(down).to.be.equal(1); | |
187 | expect(x).to.be.equal(68); | |
188 | expect(y).to.be.equal(36); | |
189 | } else if (calls === 3) { | |
190 | expect(down).to.be.equal(1); | |
191 | expect(x).to.not.be.equal(68); | |
192 | expect(y).to.not.be.equal(36); | |
193 | done(); | |
3d7bb020 | 194 | } |
747b4623 | 195 | }; |
c509e6d9 SM |
196 | mouse._handleMouseDown(mouseevent( |
197 | 'mousedown', { button: '0x01', clientX: 78, clientY: 46 })); | |
198 | this.clock.tick(10); | |
199 | mouse._handleMouseUp(mouseevent( | |
200 | 'mouseup', { button: '0x01', clientX: 79, clientY: 45 })); | |
201 | this.clock.tick(200); | |
202 | mouse._handleMouseDown(mouseevent( | |
203 | 'mousedown', { button: '0x01', clientX: 67, clientY: 35 })); | |
204 | this.clock.tick(10); | |
205 | mouse._handleMouseUp(mouseevent( | |
206 | 'mouseup', { button: '0x01', clientX: 66, clientY: 36 })); | |
207 | }); | |
208 | ||
209 | }); | |
210 | ||
28b004fd SM |
211 | describe('Accumulate mouse wheel events with small delta', function() { |
212 | ||
213 | beforeEach(function () { this.clock = sinon.useFakeTimers(); }); | |
214 | afterEach(function () { this.clock.restore(); }); | |
215 | ||
216 | it('should accumulate wheel events if small enough', function () { | |
747b4623 PO |
217 | var mouse = new Mouse(target); |
218 | mouse.onmousebutton = sinon.spy(); | |
28b004fd SM |
219 | |
220 | mouse._handleMouseWheel(mouseevent( | |
221 | 'mousewheel', { clientX: 18, clientY: 40, | |
222 | deltaX: 4, deltaY: 0, deltaMode: 0 })); | |
223 | this.clock.tick(10); | |
224 | mouse._handleMouseWheel(mouseevent( | |
225 | 'mousewheel', { clientX: 18, clientY: 40, | |
226 | deltaX: 4, deltaY: 0, deltaMode: 0 })); | |
227 | ||
228 | // threshold is 10 | |
229 | expect(mouse._accumulatedWheelDeltaX).to.be.equal(8); | |
230 | ||
231 | this.clock.tick(10); | |
232 | mouse._handleMouseWheel(mouseevent( | |
233 | 'mousewheel', { clientX: 18, clientY: 40, | |
234 | deltaX: 4, deltaY: 0, deltaMode: 0 })); | |
235 | ||
747b4623 | 236 | expect(mouse.onmousebutton).to.have.callCount(2); // mouse down and up |
28b004fd SM |
237 | |
238 | this.clock.tick(10); | |
239 | mouse._handleMouseWheel(mouseevent( | |
240 | 'mousewheel', { clientX: 18, clientY: 40, | |
241 | deltaX: 4, deltaY: 9, deltaMode: 0 })); | |
242 | ||
243 | expect(mouse._accumulatedWheelDeltaX).to.be.equal(4); | |
244 | expect(mouse._accumulatedWheelDeltaY).to.be.equal(9); | |
245 | ||
747b4623 | 246 | expect(mouse.onmousebutton).to.have.callCount(2); // still |
28b004fd SM |
247 | }); |
248 | ||
249 | it('should not accumulate large wheel events', function () { | |
747b4623 PO |
250 | var mouse = new Mouse(target); |
251 | mouse.onmousebutton = sinon.spy(); | |
28b004fd SM |
252 | |
253 | mouse._handleMouseWheel(mouseevent( | |
254 | 'mousewheel', { clientX: 18, clientY: 40, | |
255 | deltaX: 11, deltaY: 0, deltaMode: 0 })); | |
256 | this.clock.tick(10); | |
257 | mouse._handleMouseWheel(mouseevent( | |
258 | 'mousewheel', { clientX: 18, clientY: 40, | |
259 | deltaX: 0, deltaY: 70, deltaMode: 0 })); | |
260 | this.clock.tick(10); | |
261 | mouse._handleMouseWheel(mouseevent( | |
262 | 'mousewheel', { clientX: 18, clientY: 40, | |
263 | deltaX: 400, deltaY: 400, deltaMode: 0 })); | |
264 | ||
747b4623 | 265 | expect(mouse.onmousebutton).to.have.callCount(8); // mouse down and up |
28b004fd SM |
266 | }); |
267 | ||
268 | it('should send even small wheel events after a timeout', function () { | |
747b4623 PO |
269 | var mouse = new Mouse(target); |
270 | mouse.onmousebutton = sinon.spy(); | |
28b004fd SM |
271 | |
272 | mouse._handleMouseWheel(mouseevent( | |
273 | 'mousewheel', { clientX: 18, clientY: 40, | |
274 | deltaX: 1, deltaY: 0, deltaMode: 0 })); | |
275 | this.clock.tick(51); // timeout on 50 ms | |
276 | ||
747b4623 | 277 | expect(mouse.onmousebutton).to.have.callCount(2); // mouse down and up |
28b004fd SM |
278 | }); |
279 | ||
280 | it('should account for non-zero deltaMode', function () { | |
747b4623 PO |
281 | var mouse = new Mouse(target); |
282 | mouse.onmousebutton = sinon.spy(); | |
28b004fd SM |
283 | |
284 | mouse._handleMouseWheel(mouseevent( | |
285 | 'mousewheel', { clientX: 18, clientY: 40, | |
286 | deltaX: 0, deltaY: 2, deltaMode: 1 })); | |
287 | ||
288 | this.clock.tick(10); | |
289 | ||
290 | mouse._handleMouseWheel(mouseevent( | |
291 | 'mousewheel', { clientX: 18, clientY: 40, | |
292 | deltaX: 1, deltaY: 0, deltaMode: 2 })); | |
293 | ||
747b4623 | 294 | expect(mouse.onmousebutton).to.have.callCount(4); // mouse down and up |
28b004fd SM |
295 | }); |
296 | }); | |
297 | ||
c509e6d9 | 298 | }); |