comparison mde/input/Input.d @ 99:5de5810e3516

Implemented an editable TextContent widget; it's now possible to edit text options using the GUI. The widget supports moving the text entry-point using arrows and home/end, but there's no visual indicator or edit-point setting using the mouse.
author Diggory Hardy <diggory.hardy@gmail.com>
date Fri, 14 Nov 2008 12:44:32 +0000
parents 97e6dce08037
children 20f7d813bb0f
comparison
equal deleted inserted replaced
98:49e7cfed4b34 99:5de5810e3516
23 import mde.input.Config; 23 import mde.input.Config;
24 import mde.input.exception; 24 import mde.input.exception;
25 25
26 // sdl imports 26 // sdl imports
27 import derelict.sdl.events; 27 import derelict.sdl.events;
28 import derelict.sdl.keyboard;
28 import derelict.sdl.types; // only SDL_PRESSED 29 import derelict.sdl.types; // only SDL_PRESSED
29 import derelict.sdl.joystick; // SDL_HAT_* 30 import derelict.sdl.joystick; // SDL_HAT_*
30 31
32 import Utf = tango.text.convert.Utf;
31 import tango.util.log.Log : Log, Logger; 33 import tango.util.log.Log : Log, Logger;
32 34
33 /** Class encapsulating all input functionality. 35 /**************************************************************************************************
36 * Class encapsulating all input functionality.
34 * 37 *
35 * The following methods are provided for Gui mouse input: 38 * This class has several modes which affect output: interaction mode (default), text input mode,
39 * mouse gui mode and axis/button binding modes.
40 *
41 * TODO: Gui mode and button capture and axis capture modes for key binding, disabling all
42 * other modes (except gui-type mouse info?).
43 * TODO: Possible revisions: remove by-index lookup, only providing callbacks?
44 * TODO: Make callbacks send the time of the event?
45 * TODO: Adjusters, e.g. double-press, hold/click differences. Axis output: via short or double?
46 * TODO: add an Axis1Callback similar to getAxis1? Or remove getAxis1 and provide a conversion function?
47 * TODO: allow callbacks to be removed. Currently not needed.
48 * TODO: modifiers in text-input mode: shortcut handling? Global shortcuts - either mode?
49 *
50 * The primary mode is the interaction mode, mapping each button and axis to a configurable index,
51 * and allowing event callback functions to be bound per index as well as allowing the state to be
52 * looked up directly.
53 * ---
54 * // For keyboard, joystick and mouse button input
55 * bool getButton (inputID id);
56 * void addButtonCallback (inputID id, ButtonCallback dg); // callback receives both up and down events
57 *
58 * // For joystick axis input
59 * short getAxis (inputID id); // range: -32767 .. 32767
60 * double getAxis1 (inputID id); // range: -1.0 .. 1.0
61 * void addAxisCallback (inputID id, AxisCallback dg);
62 *
63 * // For mouse (and joystick ball) relative motion input
64 * void getRelMotion (inputID id, out double x, out double y);
65 * void addRelMotionCallback (inputID id, RelMotionCallback dg);
66 * ---
67 *
68 * The keyboard can be put in text input mode, disabling interaction-mode keyboard access and
69 * providing a callback called on each letter press with it's UTF-8 code. Setting a LetterCallback
70 * activates text input mode and removing it disables this mode; only one may be active at once.
71 * ---
72 * void setLetterCallback (LetterCallback dg);
73 * ---
74 *
75 * Mouse input can be recieved via gui-oriented click/coordinate callbacks in both interaction
76 * mode and gui mode, however interaction-mode button and relative motion input is not received in
77 * gui mode.
36 * --- 78 * ---
37 * void getMouseScreenPos (out uint x, out uint y); 79 * void getMouseScreenPos (out uint x, out uint y);
38 * void addMouseClickCallback (MouseClickCallback dg); 80 * void addMouseClickCallback (MouseClickCallback dg);
39 * void addMouseMotionCallback (MouseMotionCallback dg); 81 * void addMouseMotionCallback (MouseMotionCallback dg);
40 * --- 82 * ---
41 * 83 *
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: 84 * The following methods are provided for setup & posting events:
62 * --- 85 * ---
63 * bool opCall (ref SDL_Event event); 86 * bool opCall (ref SDL_Event event); // Handles an event, making all the above work
64 * void frameReset (); 87 * void frameReset (); // Needs to be called once per frame for correct relative input
65 * void loadConfig (char[] profile = "Default"); 88 * void loadConfig (char[] profile = "Default"); // Configuration for interaction-mode indexes
66 * --- 89 * ---
67 ***************************************************/ 90 ***************************************************/
68 // FIXME: remove getMouseScreenPos (no use)?
69 // FIXME: add an Axis1Callback similar to getAxis1? Or remove getAxis1 and provide a conversion
70 // function?
71 class Input 91 class Input
72 { 92 {
73 /// Typedef for all indexes (type is uint). 93 /// Typedef for all indexes (type is uint).
74 typedef uint inputID; 94 typedef uint inputID;
75 alias void delegate(inputID, bool) ButtonCallback; 95 alias void delegate(inputID, bool) ButtonCallback;
76 alias void delegate(inputID, short) AxisCallback; 96 alias void delegate(inputID, short) AxisCallback;
77 alias void delegate(inputID, real,real) RelMotionCallback; 97 alias void delegate(inputID, double,double) RelMotionCallback;
78 alias void delegate(ushort, ushort, ubyte, bool) MouseClickCallback; 98 alias void delegate(ushort, ushort, ubyte, bool) MouseClickCallback;
79 alias void delegate(ushort, ushort) MouseMotionCallback; 99 alias void delegate(ushort, ushort) MouseMotionCallback;
100 alias void delegate(ushort, char[]) LetterCallback;
80 101
81 /** Get key status at this ID. 102 /** Get key status at this ID.
82 * 103 *
83 * Returns: value (true = down, false = up) or false if no value at this ID. */ 104 * Returns: value (true = down, false = up) or false if no value at this ID. */
84 bool getButton (inputID id) { 105 bool getButton (inputID id) {
95 if (retp) return *retp; 116 if (retp) return *retp;
96 else return 0; 117 else return 0;
97 } 118 }
98 /** Get axis status at this ID. 119 /** Get axis status at this ID.
99 * 120 *
100 * Returns: value (real; range roughly -1.0 .. 1.0) or 0 if no value at this ID. */ 121 * Returns: value (double; range roughly -1.0 .. 1.0) or 0 if no value at this ID. */
101 real getAxis1 (inputID id) { 122 double getAxis1 (inputID id) {
102 short* retp = id in axis; 123 short* retp = id in axis;
103 if (retp) return (*retp) * 3.0518509475997192e-05; 124 if (retp) return (*retp) * 3.0518509475997192e-05;
104 else return 0.0; 125 else return 0.0;
105 } 126 }
106 127
107 /** Get the relative motion of the mouse or a joystick ball (since last frameReset() call). 128 /** Get the relative motion of the mouse or a joystick ball (since last frameReset() call).
108 * 129 *
109 * Future: Converts to a real via sensitivity settings (defaults may be set and overriden per item). 130 * Future: Converts to a double via sensitivity settings (defaults may be set and overriden per item).
110 * 131 *
111 * To avoid confusion over the ID here, the idea is for the input-layer upward to support 132 * To avoid confusion over the ID here, the idea is for the input-layer upward to support
112 * multiple mice, in case future platforms do. 133 * multiple mice, in case future platforms do.
113 * Also joystick balls (supported by SDL) can be used in the same way as a mouse for relative 134 * Also joystick balls (supported by SDL) can be used in the same way as a mouse for relative
114 * positions. */ 135 * positions. */
115 void getRelMotion (inputID id, out real x = 0.0, out real y = 0.0) { 136 void getRelMotion (inputID id, out double x = 0.0, out double y = 0.0) {
116 RelPair* rp = id in relMotion; 137 RelPair* rp = id in relMotion;
117 if (rp) { 138 if (rp) {
118 x = rp.x; y = rp.y; 139 x = rp.x; y = rp.y;
119 } 140 }
120 } 141 }
121 /** Get mouse pointer position in screen coordinates.
122 *
123 * Window managers only support one mouse, so there will only be one screen coordinate.
124 * Unlike nearly everything else, this is not configurable.
125 *
126 * Also see addMouseMotionCallback. */
127 void getMouseScreenPos (out uint x, out uint y) {
128 x = mouse_x; y = mouse_y;
129 }
130 // /// Is this modifier on?
131 //bool modifierStatus (inputID id);
132 142
133 /** Adds a callback delegate for key events (both DOWN and UP) with this ID. 143 /** Adds a callback delegate for key events (both DOWN and UP) with this ID.
134 * 144 *
135 * Delegate receives event status. */ 145 * Delegate receives event status. */
136 void addButtonCallback (inputID id, ButtonCallback dg) { 146 void addButtonCallback (inputID id, ButtonCallback dg) {
173 * 183 *
174 * Really just for graphical user interfaces. Use addRelMotionCallback for relative motion (for 184 * Really just for graphical user interfaces. Use addRelMotionCallback for relative motion (for
175 * manipulating 3D views, etc.). */ 185 * manipulating 3D views, etc.). */
176 void addMouseMotionCallback (MouseMotionCallback dg) { 186 void addMouseMotionCallback (MouseMotionCallback dg) {
177 mouseMotionCallbacks ~= dg; 187 mouseMotionCallbacks ~= dg;
188 }
189
190 /** Sets a callback delegate to recieve key presses as a Utf-8 char[].
191 *
192 * Since it is normal to type into only one location at once, setting a new LetterCallback
193 * removes the last set one (however active ButtonCallbacks will still receive events).
194 * Supplying a null delegate will turn off the slight overhead of unicode conversion.
195 *
196 * The char[] received by the delegate must be copied and not stored or edited directly. */
197 void setLetterCallback (LetterCallback dg = null) {
198 if (dg) {
199 SDL_EnableUNICODE (1);
200 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
201 } else {
202 SDL_EnableUNICODE (0);
203 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
204 }
205 letterCallback = dg;
178 } 206 }
179 207
180 /** Feed an SDL_Event struct (only uses if it's a key, mouse or joystick event). 208 /** Feed an SDL_Event struct (only uses if it's a key, mouse or joystick event).
181 * 209 *
182 * Other types of event functions may be added. Returns true if the event was used, false if not 210 * Other types of event functions may be added. Returns true if the event was used, false if not
205 logger.error (CB_EXC ~ e.msg); 233 logger.error (CB_EXC ~ e.msg);
206 } 234 }
207 break; 235 break;
208 236
209 case SDL_MOUSEMOTION: 237 case SDL_MOUSEMOTION:
210 mouse_x = event.motion.x;
211 mouse_y = event.motion.y;
212
213 foreach (dg; mouseMotionCallbacks) { 238 foreach (dg; mouseMotionCallbacks) {
214 try 239 try
215 dg (event.motion.x, event.motion.y); 240 dg (event.motion.x, event.motion.y);
216 catch (Exception e) 241 catch (Exception e)
217 logger.error (CB_EXC ~ e.msg); 242 logger.error (CB_EXC ~ e.msg);
227 if (!config) return false; 252 if (!config) return false;
228 253
229 switch (event.type) { 254 switch (event.type) {
230 // Keyboard events: 255 // Keyboard events:
231 case SDL_KEYDOWN: 256 case SDL_KEYDOWN:
257 if (letterCallback)
258 letterCallback (event.key.keysym.sym, Utf.toString ([cast(wchar)event.key.keysym.unicode], cast(char[])utfBuf));
232 case SDL_KEYUP: 259 case SDL_KEYUP:
260 if (letterCallback) break; // text input mode; no keyboard input from mappings
233 outQueue[]* p = (Config.B.SDLKEY | event.key.keysym.sym) in config.button; 261 outQueue[]* p = (Config.B.SDLKEY | event.key.keysym.sym) in config.button;
234 if (p) foreach (outQueue q; *p) { 262 if (p) foreach (outQueue q; *p) {
235 bEvent (this, event.key.state == SDL_PRESSED, readOutQueue(q)); 263 bEvent (this, event.key.state == SDL_PRESSED, readOutQueue(q));
236 } 264 }
237 break; 265 break;
368 396
369 logger = Log.getLogger ("mde.input.Input"); 397 logger = Log.getLogger ("mde.input.Input");
370 } 398 }
371 399
372 struct RelPair { // for mouse/joystick ball motion 400 struct RelPair { // for mouse/joystick ball motion
373 real x, y; 401 double x, y;
374 static RelPair opCall (real a, real b) { 402 static RelPair opCall (double a, double b) {
375 RelPair ret; 403 RelPair ret;
376 ret.x = a; ret.y = b; 404 ret.x = a; ret.y = b;
377 return ret; 405 return ret;
378 } 406 }
379 } 407 }
380 408
381 static const CB_EXC = "Callback exception: "; 409 static const CB_EXC = "Callback exception: ";
382 410
383 static Logger logger; 411 static Logger logger;
384 412
385 Config config; // Configuration 413 Config config; // Configuration
386 414 char[6] utfBuf; // Buffer for Utf.toString; reallocates if less than 5.
387 bool[inputID] button; // Table of button states 415
388 short[inputID] axis; // Table of axes states 416 bool[inputID] button; // Table of button states
389 ushort mouse_x, mouse_y; // Current screen coords of the window manager mouse 417 short[inputID] axis; // Table of axes states
390 RelPair[inputID] relMotion; // Table of relative mouse / joystick ball motions 418 RelPair[inputID] relMotion; // Table of relative mouse / joystick ball motions
391 419
392 // NOTE: currently no means of removal 420 // NOTE: currently no means of removal
393 ButtonCallback[][inputID] buttonCallbacks; 421 ButtonCallback[][inputID] buttonCallbacks;
394 AxisCallback[][inputID] axisCallbacks; 422 AxisCallback[][inputID] axisCallbacks;
395 RelMotionCallback[][inputID] relMotionCallbacks; 423 RelMotionCallback[][inputID] relMotionCallbacks;
396 MouseClickCallback[] mouseClickCallbacks; 424 MouseClickCallback[] mouseClickCallbacks;
397 MouseMotionCallback[] mouseMotionCallbacks; 425 MouseMotionCallback[] mouseMotionCallbacks;
398 426 LetterCallback letterCallback;
427
399 //BEGIN Event stream functionality 428 //BEGIN Event stream functionality
400 /* This section contains functions called on an event, which may modify the event (adjuster 429 /* This section contains functions called on an event, which may modify the event (adjuster
401 * functions), and finally output to one (or more) of the state tables (the event stream). 430 * functions), and finally output to one (or more) of the state tables (the event stream).
402 * 431 *
403 * Adjuster and other event functions should have a format to fit the ES_X_Func types, for X is 432 * Adjuster and other event functions should have a format to fit the ES_X_Func types, for X is
576 }); 605 });
577 ut.addAxisCallback (0x22F0, delegate void(inputID id, short x) { 606 ut.addAxisCallback (0x22F0, delegate void(inputID id, short x) {
578 assert (x == (counters[3] ? 0 : 32767)); 607 assert (x == (counters[3] ? 0 : 32767));
579 counters[3] += 1; 608 counters[3] += 1;
580 }); 609 });
581 ut.addRelMotionCallback (0x11F0, delegate void(inputID id, real x, real y) { 610 ut.addRelMotionCallback (0x11F0, delegate void(inputID id, double x, double y) {
582 assert (x == 14.0); 611 assert (x == 14.0);
583 assert (y == -1.0); 612 assert (y == -1.0);
584 counters[4] += 1; 613 counters[4] += 1;
585 }); 614 });
586 ut.addMouseClickCallback (delegate void(ushort x, ushort y, ubyte b, bool s) { 615 ut.addMouseClickCallback (delegate void(ushort x, ushort y, ubyte b, bool s) {
658 687
659 assert (ut.getAxis(0x20F0) == 32767); 688 assert (ut.getAxis(0x20F0) == 32767);
660 assert (ut.getAxis(0x21F0) == -32767); 689 assert (ut.getAxis(0x21F0) == -32767);
661 assert (ut.getAxis1(0x22F0) == 0.0); 690 assert (ut.getAxis1(0x22F0) == 0.0);
662 691
663 real s,t; 692 double s,t;
664 ut.getRelMotion(0x10F0, s,t); 693 ut.getRelMotion(0x10F0, s,t);
665 assert (s == 14.0); 694 assert (s == 14.0);
666 assert (t == -1.0); 695 assert (t == -1.0);
667 ut.getRelMotion(0x12F0, s,t); 696 ut.getRelMotion(0x12F0, s,t);
668 assert (s == -21.0); 697 assert (s == -21.0);