Mercurial > projects > mde
comparison mde/input/Input.d @ 32:316b0230a849
Lots more work on the GUI. Also renamed lots of files.
Lots of changes to the GUI. Renderer is now used exclusively for rendering and WidgetDecoration is gone.
Renamed lots of files to conform to case policies.
committer: Diggory Hardy <diggory.hardy@gmail.com>
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Wed, 30 Apr 2008 18:05:56 +0100 |
parents | |
children | 6b4116e6355c |
comparison
equal
deleted
inserted
replaced
31:baa87e68d7dc | 32:316b0230a849 |
---|---|
1 /* LICENSE BLOCK | |
2 Part of mde: a Modular D game-oriented Engine | |
3 Copyright © 2007-2008 Diggory Hardy | |
4 | |
5 This program is free software: you can redistribute it and/or modify it under the terms | |
6 of the GNU General Public License as published by the Free Software Foundation, either | |
7 version 2 of the License, or (at your option) any later version. | |
8 | |
9 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; | |
10 without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
11 See the GNU General Public License for more details. | |
12 | |
13 You should have received a copy of the GNU General Public License | |
14 along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
15 | |
16 /** | |
17 * This module contains the interface to the input system; it should be the only module of the | |
18 * input package imported from outside this package. | |
19 */ | |
20 module mde.input.Input; | |
21 | |
22 // package imports | |
23 import mde.input.Config; | |
24 import mde.input.exception; | |
25 | |
26 // sdl imports | |
27 import derelict.sdl.events; | |
28 import derelict.sdl.types; // only SDL_PRESSED | |
29 import derelict.sdl.joystick; // SDL_HAT_* | |
30 | |
31 import tango.util.log.Log : Log, Logger; | |
32 | |
33 /// Class encapsulating all input functionality. | |
34 class Input | |
35 { | |
36 /// Typedef for all indexes (type is uint). | |
37 typedef uint inputID; | |
38 alias void delegate(inputID, bool) ButtonCallback; | |
39 alias void delegate(inputID, short) AxisCallback; | |
40 alias void delegate(inputID, real,real) RelMotionCallback; | |
41 alias void delegate(ushort, ushort, ubyte, bool) MouseClickCallback; | |
42 | |
43 /** Get key status at this ID. | |
44 * | |
45 * Returns: value (true = down, false = up) or false if no value at this ID. */ | |
46 bool getButton (inputID id) { | |
47 bool* retp = id in button; | |
48 if (retp) return *retp; | |
49 else return false; | |
50 } | |
51 | |
52 /** Get axis status at this ID. | |
53 * | |
54 * Returns: value (short; range -32767 .. 32767) or 0 if no value at this ID. */ | |
55 short getAxis (inputID id) { | |
56 short* retp = id in axis; | |
57 if (retp) return *retp; | |
58 else return 0; | |
59 } | |
60 /** Get axis status at this ID. | |
61 * | |
62 * Returns: value (real; range roughly -1.0 .. 1.0) or 0 if no value at this ID. */ | |
63 real getAxis1 (inputID id) { | |
64 short* retp = id in axis; | |
65 if (retp) return (*retp) * 3.0518509475997192e-05; | |
66 else return 0.0; | |
67 } | |
68 | |
69 /** Get the relative motion of the mouse or a joystick ball (since last frameReset() call). | |
70 * | |
71 * Future: Converts to a real via sensitivity settings (defaults may be set and overriden per item). | |
72 * | |
73 * To avoid confusion over the ID here, the idea is for the input-layer upward to support | |
74 * multiple mice, in case future platforms do. | |
75 * Also joystick balls (supported by SDL) can be used in the same way as a mouse for relative | |
76 * positions. | |
77 */ | |
78 void getRelMotion (inputID id, out real x = 0.0, out real y = 0.0) { | |
79 RelPair* rp = id in relMotion; | |
80 if (rp) { | |
81 x = rp.x; y = rp.y; | |
82 } | |
83 } | |
84 /** Get mouse pointer position in screen coordinates. | |
85 * | |
86 * Window managers only support one mouse, so there will only be one screen coordinate. | |
87 * Unlike nearly everything else, this is not configurable. | |
88 */ | |
89 void getMouseScreenPos (out uint x, out uint y) { | |
90 x = mouse_x; y = mouse_y; | |
91 } | |
92 // /// Is this modifier on? | |
93 //bool modifierStatus (inputID id); | |
94 | |
95 /** Adds a callback delegate for key events (both DOWN and UP) with this ID. | |
96 * | |
97 * Delegate receives event status. | |
98 */ | |
99 void addButtonCallback (inputID id, ButtonCallback dg) { | |
100 buttonCallbacks[id] ~= dg; | |
101 } | |
102 | |
103 /** Adds a callback delegate for axis events with this ID. | |
104 * | |
105 * Delegate receives event status (as per what getAxis returns). | |
106 */ | |
107 void addAxisCallback (inputID id, AxisCallback dg) { | |
108 axisCallbacks[id] ~= dg; | |
109 } | |
110 | |
111 /** Adds a callback delegate for mouse motion/joystick ball events with this ID. | |
112 * | |
113 * Delegate receives event status. As the name suggests, this is relative motion not screen | |
114 * position, with sensitivity adjustments applied. | |
115 * | |
116 * (A separate callback for mouse screen position changes is not | |
117 * necessary since this will be triggered by the same event - use mouseScreenPos from within the | |
118 * function to get new screen coordinates.) | |
119 */ | |
120 void addRelMotionCallback (inputID id, RelMotionCallback dg) { | |
121 relMotionCallbacks[id] ~= dg; | |
122 } | |
123 | |
124 /** Adds a callback delegate for all mouse clicks & releases. | |
125 * | |
126 * Delegate recieves x,y screen position (at time of click/release), button index (1 for left, | |
127 * 2 for middle, 3 for right, 4/5 for wheel, etc.), and whether the button was pressed or | |
128 * released (true if pressed). | |
129 * | |
130 * The point of this over a standard button callback is firstly to avoid mouse configuration for | |
131 * the GUI, and secondly to give the pointer position at the time of the event, not the time the | |
132 * callback gets called. | |
133 */ | |
134 void addMouseClickCallback (MouseClickCallback dg) { | |
135 mouseClickCallbacks ~= dg; | |
136 } | |
137 | |
138 /** Feed an SDL_Event struct (only uses if it's a key, mouse or joystick event). | |
139 * | |
140 * Other types of event functions may be added. Returns true if the event was used, false if not | |
141 * or no config was available. Hmm... doesn't seem very useful, but has practically no cost. | |
142 * | |
143 * May throw InputClassExceptions (on configuration errors). Catching the exception and continuing should | |
144 * be fine. | |
145 */ | |
146 bool opCall (ref SDL_Event event) { | |
147 /* Non-config events. | |
148 * | |
149 * Mouse events don't need config for the GUI. Handle them first so that if no config exists | |
150 * some functionality at least is retained. | |
151 * | |
152 * Note that the mouse coordinates as reported by SDL put the top-left most pixel at 1,1. | |
153 * Internal coordinates put that pixel at 0,0 (see gui/GUI notes.txt). | |
154 */ | |
155 switch (event.type) { | |
156 case SDL_MOUSEBUTTONDOWN: | |
157 case SDL_MOUSEBUTTONUP: | |
158 foreach (dg; mouseClickCallbacks) | |
159 dg (event.button.x - 1, event.button.y - 1, | |
160 event.button.button, event.button.state == SDL_PRESSED); | |
161 break; | |
162 | |
163 case SDL_MOUSEMOTION: | |
164 mouse_x = event.motion.x - 1; | |
165 mouse_y = event.motion.y - 1; | |
166 break; | |
167 | |
168 default: | |
169 } | |
170 | |
171 /* No config available, so don't try to access it and segfault. | |
172 * Don't log a message because this function is called per-event (i.e. frequently). | |
173 * A message should already have been logged by loadConfig anyway. | |
174 */ | |
175 if (!config) return false; | |
176 | |
177 switch (event.type) { | |
178 // Keyboard events: | |
179 case SDL_KEYDOWN: | |
180 case SDL_KEYUP: | |
181 outQueue[]* p = (Config.B.SDLKEY | event.key.keysym.sym) in config.button; | |
182 if (p) foreach (outQueue q; *p) { | |
183 bEvent (this, event.key.state == SDL_PRESSED, readOutQueue(q)); | |
184 } | |
185 break; | |
186 | |
187 // Mouse events: | |
188 case SDL_MOUSEBUTTONDOWN: | |
189 case SDL_MOUSEBUTTONUP: | |
190 // Button events: | |
191 outQueue[]* p = (Config.B.MOUSE | event.button.button) in config.button; | |
192 if (p) foreach (outQueue q; *p) { | |
193 bEvent (this, event.button.state == SDL_PRESSED, readOutQueue(q)); | |
194 } | |
195 break; | |
196 | |
197 case SDL_MOUSEMOTION: | |
198 // Relative motion: | |
199 outQueue[]* p = (Config.M.WMMOUSE) in config.relMotion; | |
200 if (p) foreach (outQueue q; *p) { | |
201 mEvent (this, event.motion.xrel, event.motion.yrel, readOutQueue(q)); | |
202 } | |
203 break; | |
204 | |
205 // Joystick events: | |
206 case SDL_JOYBUTTONDOWN: | |
207 case SDL_JOYBUTTONUP: | |
208 outQueue[]* p = (Config.B.JOYBUTTON | (event.jbutton.which << 12) | event.jbutton.button) in config.button; | |
209 if (p) foreach (outQueue q; *p) { | |
210 bEvent (this, event.jbutton.state == SDL_PRESSED, readOutQueue(q)); | |
211 } | |
212 break; | |
213 | |
214 case SDL_JOYAXISMOTION: | |
215 outQueue[]* p = (Config.A.JOYAXIS | (event.jaxis.which << 12) | event.jaxis.axis) in config.axis; | |
216 if (p) foreach (outQueue q; *p) { | |
217 aEvent (this, event.jaxis.value, readOutQueue(q)); | |
218 } | |
219 break; | |
220 | |
221 case SDL_JOYBALLMOTION: | |
222 outQueue[]* p = (Config.M.JOYBALL | (event.jball.which << 12) | event.jball.ball) in config.relMotion; | |
223 if (p) foreach (outQueue q; *p) { | |
224 mEvent (this, event.jball.xrel, event.jball.yrel, readOutQueue(q)); | |
225 } | |
226 break; | |
227 | |
228 case SDL_JOYHATMOTION: | |
229 static ubyte[uint] oldJHatVals; // necessary to store this to know which "axis" changed | |
230 | |
231 uint index = (event.jhat.which << 12) | event.jhat.hat; | |
232 ubyte* oVal_p = index in oldJHatVals; | |
233 ubyte oldJHatVal = (oVal_p) ? *oVal_p : SDL_HAT_CENTERED; | |
234 | |
235 // Carry out functionality for an axis. | |
236 void hatExamine (ubyte neg, ubyte pos, Config.B neg_b, Config.B pos_b, Config.A axis) { | |
237 // Check if there's any change on this axis (if not, nothing to do): | |
238 ubyte filter = neg | pos; | |
239 if ((oldJHatVal & filter) != (event.jhat.value & filter)) { | |
240 // Now we know this axis changed position, so can unset old value and set | |
241 // new value (if not centre). | |
242 | |
243 // Cancel old button status: | |
244 if (oldJHatVal & neg) { | |
245 outQueue[]* p = (neg_b | index) in config.button; | |
246 if (p) foreach (outQueue q; *p) bEvent (this, false, readOutQueue(q)); | |
247 } else if (oldJHatVal & pos) { | |
248 outQueue[]* p = (pos_b | index) in config.button; | |
249 if (p) foreach (outQueue q; *p) bEvent (this, false, readOutQueue(q)); | |
250 } | |
251 | |
252 // Set new button status and position: | |
253 short position = 0; | |
254 if (event.jhat.value & neg) { | |
255 position = -32767; | |
256 outQueue[]* p = (neg_b | index) in config.button; | |
257 if (p) foreach (outQueue q; *p) bEvent (this, true, readOutQueue(q)); | |
258 } else if (event.jhat.value & pos) { | |
259 position = 32767; | |
260 outQueue[]* p = (pos_b | index) in config.button; | |
261 if (p) foreach (outQueue q; *p) bEvent (this, true, readOutQueue(q)); | |
262 } | |
263 | |
264 // New axis event: | |
265 outQueue[]* p = (axis | index) in config.axis; | |
266 if (p) foreach (outQueue q; *p) aEvent (this, position, readOutQueue(q)); | |
267 } | |
268 } | |
269 | |
270 // Now run the code for each axis: | |
271 hatExamine (SDL_HAT_UP, SDL_HAT_DOWN, | |
272 Config.B.JOYHAT_U, Config.B.JOYHAT_D, Config.A.JOYHAT_UD); | |
273 hatExamine (SDL_HAT_LEFT, SDL_HAT_RIGHT, | |
274 Config.B.JOYHAT_L, Config.B.JOYHAT_R, Config.A.JOYHAT_LR); | |
275 | |
276 oldJHatVals[index] = event.jhat.value; | |
277 break; | |
278 | |
279 // Other events: | |
280 default: | |
281 return false; // event not used | |
282 } | |
283 return true; // event used | |
284 } | |
285 | |
286 /** Resets relative movement of mice / joystick balls to zero. | |
287 * | |
288 * Should be called once-per-frame if these are used, but must be called after their state has | |
289 * been read (e.g. just before updating the input). | |
290 */ | |
291 void frameReset () { | |
292 foreach (rp; relMotion) { | |
293 rp.x = rp.y = 0.0; | |
294 } | |
295 } | |
296 | |
297 /** Loads all configs, activating the requested id. | |
298 * | |
299 * Throws: ConfigLoadException if unable to load any configs or the requested config id wasn't | |
300 * found. | |
301 */ | |
302 void loadConfig (char[] profile = "Default") { | |
303 Config.load("input"); // FIXME: filename | |
304 Config* c_p = profile in Config.configs; | |
305 if (c_p) config = *c_p; | |
306 else { | |
307 throw new ConfigLoadException; | |
308 logger.error ("Config profile \""~profile~"\" not found: input won't work unless a valid profile is loaded!"); | |
309 } | |
310 } | |
311 | |
312 private: | |
313 // Static constructor for event stream (fills es_*_fcts tables). | |
314 static this () { | |
315 es_b_fcts = [ ES_B.OUT : &es_b_out ]; | |
316 es_a_fcts = [ ES_A.OUT : &es_a_out, ES_A.REVERSE : &es_a_reverse ]; | |
317 es_m_fcts = [ ES_M.OUT : &es_m_out ]; | |
318 | |
319 logger = Log.getLogger ("mde.input.input.Input"); | |
320 } | |
321 | |
322 struct RelPair { // for mouse/joystick ball motion | |
323 real x, y; | |
324 static RelPair opCall (real a, real b) { | |
325 RelPair ret; | |
326 ret.x = a; ret.y = b; | |
327 return ret; | |
328 } | |
329 } | |
330 | |
331 static Logger logger; | |
332 | |
333 Config config; // Configuration | |
334 | |
335 bool[inputID] button; // Table of button states | |
336 short[inputID] axis; // Table of axes states | |
337 ushort mouse_x, mouse_y; // Current screen coords of the window manager mouse | |
338 RelPair[inputID] relMotion; // Table of relative mouse / joystick ball motions | |
339 | |
340 // FIXME: currently no means of removal | |
341 ButtonCallback[][inputID] buttonCallbacks; | |
342 AxisCallback[][inputID] axisCallbacks; | |
343 RelMotionCallback[][inputID] relMotionCallbacks; | |
344 MouseClickCallback[] mouseClickCallbacks; | |
345 | |
346 //BEGIN Event stream functionality | |
347 /* This section contains functions called on an event, which may modify the event (adjuster | |
348 * functions), and finally output to one (or more) of the state tables (the event stream). | |
349 * | |
350 * Adjuster and other event functions should have a format to fit the ES_X_Func types, for X is B | |
351 * (button event), A (axis event) or M (mouse relative motion event or joystick ball event). | |
352 * Adjusters should call one of the xEvent() functions with their output and the remainder of | |
353 * the readOutQueue. | |
354 * | |
355 * To control which adjusters get called and pass parameters, a stack of sorts is used: outQueue. | |
356 */ | |
357 //BEGIN ES Definitions | |
358 /* Note: We really want an array, not a stack. We cannot edit the lists, so we can either | |
359 * copy to a stack or just iterate through it as an array. | |
360 */ | |
361 alias Config.outQueue outQueue; | |
362 struct readOutQueue { // A convenient structure for reading an outQueue item by item. | |
363 private Config.outQueue _q; // the queue, stored by reference to the original | |
364 private uint p = 0; // current read position (start at beginning) | |
365 | |
366 static readOutQueue opCall (Config.outQueue q) { // Static constructor | |
367 readOutQueue ret; | |
368 ret._q = q; | |
369 return ret; | |
370 } | |
371 uint pop () { // Get the next element and advance. Throws an exception if there isn't another. | |
372 if (p >= _q.length) | |
373 throw new InputClassException ("Input: Invalid configuration: incomplete config stack"); | |
374 uint ret = _q[p]; | |
375 ++p; | |
376 return ret; | |
377 } | |
378 debug uint next () { // Get the next element. No checks; for debug use only. | |
379 return _q[p]; | |
380 } | |
381 } | |
382 | |
383 // These aliases are for pointers to the event functions. | |
384 // These need to use "this", but cannot be delegates because they musn't be bound to a | |
385 // particular instance of Input, hence this must be passed when called. | |
386 alias void function (Input, bool, readOutQueue) ES_B_Func; | |
387 alias void function (Input, short, readOutQueue) ES_A_Func; | |
388 alias void function (Input, short, short, readOutQueue) ES_M_Func; | |
389 | |
390 /* These are the codes allowing the config to specify event functions. | |
391 * | |
392 * They are organised as defined in doc/input_ID_assignments. | |
393 */ | |
394 enum ES_B : uint { | |
395 OUT = 0x1000u, | |
396 } | |
397 enum ES_A : uint { | |
398 OUT = 0x1000u, | |
399 REVERSE = 0x2000u, | |
400 } | |
401 enum ES_M : uint { | |
402 OUT = 0x1000u, | |
403 } | |
404 //END ES Definitions | |
405 | |
406 // ES Data: | |
407 // These are the tables for looking up which event function to call. | |
408 static ES_B_Func[uint] es_b_fcts; | |
409 static ES_A_Func[uint] es_a_fcts; | |
410 static ES_M_Func[uint] es_m_fcts; | |
411 | |
412 //BEGIN ES Functions | |
413 // These 3 functions pass an event to the appropriate event function (adjuster or output func). | |
414 // They are used to start and continue an event stream. | |
415 // They must be static to allow calling from event functions. | |
416 const EVCONF_ERR = "Invalid configuration: bad event function code"; | |
417 static void bEvent (Input myThis, bool b, readOutQueue s) | |
418 { | |
419 ES_B_Func* func = (s.pop() in es_b_fcts); | |
420 if (func != null) (*func)(myThis, b, s); | |
421 else throw new InputClassException (EVCONF_ERR); | |
422 } | |
423 static void aEvent (Input myThis, short x, readOutQueue s) | |
424 { | |
425 ES_A_Func* func = (s.pop() in es_a_fcts); | |
426 if (func != null) (*func)(myThis, x, s); | |
427 else throw new InputClassException (EVCONF_ERR); | |
428 } | |
429 // Only handles relative output since position-on-screen is not stored with an ID: | |
430 static void mEvent (Input myThis, short x, short y, readOutQueue s) | |
431 { | |
432 ES_M_Func* func = (s.pop() in es_m_fcts); | |
433 if (func != null) (*func)(myThis, x, y, s); | |
434 else throw new InputClassException (EVCONF_ERR); | |
435 } | |
436 | |
437 // The remaining functions are the stream functions, for adjusting and outputting an event. | |
438 // They need to work like non-static functions, but are called via a function pointer, hencne | |
439 // should be static with their first parameter being instead of this. | |
440 | |
441 // Simple output function | |
442 static void es_b_out (Input myThis, bool b, readOutQueue s) { | |
443 inputID id = cast(inputID) s.pop(); | |
444 | |
445 myThis.button[id] = b; | |
446 | |
447 ButtonCallback[]* cb_p = id in myThis.buttonCallbacks; | |
448 if (cb_p) foreach (cb; *cb_p) cb (id, b); | |
449 } | |
450 // Adjuster to check modifier keys | |
451 static void es_b_modifier (Input myThis, bool b, readOutQueue s); | |
452 | |
453 // Simple output function | |
454 static void es_a_out (Input myThis, short x, readOutQueue s) { | |
455 inputID id = cast(inputID) s.pop(); | |
456 | |
457 myThis.axis[id] = x; | |
458 | |
459 AxisCallback[]* cb_p = id in myThis.axisCallbacks; | |
460 if (cb_p) foreach (cb; *cb_p) cb (id, x); | |
461 } | |
462 | |
463 // Just reverses an axis's value | |
464 static void es_a_reverse (Input myThis, short x, readOutQueue s) { | |
465 aEvent (myThis, -x, s); | |
466 } | |
467 | |
468 // Simple output function | |
469 static void es_m_out (Input myThis, short x, short y, readOutQueue s) { | |
470 inputID id = cast(inputID) s.pop(); | |
471 | |
472 myThis.relMotion[id] = RelPair(x,y); | |
473 | |
474 RelMotionCallback[]* cb_p = id in myThis.relMotionCallbacks; | |
475 if (cb_p) foreach (cb; *cb_p) cb (id, x,y); | |
476 } | |
477 //END ES Functions | |
478 //END Event stream functionality | |
479 | |
480 | |
481 /* This unittest covers input.config.Config and input.input.Input for some events of all types. | |
482 * It is not bullet-proof, and does not cover the steam-functions other than the direct output | |
483 * ones (largely because these may get added at any time and tested via input tests). | |
484 * | |
485 * What it does test: | |
486 * Events of all types. | |
487 * Callbacks of all types. | |
488 * Status set from events for all types (button,axis,relMotion). | |
489 * | |
490 * It relies on config loaded from a file (dependant on where input bindings are loaded from; | |
491 * currently conf/input.mtt). | |
492 */ | |
493 debug (mdeUnitTest) unittest { | |
494 Input ut = new Input(); | |
495 ut.loadConfig ("UnitTest"); | |
496 | |
497 int[6] counters; // counters for callbacks | |
498 // Should become: [2,2,0,2,1,1] | |
499 | |
500 //BEGIN Set up some callbacks | |
501 ut.addButtonCallback (0x03F0, delegate void(inputID id, bool status) { | |
502 assert (status == !counters[0]); // true first call, false next | |
503 counters[0] += 1; | |
504 }); | |
505 ut.addButtonCallback (0x06F0, delegate void(inputID id, bool status) { | |
506 assert (status == !counters[1]); // true first call, false next | |
507 counters[1] += 1; | |
508 }); | |
509 ut.addButtonCallback (0x07F0, delegate void(inputID id, bool status) { | |
510 counters[2] += 1; | |
511 }); | |
512 ut.addAxisCallback (0x22F0, delegate void(inputID id, short x) { | |
513 assert (x == (counters[3] ? 0 : 32767)); | |
514 counters[3] += 1; | |
515 }); | |
516 ut.addRelMotionCallback (0x11F0, delegate void(inputID id, real x, real y) { | |
517 assert (x == 14.0); | |
518 assert (y == -1.0); | |
519 counters[4] += 1; | |
520 }); | |
521 ut.addMouseClickCallback (delegate void(ushort x, ushort y, ubyte b, bool s) { | |
522 assert (x == 291); | |
523 assert (y == 10010); | |
524 assert (b == 3); | |
525 assert (s == false); | |
526 counters[5] += 1; | |
527 }); | |
528 //END Set up some callbacks | |
529 | |
530 //BEGIN Post a lot of events | |
531 SDL_Event e; | |
532 | |
533 // F11 down: | |
534 e.type = SDL_KEYDOWN; | |
535 e.key.state = SDL_PRESSED; | |
536 e.key.keysym.sym = 292; // SDLK_F11 | |
537 ut(e); | |
538 // Right mouse button up: | |
539 e.type = SDL_MOUSEBUTTONUP; | |
540 e.button.button = 3; // SDL_BUTTON_RIGHT | |
541 e.button.state = SDL_RELEASED; | |
542 e.button.x = 291; | |
543 e.button.y = 10010; | |
544 ut(e); | |
545 // Mouse motion: | |
546 e.type = SDL_MOUSEMOTION; | |
547 e.motion.x = 63; | |
548 e.motion.y = 44; | |
549 e.motion.xrel = 14; | |
550 e.motion.yrel = -1; | |
551 ut(e); | |
552 // Joystick 2 button 5 down: | |
553 e.type = SDL_JOYBUTTONDOWN; | |
554 e.jbutton.which = 2; | |
555 e.jbutton.button = 5; | |
556 e.jbutton.state = SDL_PRESSED; | |
557 ut(e); | |
558 // Same button released: | |
559 e.jbutton.state = SDL_RELEASED; | |
560 ut(e); | |
561 // Joystick 1 axis 8 motion: | |
562 e.type = SDL_JOYAXISMOTION; | |
563 e.jaxis.which = 1; | |
564 e.jaxis.axis = 8; | |
565 e.jaxis.value = 32767; | |
566 ut(e); | |
567 // Joystick 22 ball 100 motion: | |
568 e.type = SDL_JOYBALLMOTION; | |
569 e.jball.which = 22; | |
570 e.jball.ball = 100; | |
571 e.jball.xrel = -21; | |
572 e.jball.yrel = 1024; | |
573 ut(e); | |
574 // Joystick 214 hat 12 DOWN-RIGHT: | |
575 e.type = SDL_JOYHATMOTION; | |
576 e.jhat.which = 214; | |
577 e.jhat.hat = 12; | |
578 e.jhat.value = SDL_HAT_RIGHTDOWN; | |
579 ut(e); | |
580 // Same hat LEFT: | |
581 e.jhat.value = SDL_HAT_LEFT; | |
582 ut(e); | |
583 //END Post a lot of events | |
584 | |
585 //BEGIN Check states | |
586 assert (ut.getButton(0xF0) == true); | |
587 assert (ut.getButton(0x1F0) == false); | |
588 assert (ut.getButton(0x2F0) == false); | |
589 assert (ut.getButton(0x4F0) == false); | |
590 assert (ut.getButton(0x5F0) == true); | |
591 assert (ut.getButton(0x6F0) == false); | |
592 assert (ut.getButton(0x7F0) == false); | |
593 | |
594 assert (ut.getAxis(0x20F0) == 32767); | |
595 assert (ut.getAxis(0x21F0) == -32767); | |
596 assert (ut.getAxis1(0x22F0) == 0.0); | |
597 | |
598 real s,t; | |
599 ut.getRelMotion(0x10F0, s,t); | |
600 assert (s == 14.0); | |
601 assert (t == -1.0); | |
602 ut.getRelMotion(0x12F0, s,t); | |
603 assert (s == -21.0); | |
604 assert (t == 1024.0); | |
605 | |
606 assert (counters == [2,2,0,2,1,1]); | |
607 //END Check states | |
608 | |
609 logger.info ("Unittest complete."); | |
610 } | |
611 } |