Initial commit, includes Lua with broken Luabind as a backup for branching purposes
[terrastrategy.git] / src / input / input.cpp
bloba3e62208a7fdf20ed442d2edfbd982914c0b6f1c
1 //
2 // Copyright (C) 2007 by Martin Moracek
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 // TODO: event filter should be critical section for threaded filtering
21 /**
22 * @file input.cpp
24 * blahblah
28 #include <deque>
29 #include <vector>
30 #include <algorithm>
31 #include <SDL/SDL.h>
33 #include "types.h"
34 #include "input/input.h"
35 #include "vfs/logfile.h"
37 #include "memory/mmgr.h"
39 namespace tre {
42 * Local helper functions & vars
45 namespace {
47 Vector2f sMousePos;
48 Vector2f sMouseDelta;
50 SDLKey KeysymToSDL(KeySym key)
52 SDLKey ksm;
53 switch(key) {
54 case ksEscape: ksm = SDLK_ESCAPE; break;
55 case ks1: ksm = SDLK_1; break;
56 case ks2: ksm = SDLK_2; break;
57 case ks3: ksm = SDLK_3; break;
58 case ks4: ksm = SDLK_4; break;
59 case ks5: ksm = SDLK_5; break;
60 case ks6: ksm = SDLK_6; break;
61 case ks7: ksm = SDLK_7; break;
62 case ks8: ksm = SDLK_8; break;
63 case ks9: ksm = SDLK_9; break;
64 case ks0: ksm = SDLK_0; break;
65 case ksMinus: ksm = SDLK_MINUS; break;
66 case ksEquals: ksm = SDLK_EQUALS; break;
67 case ksBack: ksm = SDLK_BACKSPACE; break;
68 case ksTab: ksm = SDLK_TAB; break;
69 case ksQ: ksm = SDLK_q; break;
70 case ksW: ksm = SDLK_w; break;
71 case ksE: ksm = SDLK_e; break;
72 case ksR: ksm = SDLK_r; break;
73 case ksT: ksm = SDLK_t; break;
74 case ksY: ksm = SDLK_y; break;
75 case ksU: ksm = SDLK_u; break;
76 case ksI: ksm = SDLK_i; break;
77 case ksO: ksm = SDLK_o; break;
78 case ksP: ksm = SDLK_p; break;
79 case ksA: ksm = SDLK_a; break;
80 case ksS: ksm = SDLK_s; break;
81 case ksD: ksm = SDLK_d; break;
82 case ksF: ksm = SDLK_f; break;
83 case ksG: ksm = SDLK_g; break;
84 case ksH: ksm = SDLK_h; break;
85 case ksJ: ksm = SDLK_j; break;
86 case ksK: ksm = SDLK_k; break;
87 case ksL: ksm = SDLK_l; break;
88 case ksZ: ksm = SDLK_z; break;
89 case ksX: ksm = SDLK_x; break;
90 case ksC: ksm = SDLK_c; break;
91 case ksV: ksm = SDLK_v; break;
92 case ksB: ksm = SDLK_b; break;
93 case ksN: ksm = SDLK_n; break;
94 case ksM: ksm = SDLK_m; break;
95 case ksLBrack: ksm = SDLK_LEFTBRACKET; break;
96 case ksRBrack: ksm = SDLK_RIGHTBRACKET; break;
97 case ksReturn: ksm = SDLK_RETURN; break;
98 case ksLCtrl: ksm = SDLK_LCTRL; break;
99 case ksSemicol: ksm = SDLK_SEMICOLON; break;
100 case ksApos: ksm = SDLK_QUOTE; break;
101 case ksGrave: ksm = SDLK_BACKQUOTE; break;
102 case ksLShift: ksm = SDLK_LSHIFT; break;
103 case ksBacksl: ksm = SDLK_BACKSLASH; break;
104 case ksComma: ksm = SDLK_COMMA; break;
105 case ksPer: ksm = SDLK_PERIOD; break;
106 case ksSlash: ksm = SDLK_SLASH; break;
107 case ksRShift: ksm = SDLK_RSHIFT; break;
108 case ksKpMul: ksm = SDLK_KP_MULTIPLY; break;
109 case ksLMenu: ksm = SDLK_LALT; break;
110 case ksSpace: ksm = SDLK_SPACE; break;
111 case ksCap: ksm = SDLK_CAPSLOCK; break;
112 case ksF1: ksm = SDLK_F1; break;
113 case ksF2: ksm = SDLK_F2; break;
114 case ksF3: ksm = SDLK_F3; break;
115 case ksF4: ksm = SDLK_F4; break;
116 case ksF5: ksm = SDLK_F5; break;
117 case ksF6: ksm = SDLK_F6; break;
118 case ksF7: ksm = SDLK_F7; break;
119 case ksF8: ksm = SDLK_F8; break;
120 case ksF9: ksm = SDLK_F9; break;
121 case ksF10: ksm = SDLK_F10; break;
122 case ksF11: ksm = SDLK_F11; break;
123 case ksF12: ksm = SDLK_F12; break;
124 case ksF13: ksm = SDLK_F13; break;
125 case ksF14: ksm = SDLK_F14; break;
126 case ksF15: ksm = SDLK_F15; break;
127 case ksNum: ksm = SDLK_NUMLOCK; break;
128 case ksScroll: ksm = SDLK_SCROLLOCK; break;
129 case ksKp0: ksm = SDLK_KP0; break;
130 case ksKp1: ksm = SDLK_KP1; break;
131 case ksKp2: ksm = SDLK_KP2; break;
132 case ksKp3: ksm = SDLK_KP3; break;
133 case ksKp4: ksm = SDLK_KP4; break;
134 case ksKp5: ksm = SDLK_KP5; break;
135 case ksKp6: ksm = SDLK_KP6; break;
136 case ksKp7: ksm = SDLK_KP7; break;
137 case ksKp8: ksm = SDLK_KP8; break;
138 case ksKp9: ksm = SDLK_KP9; break;
139 case ksKpSub: ksm = SDLK_KP_MINUS; break;
140 case ksKpAdd: ksm = SDLK_KP_PLUS; break;
141 case ksKpDec: ksm = SDLK_KP_PERIOD; break;
142 case ksRCtrl: ksm = SDLK_RCTRL; break;
143 case ksKpEquals: ksm = SDLK_KP_EQUALS; break;
144 case ksKpDiv: ksm = SDLK_KP_DIVIDE; break;
145 case ksSysRq: ksm = SDLK_SYSREQ; break;
146 case ksRMenu: ksm = SDLK_RALT; break;
147 case ksPause: ksm = SDLK_PAUSE; break;
148 case ksHome: ksm = SDLK_HOME; break;
149 case ksUp: ksm = SDLK_UP; break;
150 case ksPgUp: ksm = SDLK_PAGEUP; break;
151 case ksLeft: ksm = SDLK_LEFT; break;
152 case ksRight: ksm = SDLK_RIGHT; break;
153 case ksEnd: ksm = SDLK_END; break;
154 case ksDown: ksm = SDLK_DOWN; break;
155 case ksPgDown: ksm = SDLK_PAGEDOWN; break;
156 case ksIns: ksm = SDLK_INSERT; break;
157 case ksDel: ksm = SDLK_DELETE; break;
158 case ksPower: ksm = SDLK_POWER; break;
159 case ksLWin: ksm = SDLK_LSUPER; break;
160 case ksRWin: ksm = SDLK_RSUPER; break;
161 default: ksm = SDLK_a; break;
163 return ksm;
166 KeySym SDLToKeysym(SDLKey key)
168 KeySym ksm;
169 switch(key) {
170 case SDLK_BACKSPACE: ksm = ksBack; break;
171 case SDLK_TAB: ksm = ksTab; break;
172 case SDLK_RETURN: ksm = ksReturn; break;
173 case SDLK_PAUSE: ksm = ksPause; break;
174 case SDLK_ESCAPE: ksm = ksEscape; break;
175 case SDLK_SPACE: ksm = ksSpace; break;
176 case SDLK_QUOTE: ksm = ksApos; break;
177 case SDLK_COMMA: ksm = ksComma; break;
178 case SDLK_MINUS: ksm = ksMinus; break;
179 case SDLK_PERIOD: ksm = ksPer; break;
180 case SDLK_SLASH: ksm = ksSlash; break;
181 case SDLK_0: ksm = ks0; break;
182 case SDLK_1: ksm = ks1; break;
183 case SDLK_2: ksm = ks2; break;
184 case SDLK_3: ksm = ks3; break;
185 case SDLK_4: ksm = ks4; break;
186 case SDLK_5: ksm = ks5; break;
187 case SDLK_6: ksm = ks6; break;
188 case SDLK_7: ksm = ks7; break;
189 case SDLK_8: ksm = ks8; break;
190 case SDLK_9: ksm = ks9; break;
191 case SDLK_SEMICOLON: ksm = ksSemicol; break;
192 case SDLK_EQUALS: ksm = ksEquals; break;
193 case SDLK_LEFTBRACKET: ksm = ksLBrack; break;
194 case SDLK_BACKSLASH: ksm = ksBacksl; break;
195 case SDLK_RIGHTBRACKET: ksm = ksRBrack; break;
196 case SDLK_BACKQUOTE: ksm = ksGrave; break;
197 case SDLK_a: ksm = ksA; break;
198 case SDLK_b: ksm = ksB; break;
199 case SDLK_c: ksm = ksC; break;
200 case SDLK_d: ksm = ksD; break;
201 case SDLK_e: ksm = ksE; break;
202 case SDLK_f: ksm = ksF; break;
203 case SDLK_g: ksm = ksG; break;
204 case SDLK_h: ksm = ksH; break;
205 case SDLK_i: ksm = ksI; break;
206 case SDLK_j: ksm = ksJ; break;
207 case SDLK_k: ksm = ksK; break;
208 case SDLK_l: ksm = ksL; break;
209 case SDLK_m: ksm = ksM; break;
210 case SDLK_n: ksm = ksN; break;
211 case SDLK_o: ksm = ksO; break;
212 case SDLK_p: ksm = ksP; break;
213 case SDLK_q: ksm = ksQ; break;
214 case SDLK_r: ksm = ksR; break;
215 case SDLK_s: ksm = ksS; break;
216 case SDLK_t: ksm = ksT; break;
217 case SDLK_u: ksm = ksU; break;
218 case SDLK_v: ksm = ksV; break;
219 case SDLK_w: ksm = ksW; break;
220 case SDLK_x: ksm = ksX; break;
221 case SDLK_y: ksm = ksY; break;
222 case SDLK_z: ksm = ksZ; break;
223 case SDLK_DELETE: ksm = ksDel; break;
224 case SDLK_KP0: ksm = ksKp0; break;
225 case SDLK_KP1: ksm = ksKp1; break;
226 case SDLK_KP2: ksm = ksKp2; break;
227 case SDLK_KP3: ksm = ksKp3; break;
228 case SDLK_KP4: ksm = ksKp4; break;
229 case SDLK_KP5: ksm = ksKp5; break;
230 case SDLK_KP6: ksm = ksKp6; break;
231 case SDLK_KP7: ksm = ksKp7; break;
232 case SDLK_KP8: ksm = ksKp8; break;
233 case SDLK_KP9: ksm = ksKp9; break;
234 case SDLK_KP_PERIOD: ksm = ksKpDec; break;
235 case SDLK_KP_DIVIDE: ksm = ksKpDiv; break;
236 case SDLK_KP_MULTIPLY: ksm = ksKpMul; break;
237 case SDLK_KP_MINUS: ksm = ksKpSub; break;
238 case SDLK_KP_PLUS: ksm = ksKpAdd; break;
239 case SDLK_KP_ENTER: ksm = ksKpEnter; break;
240 case SDLK_KP_EQUALS: ksm = ksKpEquals; break;
241 case SDLK_UP: ksm = ksUp; break;
242 case SDLK_DOWN: ksm = ksDown; break;
243 case SDLK_RIGHT: ksm = ksRight; break;
244 case SDLK_LEFT: ksm = ksLeft; break;
245 case SDLK_INSERT: ksm = ksIns; break;
246 case SDLK_HOME: ksm = ksHome; break;
247 case SDLK_END: ksm = ksEnd; break;
248 case SDLK_PAGEUP: ksm = ksPgUp; break;
249 case SDLK_PAGEDOWN: ksm = ksPgDown; break;
250 case SDLK_F1: ksm = ksF1; break;
251 case SDLK_F2: ksm = ksF2; break;
252 case SDLK_F3: ksm = ksF3; break;
253 case SDLK_F4: ksm = ksF4; break;
254 case SDLK_F5: ksm = ksF5; break;
255 case SDLK_F6: ksm = ksF6; break;
256 case SDLK_F7: ksm = ksF7; break;
257 case SDLK_F8: ksm = ksF8; break;
258 case SDLK_F9: ksm = ksF9; break;
259 case SDLK_F10: ksm = ksF10; break;
260 case SDLK_F11: ksm = ksF11; break;
261 case SDLK_F12: ksm = ksF12; break;
262 case SDLK_F13: ksm = ksF13; break;
263 case SDLK_F14: ksm = ksF14; break;
264 case SDLK_F15: ksm = ksF15; break;
265 case SDLK_NUMLOCK: ksm = ksNum; break;
266 case SDLK_CAPSLOCK: ksm = ksCap; break;
267 case SDLK_SCROLLOCK: ksm = ksScroll; break;
268 case SDLK_RSHIFT: ksm = ksRShift; break;
269 case SDLK_LSHIFT: ksm = ksLShift; break;
270 case SDLK_RCTRL: ksm = ksRCtrl; break;
271 case SDLK_LCTRL: ksm = ksLCtrl; break;
272 case SDLK_RALT: ksm = ksRMenu; break;
273 case SDLK_LALT: ksm = ksLMenu; break;
274 case SDLK_LSUPER: ksm = ksLWin; break;
275 case SDLK_RSUPER: ksm = ksRWin; break;
276 case SDLK_SYSREQ: ksm = ksSysRq; break;
277 case SDLK_POWER: ksm = ksPower; break;
278 default: ksm = ksNone;
280 return ksm;
285 int EventFilter(const SDL_Event *event)
287 if(event == NULL)
288 return 0;
290 if(event->type == SDL_MOUSEMOTION) {
291 sMouseDelta.x += event->motion.xrel;
292 sMouseDelta.y += event->motion.yrel;
293 sMousePos.x = event->motion.x;
294 sMousePos.y = event->motion.y;
295 return 0;
298 return event->type == SDL_QUIT || event->type == SDL_MOUSEBUTTONDOWN ||
299 event->type == SDL_MOUSEBUTTONUP || event->type == SDL_KEYDOWN ||
300 event->type == SDL_KEYUP;
304 * InputInternals class
307 const uint maxButtons = 5;
309 class Input::InputInternals {
310 public:
311 typedef std::deque<InputEvent> InputQueue;
313 public:
314 InputQueue iqueue;
316 bool buttons[maxButtons];
318 public:
319 InputInternals();
320 ~InputInternals();
322 void ProcessEvent(const SDL_Event & event);
324 friend int EventFilter(const SDL_Event *event);
327 Input::InputInternals::InputInternals()
329 SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
330 SDL_EventState(SDL_JOYAXISMOTION, SDL_IGNORE);
331 SDL_EventState(SDL_JOYBALLMOTION, SDL_IGNORE);
332 SDL_EventState(SDL_JOYHATMOTION, SDL_IGNORE);
333 SDL_EventState(SDL_JOYBUTTONDOWN, SDL_IGNORE);
334 SDL_EventState(SDL_JOYBUTTONUP, SDL_IGNORE);
335 SDL_EventState(SDL_VIDEORESIZE, SDL_IGNORE);
336 SDL_EventState(SDL_VIDEOEXPOSE, SDL_IGNORE);
337 SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
338 SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
340 // SDL_EnableUNICODE(1);
341 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
343 // init values
344 sMousePos.Set(0.0f, 0.0f);
345 sMouseDelta.Set(0.0f, 0.0f);
347 std::fill(buttons, buttons + maxButtons, false);
349 SDL_SetEventFilter(EventFilter);
352 Input::InputInternals::~InputInternals()
354 SDL_SetEventFilter(NULL);
357 void Input::InputInternals::ProcessEvent(const SDL_Event & event)
359 InputEvent ev;
360 switch(event.type) {
361 case SDL_QUIT:
362 ev.type = etQuit;
363 iqueue.push_back(ev);
364 break;
365 case SDL_MOUSEBUTTONDOWN:
366 if(event.button.button > 0 && event.button.button <= maxButtons) {
367 buttons[event.button.button - 1] = true;
368 ev.type = etButtonOn;
369 ev.button = event.button.button - 1;
370 iqueue.push_back(ev);
372 break;
373 case SDL_MOUSEBUTTONUP:
374 if(event.button.button > 0 && event.button.button <= 3) {
375 buttons[event.button.button - 1] = false;
376 ev.type = etButtonOff;
377 ev.button = event.button.button - 1;
378 iqueue.push_back(ev);
380 break;
381 case SDL_KEYDOWN:
382 ev.type = etKeyOn;
383 ev.key.sym = SDLToKeysym(event.key.keysym.sym);
384 ev.key.chr = event.key.keysym.sym > 255 ?
385 0 : static_cast<char>(event.key.keysym.sym);
386 iqueue.push_back(ev);
387 break;
388 case SDL_KEYUP:
389 ev.type = etKeyOff;
390 ev.key.sym = SDLToKeysym(event.key.keysym.sym);
391 ev.key.chr = event.key.keysym.sym > 255 ?
392 0 : static_cast<char>(event.key.keysym.sym);
393 iqueue.push_back(ev);
394 break;
399 * Input class implementation
402 Input & sInput(void)
404 static Input input;
406 return input;
409 Input::Input() : internals_(new InputInternals)
411 #ifdef LOG_SINGLETONS
412 vLog << info() << "Initializing input." << std::endl;
413 #endif /* LOG_SINGLETONS */
416 Input::~Input()
418 #ifdef LOG_SINGLETONS
419 vLog << info() << "Releasing input." << std::endl;
420 #endif /* LOG_SINGLETONS */
421 delete internals_;
424 const Vector2f Input::GetPosition(void)
426 return sMousePos;
429 const Vector2f Input::GetPositionChange(void)
431 Vector2f res = sMouseDelta;
432 sMouseDelta.Set(0.0f, 0.0f);
433 return res;
436 void Input::SetPosition(const Vector2f & v)
438 sMouseDelta.Set(0.0f, 0.0f);
439 sMouseDelta = v;
442 bool Input::GetButtonState(uint id)
444 if(id < maxButtons) {
445 return internals_->buttons[id];
446 } else {
447 vLog << warn("Input")
448 << "Indexing unavailable mouse button." << std::endl;
450 return false;
453 bool Input::GetCharacterState(char chr)
455 uint8 * keystate = SDL_GetKeyState(NULL);
456 return (keystate[SDLK_a+tolower(chr)] == 1);
459 bool Input::GetKeysymState(KeySym sym)
461 uint8 * keystate = SDL_GetKeyState(NULL);
462 return (keystate[KeysymToSDL(sym)] == 1);
465 KeyMod Input::GetKeyMod(void)
467 return SDL_GetModState();
470 void Input::PumpEvents(void)
472 SDL_PumpEvents();
474 // process events and fill up the queue
475 SDL_Event event;
476 while(SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_ALLEVENTS) > 0) {
477 internals_->ProcessEvent(event);
481 void Input::DropEvents(void)
483 internals_->iqueue.resize(0);
486 InputEvent Input::GetNextEvent(void)
488 InputEvent event;
490 if(internals_->iqueue.empty()) {
491 event.type = etNone;
492 } else {
493 event = internals_->iqueue.front();
494 internals_->iqueue.pop_front();
496 return event;