Mercurial > projects > mde
comparison mde/input/input.d @ 9:1885a9080f2a
Joystick button input now works with config.
committer: Diggory Hardy <diggory.hardy@gmail.com>
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Wed, 30 Jan 2008 11:33:56 +0000 |
parents | f63f4f41a2dc |
children | 4c3575400769 |
comparison
equal
deleted
inserted
replaced
8:f63f4f41a2dc | 9:1885a9080f2a |
---|---|
11 // sdl imports | 11 // sdl imports |
12 import derelict.sdl.events; | 12 import derelict.sdl.events; |
13 | 13 |
14 import tango.util.log.Log : Log, Logger; | 14 import tango.util.log.Log : Log, Logger; |
15 | 15 |
16 Input input; /// Global instance of input. | 16 public Input input; /// Global instance of input. |
17 private Logger logger; | |
18 | |
19 static this() { | 17 static this() { |
20 input = new Input; | 18 input = new Input(); |
21 | |
22 logger = Log.getLogger ("mde.input.config"); | |
23 } | 19 } |
24 | 20 |
25 /// Class encapsulating all input functionality. | 21 /// Class encapsulating all input functionality. |
26 class Input | 22 class Input |
27 { | 23 { |
33 | 29 |
34 /** Get key status at this ID. | 30 /** Get key status at this ID. |
35 * | 31 * |
36 * Returns: value (true = down, false = up) or false if no value at this ID. */ | 32 * Returns: value (true = down, false = up) or false if no value at this ID. */ |
37 bool getButton (inputID id) { | 33 bool getButton (inputID id) { |
38 bool* retp = cast(inputID) id in button; | 34 assert (this is input); |
35 bool* retp = id in button; | |
39 if (retp) return *retp; | 36 if (retp) return *retp; |
40 else return false; | 37 else return false; |
41 } | 38 } |
42 /** Get axis status at this ID. | 39 /** Get axis status at this ID. |
43 * | 40 * |
44 * Returns: value (range -1.0 .. 1.0) or 0.0 if no value at this ID. */ | 41 * Returns: value (range -1.0 .. 1.0) or 0.0 if no value at this ID. */ |
45 real getAxis (inputID id) { | 42 real getAxis (inputID id) { |
46 real* retp = cast(inputID) id in axis; | 43 real* retp = id in axis; |
47 if (retp) return *retp; | 44 if (retp) return *retp; |
48 else return 0.0; | 45 else return 0.0; |
49 } | 46 } |
50 /** Get mouse pointer position in screen coordinates. | 47 /** Get mouse pointer position in screen coordinates. |
51 * | 48 * |
63 * multiple mice, in case future platforms do. | 60 * multiple mice, in case future platforms do. |
64 * Also joystick balls (supported by SDL) can be used in the same way as a mouse for relative | 61 * Also joystick balls (supported by SDL) can be used in the same way as a mouse for relative |
65 * positions. | 62 * positions. |
66 */ | 63 */ |
67 void mouseRelativePos (inputID id, out real x = 0.0, out real y = 0.0) { | 64 void mouseRelativePos (inputID id, out real x = 0.0, out real y = 0.0) { |
68 RelPair* rp = cast(inputID) id in axis_rel; | 65 RelPair* rp = id in axis_rel; |
69 if (rp) { | 66 if (rp) { |
70 x = rp.x; y = rp.y; | 67 x = rp.x; y = rp.y; |
71 } | 68 } |
72 } | 69 } |
73 // /// Is this modifier on? | 70 // /// Is this modifier on? |
102 /** Feed an SDL_Event struct (only uses if it's a key, mouse or joystick event). | 99 /** Feed an SDL_Event struct (only uses if it's a key, mouse or joystick event). |
103 * | 100 * |
104 * Other types of event functions may be added. Returns true if the event was used, false if not. | 101 * Other types of event functions may be added. Returns true if the event was used, false if not. |
105 */ | 102 */ |
106 bool opCall (ref SDL_Event event) { | 103 bool opCall (ref SDL_Event event) { |
104 assert (this is input); | |
107 switch (event.type) { | 105 switch (event.type) { |
108 case SDL_JOYBUTTONDOWN: | 106 case SDL_JOYBUTTONDOWN: |
109 case SDL_JOYBUTTONUP: | 107 case SDL_JOYBUTTONUP: |
110 debug { | |
111 char tmp[128] = void; | |
112 logger.trace (logger.format (tmp, "Got a joystick button event: ({}, {}) - {}", event.jbutton.which, event.jbutton.button, event.jbutton.state)); | |
113 } | |
114 outQueue* p = (Config.B.JOYBUTTON | (event.jbutton.which << 12) | event.jbutton.button) in config.button; | 108 outQueue* p = (Config.B.JOYBUTTON | (event.jbutton.which << 12) | event.jbutton.button) in config.button; |
115 if (p) bEventOut (event.jbutton.state == 0x1, readOutQueue(*p)); | 109 if (p) bEventOut (event.jbutton.state == 0x1, readOutQueue(*p)); |
116 break; | 110 break; |
117 | 111 |
118 /+ | 112 /+ |
119 case SDL_KEYDOWN: | 113 case SDL_KEYDOWN: |
120 case SDL_KEYUP: | 114 case SDL_KEYUP: |
121 outQueue* p = (Config.B.SDLKEY | event.key.keysym.sym) in config.button; | 115 outQueue* p = (Config.B.SDLKEY | event.key.keysym.sym) in config.button; |
122 if (p) eventstream.bEventOut (event.key.state == SDL_PRESSED, readOutQueue(*p)); | 116 if (p) eventstream.bEventOut (event.key.state == SDL_PRESSED, readOutQueue(*p)); |
152 Config.load("conf/input.mtt"); // FIXME: filename | 146 Config.load("conf/input.mtt"); // FIXME: filename |
153 Config* c_p = "Default" in Config.configs; | 147 Config* c_p = "Default" in Config.configs; |
154 if (c_p) { | 148 if (c_p) { |
155 config = *c_p; | 149 config = *c_p; |
156 return false; | 150 return false; |
157 debug logger.trace ("Succesfully loaded config."); | |
158 } | 151 } |
159 debug logger.warn ("Config \"Default\" not found."); | 152 debug logger.warn ("Config \"Default\" not found."); |
160 return true; | 153 return true; |
161 } | 154 } |
162 | 155 |
163 private: | 156 private: |
164 // Static constructor for event stream (fills es_*_fcts tables). | 157 // Static constructor for event stream (fills es_*_fcts tables). |
165 static this () { | 158 static this () { |
166 es_b_fcts = [ ES_B_OUT : &es_b_out ]; | 159 es_b_fcts = [ ES_B_OUT : &es_b_out ]; |
160 | |
161 logger = Log.getLogger ("mde.input.input.Input"); | |
167 } | 162 } |
168 | 163 |
169 struct RelPair { // for mouse/joystick ball motion | 164 struct RelPair { // for mouse/joystick ball motion |
170 real x, y; | 165 real x, y; |
171 static RelPair opCall (real a, real b) { | 166 static RelPair opCall (real a, real b) { |
173 ret.x = a; ret.y = b; | 168 ret.x = a; ret.y = b; |
174 return ret; | 169 return ret; |
175 } | 170 } |
176 } | 171 } |
177 | 172 |
173 static Logger logger; | |
174 | |
178 Config config; // Configuration | 175 Config config; // Configuration |
179 | 176 |
180 bool[inputID] button; // Table of button states | 177 bool[inputID] button; // Table of button states |
181 real[inputID] axis; // Table of axes states | 178 real[inputID] axis; // Table of axes states |
182 ushort mouse_x, mouse_y; // Current screen coords of the mouse | 179 ushort mouse_x, mouse_y; // Current screen coords of the mouse |
211 static readOutQueue opCall (Config.outQueue q) { // Static constructor | 208 static readOutQueue opCall (Config.outQueue q) { // Static constructor |
212 readOutQueue ret; | 209 readOutQueue ret; |
213 ret._q = q; | 210 ret._q = q; |
214 return ret; | 211 return ret; |
215 } | 212 } |
216 uint next () { // Get the next element. Throws an exception if there isn't another. | 213 uint pop () { // Get the next element and advance. Throws an exception if there isn't another. |
217 if (p >= _q.length) | 214 if (p >= _q.length) |
218 throw new InputClassException ("Input: Invalid configuration: incomplete config stack"); | 215 throw new InputClassException ("Input: Invalid configuration: incomplete config stack"); |
219 uint ret = _q[p]; | 216 uint ret = _q[p]; |
220 ++p; | 217 ++p; |
221 return ret; | 218 return ret; |
222 } | 219 } |
220 debug uint next () { // Get the next element. No checks; for debug use only. | |
221 return _q[p]; | |
222 } | |
223 } | 223 } |
224 | 224 |
225 // These aliases are for pointers to the event functions. | 225 // These aliases are for pointers to the event functions. |
226 alias void function (bool, readOutQueue) ES_B_Func; | 226 // These need to use "this", but cannot be delegates because they musn't be bound to a |
227 alias void function (short, readOutQueue) ES_A_Func; | 227 // particular instance of Input, hence this must be passed when called. |
228 alias void function (short, short, readOutQueue) ES_M_Func; | 228 alias void function (Input, bool, readOutQueue) ES_B_Func; |
229 alias void function (Input, short, readOutQueue) ES_A_Func; | |
230 alias void function (Input, short, short, readOutQueue) ES_M_Func; | |
229 | 231 |
230 // These are the codes allowing the config to specify event functions: | 232 // These are the codes allowing the config to specify event functions: |
231 enum : uint { | 233 enum : uint { |
232 ES_B_OUT = 0x0000_0100u, | 234 ES_B_OUT = 0x0000_0100u, |
233 ES_A_OUT = 0x0000_0200u, | 235 ES_A_OUT = 0x0000_0200u, |
242 static ES_M_Func[uint] es_m_fcts; | 244 static ES_M_Func[uint] es_m_fcts; |
243 | 245 |
244 //BEGIN ES Functions | 246 //BEGIN ES Functions |
245 // These 3 functions pass an event to the appropriate event function (adjuster or output func). | 247 // These 3 functions pass an event to the appropriate event function (adjuster or output func). |
246 // They are used to start and continue an event stream. | 248 // They are used to start and continue an event stream. |
249 const EVCONF_ERR = "Input: Invalid configuration: bad event function code"; | |
247 void bEventOut (bool b, readOutQueue s) | 250 void bEventOut (bool b, readOutQueue s) |
248 { | 251 { |
249 ES_B_Func* func = (s.next() in es_b_fcts); | 252 ES_B_Func* func = (s.pop() in es_b_fcts); |
250 if (func != null) (*func)(b,s); | 253 if (func != null) (*func)(this, b, s); |
251 else throw new InputClassException ("Input: Invalid configuration: bad event function code"); | 254 else throw new InputClassException (EVCONF_ERR); |
252 } | 255 } |
253 void aEventOut (short x, readOutQueue s) | 256 void aEventOut (short x, readOutQueue s) |
254 { | 257 { |
255 ES_A_Func* func = (s.next() in es_a_fcts); | 258 ES_A_Func* func = (s.pop() in es_a_fcts); |
256 if (func != null) (*func)(x,s); | 259 if (func != null) (*func)(this, x, s); |
257 else throw new InputClassException ("Input: Invalid configuration: bad event function code"); | 260 else throw new InputClassException (EVCONF_ERR); |
258 } | 261 } |
259 void mEventOut (short x, short y, readOutQueue s) | 262 void mEventOut (short x, short y, readOutQueue s) |
260 { | 263 { |
261 ES_M_Func* func = (s.next() in es_m_fcts); | 264 ES_M_Func* func = (s.pop() in es_m_fcts); |
262 if (func != null) (*func)(x,y,s); | 265 if (func != null) (*func)(this, x, y, s); |
263 else throw new InputClassException ("Input: Invalid configuration: bad event function code"); | 266 else throw new InputClassException (EVCONF_ERR); |
264 } | 267 } |
265 | 268 |
266 // The remaining functions are the stream functions, for adjusting and outputting an event. | 269 // The remaining functions are the stream functions, for adjusting and outputting an event. |
270 // They need to work like non-static functions, but are called via a function pointer, hencne | |
271 // should be static with their first parameter being instead of this. | |
267 | 272 |
268 // Simple output function | 273 // Simple output function |
269 void es_b_out (bool b, readOutQueue s) { | 274 static void es_b_out (Input myThis, bool b, readOutQueue s) { |
270 inputID id = cast(inputID) s.next(); | 275 inputID id = cast(inputID) s.pop(); |
271 button[id] = b; | 276 |
272 ButtonCallback* cb_p = id in buttonCallbacks; | 277 myThis.button[id] = b; |
278 | |
279 ButtonCallback* cb_p = id in myThis.buttonCallbacks; | |
273 if (cb_p) (*cb_p) (id, b); | 280 if (cb_p) (*cb_p) (id, b); |
274 } | 281 } |
275 // Adjuster to check modifier keys | 282 // Adjuster to check modifier keys |
276 void es_b_modifier (bool b, readOutQueue s); | 283 void es_b_modifier (Input myThis, bool b, readOutQueue s); |
277 | 284 |
278 /* Simple output function | 285 /* Simple output function |
279 | 286 |
280 Adds 1-2 items on the stack. | 287 Adds 1-2 items on the stack. |
281 */ | 288 */ |
282 void es_a_out (short x, readOutQueue s) { | 289 void es_a_out (Input myThis, short x, readOutQueue s) { |
283 real y = x; | 290 real y = x; |
284 uint conf = s.next(); | 291 uint conf = s.pop(); |
285 enum : uint { | 292 enum : uint { |
286 HALF_RANGE = 0x8000_0000u, | 293 HALF_RANGE = 0x8000_0000u, |
287 SENSITIVITY = 0x0080_0000u, | 294 SENSITIVITY = 0x0080_0000u, |
288 } | 295 } |
289 // Convert ranges into standard intervals (with or without reverse values) | 296 // Convert ranges into standard intervals (with or without reverse values) |
290 if (conf & HALF_RANGE) y = (y + 32767.0) * 1.5259254737998596e-05; // range 0.0 - 1.0 | 297 if (conf & HALF_RANGE) y = (y + 32767.0) * 1.5259254737998596e-05; // range 0.0 - 1.0 |
291 else y *= 3.0518509475997192e-05; // range -1.0 - 1.0 | 298 else y *= 3.0518509475997192e-05; // range -1.0 - 1.0 |
292 real a; | 299 real a; |
293 if (conf & SENSITIVITY) a = s.next(); | 300 if (conf & SENSITIVITY) a = s.pop(); |
294 /+ When a global sensitivity is available (possibly only use if it's enabled)... | 301 /+ When a global sensitivity is available (possibly only use if it's enabled)... |
295 else a = axis.sensitivity; | 302 else a = axis.sensitivity; |
296 y = sign(y) * pow(abs(y), a); // sensitivity adjustment by a +/ | 303 y = sign(y) * pow(abs(y), a); // sensitivity adjustment by a +/ |
297 axis[cast(inputID) s.next()] = y; | 304 myThis.axis[cast(inputID) s.pop()] = y; |
298 } | 305 } |
299 | 306 |
300 // Simple output function | 307 // Simple output function |
301 void es_m_out (short x, short y, readOutQueue s) { | 308 void es_m_out (Input myThis, short x, short y, readOutQueue s) { |
302 axis_rel[cast(inputID) s.next()] = RelPair(x,y); | 309 myThis.axis_rel[cast(inputID) s.pop()] = RelPair(x,y); |
303 } | 310 } |
304 //END ES Functions | 311 //END ES Functions |
305 //END Event stream functionality | 312 //END Event stream functionality |
306 } | 313 } |