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