Mercurial > projects > mde
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); |