1 /*      _______   __   __   __   ______   __   __   _______   __   __
2  *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
3  *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
4  *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
5  *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
6  * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
7  * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
8  *
9  * Copyright (c) 2004 - 2008 Olof Naess�n and Per Larsson
10  *
11  *
12  * Per Larsson a.k.a finalman
13  * Olof Naess�n a.k.a jansem/yakslem
14  *
15  * Visit: http://guichan.sourceforge.net
16  *
17  * License: (BSD)
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in
25  *    the documentation and/or other materials provided with the
26  *    distribution.
27  * 3. Neither the name of Guichan nor the names of its contributors may
28  *    be used to endorse or promote products derived from this software
29  *    without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
37  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
38  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
39  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  */
43 
44 /*
45  * For comments regarding functions please see the header file.
46  */
47 
48 #include "guichan/allegro/allegroinput.hpp"
49 
50 #include <allegro.h>
51 
52 #include "guichan/exception.hpp"
53 
54 namespace gcn
55 {
AllegroInput()56     AllegroInput::AllegroInput()
57     {
58         mMouseButton1 = mMouseButton2 = mMouseButton3 = false;
59         mLastMouseZ = 0;
60         mLastMouseX = 0;
61         mLastMouseY = 0;
62     }
63 
isKeyQueueEmpty()64     bool AllegroInput::isKeyQueueEmpty()
65     {
66         return mKeyQueue.empty();
67     }
68 
dequeueKeyInput()69     KeyInput AllegroInput::dequeueKeyInput()
70     {
71         if (isKeyQueueEmpty())
72         {
73             throw GCN_EXCEPTION("Key queue is empty.");
74         }
75 
76         KeyInput ki = mKeyQueue.front();
77         mKeyQueue.pop();
78 
79         return ki;
80     }
81 
isMouseQueueEmpty()82     bool AllegroInput::isMouseQueueEmpty()
83     {
84         return mMouseQueue.empty();
85     }
86 
dequeueMouseInput()87     MouseInput AllegroInput::dequeueMouseInput()
88     {
89         if (isMouseQueueEmpty())
90         {
91             throw GCN_EXCEPTION("Mouse queue is empty.");
92         }
93 
94         MouseInput mi = mMouseQueue.front();
95         mMouseQueue.pop();
96 
97         return mi;
98     }
99 
_pollInput()100     void AllegroInput::_pollInput()
101     {
102         pollMouseInput();
103         pollKeyInput();
104     }
105 
pollMouseInput()106     void AllegroInput::pollMouseInput()
107     {
108         if (mouse_needs_poll())
109         {
110             poll_mouse();
111         }
112         int mouseX = mouse_x;
113         int mouseY = mouse_y;
114         int mouseZ = mouse_z;
115         int mouseB1 = mouse_b & 1;
116         int mouseB2 = mouse_b & 2;
117         int mouseB3 = mouse_b & 4;
118 
119         // Check mouse movement
120         if (mouseX != mLastMouseX || mouseY != mLastMouseY)
121         {
122             mMouseQueue.push(MouseInput(MouseInput::EMPTY,
123                                         MouseInput::MOVED,
124                                         mouseX,
125                                         mouseY,
126                                         0));
127             mLastMouseX = mouseX;
128             mLastMouseY = mouseY;
129         }
130 
131         // Check mouse Wheel
132         while (mLastMouseZ < mouseZ)
133         {
134             mMouseQueue.push(MouseInput(MouseInput::EMPTY,
135                                         MouseInput::WHEEL_MOVED_UP,
136                                         mouseX,
137                                         mouseY,
138                                         0));
139             mLastMouseZ++;
140         }
141 
142         while (mLastMouseZ > mouseZ)
143         {
144             mMouseQueue.push(MouseInput(MouseInput::EMPTY,
145                                         MouseInput::WHEEL_MOVED_DOWN,
146                                         mouseX,
147                                         mouseY,
148                                         0));
149             mLastMouseZ--;
150         }
151 
152         // Check mouse buttons
153         if (!mMouseButton1 && mouseB1)
154         {
155             mMouseQueue.push(MouseInput(MouseInput::LEFT,
156                                         MouseInput::PRESSED,
157                                         mouseX,
158                                         mouseY,
159                                         0));
160         }
161 
162         if (mMouseButton1 && !mouseB1)
163         {
164             mMouseQueue.push(MouseInput(MouseInput::LEFT,
165                                         MouseInput::RELEASED,
166                                         mouseX,
167                                         mouseY,
168                                         0));
169         }
170 
171 
172         if (!mMouseButton2 && mouseB2)
173         {
174             mMouseQueue.push(MouseInput(MouseInput::RIGHT,
175                                         MouseInput::PRESSED,
176                                         mouseX,
177                                         mouseY,
178                                         0));
179         }
180 
181         if (mMouseButton2 && !mouseB2)
182         {
183             mMouseQueue.push(MouseInput(MouseInput::RIGHT,
184                                         MouseInput::RELEASED,
185                                         mouseX,
186                                         mouseY,
187                                         0));
188         }
189 
190 
191         if (!mMouseButton3 && mouseB3)
192         {
193             mMouseQueue.push(MouseInput(MouseInput::MIDDLE,
194                                         MouseInput::PRESSED,
195                                         mouseX,
196                                         mouseY,
197                                         0));
198         }
199 
200         if (mMouseButton3 && !mouseB3)
201         {
202             mMouseQueue.push(MouseInput(MouseInput::MIDDLE,
203                                         MouseInput::RELEASED,
204                                         mouseX,
205                                         mouseY,
206                                         0));
207         }
208 
209         mMouseButton1 = mouseB1;
210         mMouseButton2 = mouseB2;
211         mMouseButton3 = mouseB3;
212     }
213 
pollKeyInput()214     void AllegroInput::pollKeyInput()
215     {
216         int unicode, scancode;
217 
218         if (keyboard_needs_poll())
219         {
220             poll_keyboard();
221         }
222 
223         while (keypressed())
224         {
225             unicode = ureadkey(&scancode);
226             Key keyObj = convertToKey(scancode, unicode);
227 
228             KeyInput keyInput(keyObj, KeyInput::PRESSED);
229 
230             keyInput.setNumericPad(isNumericPad(scancode));
231             keyInput.setShiftPressed(key_shifts & KB_SHIFT_FLAG);
232             keyInput.setAltPressed(key_shifts & KB_ALT_FLAG);
233             keyInput.setControlPressed(key_shifts & KB_CTRL_FLAG);
234 #ifdef KB_COMMAND_FLAG
235             keyInput.setMetaPressed(key_shifts & (KB_COMMAND_FLAG |
236                                            KB_LWIN_FLAG |
237                                            KB_RWIN_FLAG));
238 #else
239             keyInput.setMetaPressed(key_shifts & (KB_LWIN_FLAG |
240                                                   KB_RWIN_FLAG));
241 #endif
242 
243 
244             mKeyQueue.push(keyInput);
245 
246             mPressedKeys[scancode] = keyInput;
247         }
248 
249         if (key[KEY_ALT] && mPressedKeys.find(KEY_ALT) == mPressedKeys.end())
250 		{
251 			KeyInput keyInput(convertToKey(KEY_ALT, 0), KeyInput::PRESSED);
252             mKeyQueue.push(keyInput);
253             mPressedKeys[KEY_ALT] = keyInput;
254 		}
255 
256 		if (key[KEY_ALTGR] && mPressedKeys.find(KEY_ALTGR) == mPressedKeys.end())
257 		{
258 			KeyInput keyInput(convertToKey(KEY_ALTGR, 0), KeyInput::PRESSED);
259             mKeyQueue.push(keyInput);
260             mPressedKeys[KEY_ALTGR] = keyInput;
261 		}
262 
263 		if (key[KEY_LSHIFT] && mPressedKeys.find(KEY_LSHIFT) == mPressedKeys.end())
264 		{
265 			KeyInput keyInput(convertToKey(KEY_LSHIFT, 0), KeyInput::PRESSED);
266             mKeyQueue.push(keyInput);
267             mPressedKeys[KEY_LSHIFT] = keyInput;
268 		}
269 
270 		if (key[KEY_RSHIFT] && mPressedKeys.find(KEY_RSHIFT) == mPressedKeys.end())
271 		{
272 			KeyInput keyInput(convertToKey(KEY_RSHIFT, 0), KeyInput::PRESSED);
273             mKeyQueue.push(keyInput);
274             mPressedKeys[KEY_RSHIFT] = keyInput;
275 		}
276 
277 		if (key[KEY_LCONTROL] && mPressedKeys.find(KEY_LCONTROL) == mPressedKeys.end())
278 		{
279 			KeyInput keyInput(convertToKey(KEY_LCONTROL, 0), KeyInput::PRESSED);
280             mKeyQueue.push(keyInput);
281             mPressedKeys[KEY_LCONTROL] = keyInput;
282 		}
283 
284 		if (key[KEY_RCONTROL] && mPressedKeys.find(KEY_RCONTROL) == mPressedKeys.end())
285 		{
286 			KeyInput keyInput(convertToKey(KEY_RCONTROL, 0), KeyInput::PRESSED);
287             mKeyQueue.push(keyInput);
288             mPressedKeys[KEY_RCONTROL] = keyInput;
289 		}
290 
291          // Check for released keys
292         std::map<int, KeyInput>::iterator iter, tempIter;
293         for (iter = mPressedKeys.begin(); iter != mPressedKeys.end(); )
294          {
295             if (!key[iter->first])
296             {
297                 KeyInput keyInput(iter->second.getKey(), KeyInput::RELEASED);
298                 keyInput.setNumericPad(iter->second.isNumericPad());
299                 keyInput.setShiftPressed(iter->second.isShiftPressed());
300                 keyInput.setAltPressed(iter->second.isAltPressed());
301                 keyInput.setControlPressed(iter->second.isControlPressed());
302 
303                 mKeyQueue.push(keyInput);
304 
305                 tempIter = iter;
306                 iter++;
307                 mPressedKeys.erase(tempIter);
308             }
309             else
310             {
311                 iter++;
312             }
313         }
314     }
315 
convertToKey(int scancode,int unicode)316     Key AllegroInput::convertToKey(int scancode, int unicode)
317     {
318         int keysym;
319         bool pad = false;
320 
321         switch(scancode)
322         {
323           case KEY_ESC:
324               keysym = Key::ESCAPE;
325               break;
326 
327           case KEY_ALT:
328               keysym = Key::LEFT_ALT;
329               break;
330 
331           case KEY_ALTGR:
332               keysym = Key::RIGHT_ALT;
333               break;
334 
335           case KEY_LSHIFT:
336               keysym = Key::LEFT_SHIFT;
337               break;
338 
339           case KEY_RSHIFT:
340               keysym = Key::RIGHT_SHIFT;
341               break;
342 
343           case KEY_LCONTROL:
344               keysym = Key::LEFT_CONTROL;
345               break;
346 
347           case KEY_RCONTROL:
348               keysym = Key::RIGHT_CONTROL;
349               break;
350 
351           case KEY_LWIN:
352               keysym = Key::LEFT_META;
353               break;
354 
355           case KEY_RWIN:
356               keysym = Key::RIGHT_META;
357               break;
358 
359           case KEY_INSERT:
360               keysym = Key::INSERT;
361               break;
362 
363           case KEY_HOME:
364               keysym = Key::HOME;
365               break;
366 
367           case KEY_PGUP:
368               keysym = Key::PAGE_UP;
369               break;
370 
371           case KEY_PGDN:
372               keysym = Key::PAGE_DOWN;
373               break;
374 
375           case KEY_DEL:
376               keysym = Key::DELETE;
377               break;
378 
379           case KEY_DEL_PAD:
380               keysym = Key::DELETE;
381               pad = true;
382               break;
383 
384           case KEY_END:
385               keysym = Key::END;
386               break;
387 
388           case KEY_CAPSLOCK:
389               keysym = Key::CAPS_LOCK;
390               break;
391 
392           case KEY_BACKSPACE:
393               keysym = Key::BACKSPACE;
394               break;
395 
396           case KEY_F1:
397               keysym = Key::F1;
398               break;
399 
400           case KEY_F2:
401               keysym = Key::F2;
402               break;
403 
404           case KEY_F3:
405               keysym = Key::F3;
406               break;
407 
408           case KEY_F4:
409               keysym = Key::F4;
410               break;
411 
412           case KEY_F5:
413               keysym = Key::F5;
414               break;
415 
416           case KEY_F6:
417               keysym = Key::F6;
418               break;
419 
420           case KEY_F7:
421               keysym = Key::F7;
422               break;
423 
424           case KEY_F8:
425               keysym = Key::F8;
426               break;
427 
428           case KEY_F9:
429               keysym = Key::F9;
430               break;
431 
432           case KEY_F10:
433               keysym = Key::F10;
434               break;
435 
436           case KEY_F11:
437               keysym = Key::F11;
438               break;
439 
440           case KEY_F12:
441               keysym = Key::F12;
442               break;
443 
444           case KEY_PRTSCR:
445               keysym = Key::PRINT_SCREEN;
446               break;
447 
448           case KEY_PAUSE:
449               keysym = Key::PAUSE;
450               break;
451 
452           case KEY_SCRLOCK:
453               keysym = Key::SCROLL_LOCK;
454               break;
455 
456           case KEY_NUMLOCK:
457               keysym = Key::NUM_LOCK;
458               break;
459 
460           case KEY_LEFT:
461               keysym = Key::LEFT;
462               break;
463 
464           case KEY_RIGHT:
465               keysym = Key::RIGHT;
466               break;
467 
468           case KEY_UP:
469               keysym = Key::UP;
470               break;
471 
472           case KEY_DOWN:
473               keysym = Key::DOWN;
474               break;
475 
476           case KEY_ENTER_PAD:
477               pad = true;
478           case KEY_ENTER:
479               keysym = Key::ENTER;
480               break;
481      default:
482               keysym = unicode;
483         }
484 
485         Key k = Key(keysym);
486 
487         return k;
488 
489         //Now, THAT was fun to code! =D =D =D
490     }
491 
isNumericPad(int scancode)492     bool AllegroInput::isNumericPad(int scancode)
493     {
494         switch (scancode)
495         {
496           case KEY_0_PAD:
497           case KEY_1_PAD:
498           case KEY_2_PAD:
499           case KEY_3_PAD:
500           case KEY_4_PAD:
501           case KEY_5_PAD:
502           case KEY_6_PAD:
503           case KEY_7_PAD:
504           case KEY_8_PAD:
505           case KEY_9_PAD:
506           case KEY_SLASH_PAD:
507           case KEY_MINUS_PAD:
508           case KEY_PLUS_PAD:
509               return true;
510           default:
511               return false;
512         }
513     }
514 }
515