comparison mde/input/Input.d @ 34:6b4116e6355c

Work on the Gui: some of the framework for drag & drop. Also made Window an IWidget. Implemented getWidget(x,y) to find the widget under this location for IWidgets (but not Gui). Made Window an IWidget and made it work a little more similarly to widgets. Implemented callbacks on the Gui for mouse events (enabling drag & drop, etc.). committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Fri, 02 May 2008 16:03:52 +0100
parents 316b0230a849
children 052df9b2fe07
comparison
equal deleted inserted replaced
33:6886402c1545 34:6b4116e6355c
28 import derelict.sdl.types; // only SDL_PRESSED 28 import derelict.sdl.types; // only SDL_PRESSED
29 import derelict.sdl.joystick; // SDL_HAT_* 29 import derelict.sdl.joystick; // SDL_HAT_*
30 30
31 import tango.util.log.Log : Log, Logger; 31 import tango.util.log.Log : Log, Logger;
32 32
33 /// Class encapsulating all input functionality. 33 /** Class encapsulating all input functionality.
34 *
35 * The following methods are provided for Gui mouse input:
36 * ---
37 * void getMouseScreenPos (out uint x, out uint y);
38 * void addMouseClickCallback (MouseClickCallback dg);
39 * void addMouseMotionCallback (MouseMotionCallback dg);
40 * ---
41 *
42 * The following methods are provided for mouse (and joystick ball) relative motion input:
43 * ---
44 * void getRelMotion (inputID id, out real x = 0.0, out real y = 0.0);
45 * void addRelMotionCallback (inputID id, RelMotionCallback dg);
46 * ---
47 *
48 * The following methods are provided for joystick axis input:
49 * ---
50 * short getAxis (inputID id);
51 * real getAxis1 (inputID id);
52 * void addAxisCallback (inputID id, AxisCallback dg);
53 * ---
54 *
55 * The following methods are provided for keyboard, joystick and mouse button input:
56 * ---
57 * bool getButton (inputID id);
58 * void addButtonCallback (inputID id, ButtonCallback dg)
59 * ---
60 *
61 * The following methods are provided for setup & posting events:
62 * ---
63 * bool opCall (ref SDL_Event event);
64 * void frameReset ();
65 * void loadConfig (char[] profile = "Default");
66 * ---
67 ***************************************************/
68 // FIXME: remove getMouseScreenPos (no use)?
69 // FIXME: add an Axis1Callback similar to getAxis1? Or remove getAxis1 and provide a conversion
70 // function?
34 class Input 71 class Input
35 { 72 {
36 /// Typedef for all indexes (type is uint). 73 /// Typedef for all indexes (type is uint).
37 typedef uint inputID; 74 typedef uint inputID;
38 alias void delegate(inputID, bool) ButtonCallback; 75 alias void delegate(inputID, bool) ButtonCallback;
39 alias void delegate(inputID, short) AxisCallback; 76 alias void delegate(inputID, short) AxisCallback;
40 alias void delegate(inputID, real,real) RelMotionCallback; 77 alias void delegate(inputID, real,real) RelMotionCallback;
41 alias void delegate(ushort, ushort, ubyte, bool) MouseClickCallback; 78 alias void delegate(ushort, ushort, ubyte, bool) MouseClickCallback;
79 alias void delegate(ushort, ushort) MouseMotionCallback;
42 80
43 /** Get key status at this ID. 81 /** Get key status at this ID.
44 * 82 *
45 * Returns: value (true = down, false = up) or false if no value at this ID. */ 83 * Returns: value (true = down, false = up) or false if no value at this ID. */
46 bool getButton (inputID id) { 84 bool getButton (inputID id) {
71 * Future: Converts to a real via sensitivity settings (defaults may be set and overriden per item). 109 * Future: Converts to a real via sensitivity settings (defaults may be set and overriden per item).
72 * 110 *
73 * To avoid confusion over the ID here, the idea is for the input-layer upward to support 111 * 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. 112 * 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 113 * Also joystick balls (supported by SDL) can be used in the same way as a mouse for relative
76 * positions. 114 * positions. */
77 */
78 void getRelMotion (inputID id, out real x = 0.0, out real y = 0.0) { 115 void getRelMotion (inputID id, out real x = 0.0, out real y = 0.0) {
79 RelPair* rp = id in relMotion; 116 RelPair* rp = id in relMotion;
80 if (rp) { 117 if (rp) {
81 x = rp.x; y = rp.y; 118 x = rp.x; y = rp.y;
82 } 119 }
83 } 120 }
84 /** Get mouse pointer position in screen coordinates. 121 /** Get mouse pointer position in screen coordinates.
85 * 122 *
86 * Window managers only support one mouse, so there will only be one screen coordinate. 123 * Window managers only support one mouse, so there will only be one screen coordinate.
87 * Unlike nearly everything else, this is not configurable. 124 * Unlike nearly everything else, this is not configurable.
88 */ 125 *
126 * Also see addMouseMotionCallback. */
89 void getMouseScreenPos (out uint x, out uint y) { 127 void getMouseScreenPos (out uint x, out uint y) {
90 x = mouse_x; y = mouse_y; 128 x = mouse_x; y = mouse_y;
91 } 129 }
92 // /// Is this modifier on? 130 // /// Is this modifier on?
93 //bool modifierStatus (inputID id); 131 //bool modifierStatus (inputID id);
94 132
95 /** Adds a callback delegate for key events (both DOWN and UP) with this ID. 133 /** Adds a callback delegate for key events (both DOWN and UP) with this ID.
96 * 134 *
97 * Delegate receives event status. 135 * Delegate receives event status. */
98 */
99 void addButtonCallback (inputID id, ButtonCallback dg) { 136 void addButtonCallback (inputID id, ButtonCallback dg) {
100 buttonCallbacks[id] ~= dg; 137 buttonCallbacks[id] ~= dg;
101 } 138 }
102 139
103 /** Adds a callback delegate for axis events with this ID. 140 /** Adds a callback delegate for axis events with this ID.
104 * 141 *
105 * Delegate receives event status (as per what getAxis returns). 142 * Delegate receives event status (as per what getAxis returns). */
106 */
107 void addAxisCallback (inputID id, AxisCallback dg) { 143 void addAxisCallback (inputID id, AxisCallback dg) {
108 axisCallbacks[id] ~= dg; 144 axisCallbacks[id] ~= dg;
109 } 145 }
110 146
111 /** Adds a callback delegate for mouse motion/joystick ball events with this ID. 147 /** Adds a callback delegate for mouse motion/joystick ball events with this ID.
113 * Delegate receives event status. As the name suggests, this is relative motion not screen 149 * Delegate receives event status. As the name suggests, this is relative motion not screen
114 * position, with sensitivity adjustments applied. 150 * position, with sensitivity adjustments applied.
115 * 151 *
116 * (A separate callback for mouse screen position changes is not 152 * (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 153 * necessary since this will be triggered by the same event - use mouseScreenPos from within the
118 * function to get new screen coordinates.) 154 * function to get new screen coordinates.) */
119 */
120 void addRelMotionCallback (inputID id, RelMotionCallback dg) { 155 void addRelMotionCallback (inputID id, RelMotionCallback dg) {
121 relMotionCallbacks[id] ~= dg; 156 relMotionCallbacks[id] ~= dg;
122 } 157 }
123 158
124 /** Adds a callback delegate for all mouse clicks & releases. 159 /** Adds a callback delegate for all mouse clicks & releases.
127 * 2 for middle, 3 for right, 4/5 for wheel, etc.), and whether the button was pressed or 162 * 2 for middle, 3 for right, 4/5 for wheel, etc.), and whether the button was pressed or
128 * released (true if pressed). 163 * released (true if pressed).
129 * 164 *
130 * The point of this over a standard button callback is firstly to avoid mouse configuration for 165 * 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 166 * the GUI, and secondly to give the pointer position at the time of the event, not the time the
132 * callback gets called. 167 * callback gets called. */
133 */
134 void addMouseClickCallback (MouseClickCallback dg) { 168 void addMouseClickCallback (MouseClickCallback dg) {
135 mouseClickCallbacks ~= dg; 169 mouseClickCallbacks ~= dg;
136 } 170 }
171
172 /** Adds a callback delegate for all mouse motion events.
173 *
174 * Really just for graphical user interfaces. Use addRelMotionCallback for relative motion (for
175 * manipulating 3D views, etc.). */
176 void addMouseMotionCallback (MouseMotionCallback dg) {
177 mouseMotionCallbacks ~= dg;
178 }
137 179
138 /** Feed an SDL_Event struct (only uses if it's a key, mouse or joystick event). 180 /** Feed an SDL_Event struct (only uses if it's a key, mouse or joystick event).
139 * 181 *
140 * Other types of event functions may be added. Returns true if the event was used, false if not 182 * 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. 183 * or no config was available. Hmm... doesn't seem very useful, but has practically no cost.
142 * 184 *
143 * May throw InputClassExceptions (on configuration errors). Catching the exception and continuing should 185 * May throw InputClassExceptions (on configuration errors). Catching the exception and continuing should
144 * be fine. 186 * be fine. */
145 */
146 bool opCall (ref SDL_Event event) { 187 bool opCall (ref SDL_Event event) {
147 /* Non-config events. 188 /* Non-config events.
148 * 189 *
149 * Mouse events don't need config for the GUI. Handle them first so that if no config exists 190 * 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. 191 * some functionality at least is retained.
161 break; 202 break;
162 203
163 case SDL_MOUSEMOTION: 204 case SDL_MOUSEMOTION:
164 mouse_x = event.motion.x - 1; 205 mouse_x = event.motion.x - 1;
165 mouse_y = event.motion.y - 1; 206 mouse_y = event.motion.y - 1;
207
208 foreach (dg; mouseMotionCallbacks)
209 dg (event.motion.x - 1, event.motion.y - 1);
166 break; 210 break;
167 211
168 default: 212 default:
169 } 213 }
170 214
171 /* No config available, so don't try to access it and segfault. 215 /* 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). 216 * 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. 217 * A message should already have been logged by loadConfig anyway. */
174 */
175 if (!config) return false; 218 if (!config) return false;
176 219
177 switch (event.type) { 220 switch (event.type) {
178 // Keyboard events: 221 // Keyboard events:
179 case SDL_KEYDOWN: 222 case SDL_KEYDOWN:
284 } 327 }
285 328
286 /** Resets relative movement of mice / joystick balls to zero. 329 /** Resets relative movement of mice / joystick balls to zero.
287 * 330 *
288 * Should be called once-per-frame if these are used, but must be called after their state has 331 * 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). 332 * been read (e.g. just before updating the input). */
290 */
291 void frameReset () { 333 void frameReset () {
292 foreach (rp; relMotion) { 334 foreach (rp; relMotion) {
293 rp.x = rp.y = 0.0; 335 rp.x = rp.y = 0.0;
294 } 336 }
295 } 337 }
296 338
297 /** Loads all configs, activating the requested id. 339 /** Loads all configs, activating the requested id.
298 * 340 *
299 * Throws: ConfigLoadException if unable to load any configs or the requested config id wasn't 341 * Throws: ConfigLoadException if unable to load any configs or the requested config id wasn't
300 * found. 342 * found. */
301 */
302 void loadConfig (char[] profile = "Default") { 343 void loadConfig (char[] profile = "Default") {
303 Config.load("input"); // FIXME: filename 344 Config.load("input"); // FIXME: filename
304 Config* c_p = profile in Config.configs; 345 Config* c_p = profile in Config.configs;
305 if (c_p) config = *c_p; 346 if (c_p) config = *c_p;
306 else { 347 else {
340 // FIXME: currently no means of removal 381 // FIXME: currently no means of removal
341 ButtonCallback[][inputID] buttonCallbacks; 382 ButtonCallback[][inputID] buttonCallbacks;
342 AxisCallback[][inputID] axisCallbacks; 383 AxisCallback[][inputID] axisCallbacks;
343 RelMotionCallback[][inputID] relMotionCallbacks; 384 RelMotionCallback[][inputID] relMotionCallbacks;
344 MouseClickCallback[] mouseClickCallbacks; 385 MouseClickCallback[] mouseClickCallbacks;
386 MouseMotionCallback[] mouseMotionCallbacks;
345 387
346 //BEGIN Event stream functionality 388 //BEGIN Event stream functionality
347 /* This section contains functions called on an event, which may modify the event (adjuster 389 /* 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). 390 * functions), and finally output to one (or more) of the state tables (the event stream).
349 * 391 *
350 * Adjuster and other event functions should have a format to fit the ES_X_Func types, for X is B 392 * Adjuster and other event functions should have a format to fit the ES_X_Func types, for X is
351 * (button event), A (axis event) or M (mouse relative motion event or joystick ball event). 393 * B (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 394 * Adjusters should call one of the xEvent() functions with their output and the remainder of
353 * the readOutQueue. 395 * the readOutQueue.
354 * 396 *
355 * To control which adjusters get called and pass parameters, a stack of sorts is used: outQueue. 397 * To control which adjusters get called and pass parameters, a stack of sorts is used:
356 */ 398 * outQueue. */
357 //BEGIN ES Definitions 399 //BEGIN ES Definitions
358 /* Note: We really want an array, not a stack. We cannot edit the lists, so we can either 400 /* 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. 401 * copy to a stack or just iterate through it as an array. */
360 */
361 alias Config.outQueue outQueue; 402 alias Config.outQueue outQueue;
362 struct readOutQueue { // A convenient structure for reading an outQueue item by item. 403 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 404 private Config.outQueue _q; // the queue, stored by reference to the original
364 private uint p = 0; // current read position (start at beginning) 405 private uint p = 0; // current read position (start at beginning)
365 406
387 alias void function (Input, short, readOutQueue) ES_A_Func; 428 alias void function (Input, short, readOutQueue) ES_A_Func;
388 alias void function (Input, short, short, readOutQueue) ES_M_Func; 429 alias void function (Input, short, short, readOutQueue) ES_M_Func;
389 430
390 /* These are the codes allowing the config to specify event functions. 431 /* These are the codes allowing the config to specify event functions.
391 * 432 *
392 * They are organised as defined in doc/input_ID_assignments. 433 * They are organised as defined in doc/input_ID_assignments. */
393 */
394 enum ES_B : uint { 434 enum ES_B : uint {
395 OUT = 0x1000u, 435 OUT = 0x1000u,
396 } 436 }
397 enum ES_A : uint { 437 enum ES_A : uint {
398 OUT = 0x1000u, 438 OUT = 0x1000u,
486 * Events of all types. 526 * Events of all types.
487 * Callbacks of all types. 527 * Callbacks of all types.
488 * Status set from events for all types (button,axis,relMotion). 528 * Status set from events for all types (button,axis,relMotion).
489 * 529 *
490 * It relies on config loaded from a file (dependant on where input bindings are loaded from; 530 * It relies on config loaded from a file (dependant on where input bindings are loaded from;
491 * currently conf/input.mtt). 531 * currently conf/input.mtt). */
492 */
493 debug (mdeUnitTest) unittest { 532 debug (mdeUnitTest) unittest {
494 Input ut = new Input(); 533 Input ut = new Input();
495 ut.loadConfig ("UnitTest"); 534 ut.loadConfig ("UnitTest");
496 535
497 int[6] counters; // counters for callbacks 536 int[6] counters; // counters for callbacks