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 }