1 /*      _______   __   __   __   ______   __   __   _______   __   __
2  *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
3  *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
4  *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
5  *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
6  * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
7  * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
8  *
9  * Copyright (c) 2004, 2005 darkbits                        Js_./
10  * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
11  * Olof Naess�n a.k.a jansem/yakslem                _asww7!uY`>  )\a//
12  *                                                 _Qhm`] _f "'c  1!5m
13  * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
14  *                                               .)j(] .d_/ '-(  P .   S
15  * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
16  * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
17  * binary forms, with or without                 )4d[#7r, .   '     )d`)[
18  * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
19  * that the following conditions are met:       j<<WP+k/);.        _W=j f
20  * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
21  *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
22  *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
23  *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
24  * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
25  *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
26  *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
27  *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
28  *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
29  *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
30  * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
31  *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
32  *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
33  *    from this software without specific        (js, \[QQW$QWW#?!V"".
34  *    prior written permission.                    ]y:.<\..          .
35  *                                                 -]n w/ '         [.
36  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
37  * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
38  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
39  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
40  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
41  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
42  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
43  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
44  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
45  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
46  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
47  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
49  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
51  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
52  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53  */
54 
55 /*
56  * For comments regarding functions please see the header file.
57  */
58 #include <assert.h>
59 #include "guichan/sdl/sdlinput.h"
60 #include "guichan/exception.h"
61 
62 extern uint32_t SDL_CUSTOM_KEY_UP;
63 
64 namespace gcn
65 {
SDLInput()66     SDLInput::SDLInput()
67     {
68         mMouseInWindow = true;
69 		mMouseDown = false;
70 		mIsRepeating = false;
71     }
72 
isKeyQueueEmpty()73     bool SDLInput::isKeyQueueEmpty()
74     {
75         return mKeyInputQueue.empty();
76     }
77 
dequeueKeyInput()78     KeyInput SDLInput::dequeueKeyInput()
79     {
80         KeyInput keyInput;
81 
82         if (mKeyInputQueue.empty())
83         {
84         	assert(!"The queue is empty.");
85             //throw GCN_EXCEPTION("The queue is empty.");
86         }
87 
88         keyInput = mKeyInputQueue.front();
89         mKeyInputQueue.pop();
90 
91         return keyInput;
92     }
93 
isMouseQueueEmpty()94     bool SDLInput::isMouseQueueEmpty()
95     {
96         return mMouseInputQueue.empty();
97     }
98 
dequeueMouseInput()99     MouseInput SDLInput::dequeueMouseInput()
100     {
101         MouseInput mouseInput;
102 
103         if (mMouseInputQueue.empty())
104         {
105         	assert(!"The queue is empty.");
106             //throw GCN_EXCEPTION("The queue is empty.");
107         }
108 
109         mouseInput = mMouseInputQueue.front();
110         mMouseInputQueue.pop();
111 
112         return mouseInput;
113     }
114 
processKeyRepeat()115 	void SDLInput::processKeyRepeat()
116 	{
117 		KeyInput keyInput;
118 
119 		if (mIsRepeating) {
120 			keyInput.setKey(mLastKey);
121 			keyInput.setType(KeyInput::PRESS);
122 			mKeyInputQueue.push(keyInput);
123 		}
124 	}
125 
pushInput(SDL_Event event)126     void SDLInput::pushInput(SDL_Event event)
127     {
128         KeyInput keyInput;
129         MouseInput mouseInput;
130 
131         switch (event.type)
132         {
133           case SDL_TEXTINPUT:
134               {
135                   char* text = event.text.text;
136                   if ((uint8_t)text[0] >= 32 || (uint8_t)text[0] < 128) {
137                       mLastKey = text[0];
138                       mIsRepeating = true;
139                       keyInput.setKey(mLastKey);
140                       keyInput.setType(KeyInput::PRESS);
141                       mKeyInputQueue.push(keyInput);
142                   }
143               }
144               break;
145 
146           case SDL_USEREVENT:
147               if (reinterpret_cast<uintptr_t>(event.user.data1) == SDL_CUSTOM_KEY_UP) {
148                   mIsRepeating = false;
149                   keyInput.setKey(static_cast<char>(event.user.code));
150                   keyInput.setType(KeyInput::RELEASE);
151                   mKeyInputQueue.push(keyInput);
152               }
153 
154           case SDL_KEYDOWN:
155               if (event.key.keysym.sym < 32 || event.key.keysym.sym >= 128) {
156                   mLastKey = convertKeyCharacter(event.key.keysym);
157                   mIsRepeating = true;
158                   keyInput.setKey(mLastKey);
159                   keyInput.setType(KeyInput::PRESS);
160                   mKeyInputQueue.push(keyInput);
161               }
162               break;
163 
164           case SDL_KEYUP:
165               if (event.key.keysym.sym < 32 || event.key.keysym.sym >= 128) {
166                   mIsRepeating = false;
167                   keyInput.setKey(convertKeyCharacter(event.key.keysym));
168                   keyInput.setType(KeyInput::RELEASE);
169                   mKeyInputQueue.push(keyInput);
170               }
171               break;
172 
173           case SDL_MOUSEBUTTONDOWN:
174               mMouseDown = true;
175               mouseInput.x = event.button.x;
176               mouseInput.y = event.button.y;
177               mouseInput.setButton(convertMouseButton(event.button.button));
178               mouseInput.setType(MouseInput::PRESS);
179               mouseInput.setTimeStamp(SDL_GetTicks());
180               mMouseInputQueue.push(mouseInput);
181               break;
182 
183           case SDL_MOUSEBUTTONUP:
184               mMouseDown = false;
185               mouseInput.x = event.button.x;
186               mouseInput.y = event.button.y;
187               mouseInput.setButton(convertMouseButton(event.button.button));
188               mouseInput.setType(MouseInput::RELEASE);
189               mouseInput.setTimeStamp(SDL_GetTicks());
190               mMouseInputQueue.push(mouseInput);
191               break;
192 
193           case SDL_MOUSEWHEEL:
194               if (event.wheel.y != 0) {
195                   SDL_GetMouseState(&mouseInput.x, &mouseInput.y);
196                   if (event.wheel.y > 0)
197                     mouseInput.setType(MouseInput::WHEEL_UP);
198                   else
199                     mouseInput.setType(MouseInput::WHEEL_DOWN);
200                   mouseInput.setButton(MouseInput::EMPTY);
201                   mouseInput.setTimeStamp(event.wheel.timestamp);
202                   mMouseInputQueue.push(mouseInput);
203               }
204               break;
205 
206           case SDL_MOUSEMOTION:
207               mouseInput.x = event.button.x;
208               mouseInput.y = event.button.y;
209               mouseInput.setButton(MouseInput::EMPTY);
210               mouseInput.setType(MouseInput::MOTION);
211               mouseInput.setTimeStamp(SDL_GetTicks());
212               mMouseInputQueue.push(mouseInput);
213               break;
214 
215           case SDL_WINDOWEVENT:
216               /*
217                * This occurs when the mouse leaves the window and the Gui-chan
218                * application loses its mousefocus.
219                */
220               switch (event.window.event)
221               {
222                   case SDL_WINDOWEVENT_LEAVE:
223                       {
224                           mMouseInWindow = false;
225 
226                           if (!mMouseDown)
227                           {
228                               mouseInput.x = -1;
229                               mouseInput.y = -1;
230                               mouseInput.setButton(MouseInput::EMPTY);
231                               mouseInput.setType(MouseInput::MOTION);
232                               mMouseInputQueue.push(mouseInput);
233                           }
234                       }
235                       break;
236 
237                   case SDL_WINDOWEVENT_ENTER:
238                       mMouseInWindow = true;
239                       break;
240               }
241               break;
242 
243         } // end switch
244     }
245 
convertMouseButton(int button)246     int SDLInput::convertMouseButton(int button)
247     {
248         switch (button)
249         {
250           case SDL_BUTTON_LEFT:
251               return MouseInput::LEFT;
252               break;
253           case SDL_BUTTON_RIGHT:
254               return MouseInput::RIGHT;
255               break;
256           case SDL_BUTTON_MIDDLE:
257               return MouseInput::MIDDLE;
258               break;
259         }
260 
261 #ifdef DEBUG
262     	fprintf(stderr,"Unknown SDL mouse button.\n");
263 #endif
264 
265         return 0;
266     }
267 
convertKeyCharacter(SDL_Keysym keysym)268     Key SDLInput::convertKeyCharacter(SDL_Keysym keysym)
269     {
270         int value = 0;
271         Key key;
272 
273         switch (keysym.sym)
274         {
275           case SDLK_TAB:
276               value = Key::K_TAB;
277               break;
278           case SDLK_LALT:
279               value = Key::K_LEFT_ALT;
280               break;
281           case SDLK_RALT:
282               value = Key::K_RIGHT_ALT;
283               break;
284           case SDLK_LSHIFT:
285               value = Key::K_LEFT_SHIFT;
286               break;
287           case SDLK_RSHIFT:
288               value = Key::K_RIGHT_SHIFT;
289               break;
290           case SDLK_LCTRL:
291               value = Key::K_LEFT_CONTROL;
292               break;
293           case SDLK_RCTRL:
294               value = Key::K_RIGHT_CONTROL;
295               break;
296           case SDLK_BACKSPACE:
297               value = Key::K_BACKSPACE;
298               break;
299           case SDLK_PAUSE:
300               value = Key::K_PAUSE;
301               break;
302           case SDLK_SPACE:
303               value = Key::K_SPACE;
304               break;
305           case SDLK_ESCAPE:
306               value = Key::K_ESCAPE;
307               break;
308           case SDLK_DELETE:
309               value = Key::K_DELETE;
310               break;
311           case SDLK_INSERT:
312               value = Key::K_INSERT;
313               break;
314           case SDLK_HOME:
315               value = Key::K_HOME;
316               break;
317           case SDLK_END:
318               value = Key::K_END;
319               break;
320           case SDLK_PAGEUP:
321               value = Key::K_PAGE_UP;
322               break;
323           case SDLK_PRINTSCREEN:
324               value = Key::K_PRINT_SCREEN;
325               break;
326           case SDLK_PAGEDOWN:
327               value = Key::K_PAGE_DOWN;
328               break;
329           case SDLK_F1:
330               value = Key::K_F1;
331               break;
332           case SDLK_F2:
333               value = Key::K_F2;
334               break;
335           case SDLK_F3:
336               value = Key::K_F3;
337               break;
338           case SDLK_F4:
339               value = Key::K_F4;
340               break;
341           case SDLK_F5:
342               value = Key::K_F5;
343               break;
344           case SDLK_F6:
345               value = Key::K_F6;
346               break;
347           case SDLK_F7:
348               value = Key::K_F7;
349               break;
350           case SDLK_F8:
351               value = Key::K_F8;
352               break;
353           case SDLK_F9:
354               value = Key::K_F9;
355               break;
356           case SDLK_F10:
357               value = Key::K_F10;
358               break;
359           case SDLK_F11:
360               value = Key::K_F11;
361               break;
362           case SDLK_F12:
363               value = Key::K_F12;
364               break;
365           case SDLK_F13:
366               value = Key::K_F13;
367               break;
368           case SDLK_F14:
369               value = Key::K_F14;
370               break;
371           case SDLK_F15:
372               value = Key::K_F15;
373               break;
374           case SDLK_NUMLOCKCLEAR:
375               value = Key::K_NUM_LOCK;
376               break;
377           case SDLK_CAPSLOCK:
378               value = Key::K_CAPS_LOCK;
379               break;
380           case SDLK_SCROLLLOCK:
381               value = Key::K_SCROLL_LOCK;
382               break;
383           case SDLK_LGUI:
384               value = Key::K_LEFT_SUPER;
385               break;
386           case SDLK_RGUI:
387               value = Key::K_RIGHT_SUPER;
388               break;
389           case SDLK_MODE:
390               value = Key::K_ALT_GR;
391               break;
392           case SDLK_UP:
393               value = Key::K_UP;
394               break;
395           case SDLK_DOWN:
396               value = Key::K_DOWN;
397               break;
398           case SDLK_LEFT:
399               value = Key::K_LEFT;
400               break;
401           case SDLK_RIGHT:
402               value = Key::K_RIGHT;
403               break;
404           case SDLK_RETURN:
405               value = Key::K_ENTER;
406               break;
407           case SDLK_KP_ENTER:
408               value = Key::K_ENTER;
409               break;
410 
411           default:
412               value = keysym.sym;
413               break;
414         }
415 
416         if (!(keysym.mod & KMOD_NUM))
417         {
418             switch (keysym.sym)
419             {
420               case SDLK_KP_0:
421                   value = Key::K_INSERT;
422                   break;
423               case SDLK_KP_1:
424                   value = Key::K_END;
425                   break;
426               case SDLK_KP_2:
427                   value = Key::K_DOWN;
428                   break;
429               case SDLK_KP_3:
430                   value = Key::K_PAGE_DOWN;
431                   break;
432               case SDLK_KP_4:
433                   value = Key::K_LEFT;
434                   break;
435               case SDLK_KP_5:
436                   value = 0;
437                   break;
438               case SDLK_KP_6:
439                   value = Key::K_RIGHT;
440                   break;
441               case SDLK_KP_7:
442                   value = Key::K_HOME;
443                   break;
444               case SDLK_KP_8:
445                   value = Key::K_UP;
446                   break;
447               case SDLK_KP_9:
448                   value = Key::K_PAGE_UP;
449                   break;
450               default:
451                   break;
452             }
453         }
454 
455         key.setValue(value);
456         key.setShiftPressed((keysym.mod & KMOD_SHIFT) != 0);
457         key.setControlPressed((keysym.mod & KMOD_CTRL) != 0);
458         key.setAltPressed((keysym.mod & KMOD_ALT) != 0);
459         key.setMetaPressed((keysym.mod & KMOD_GUI) != 0);
460 
461         if (keysym.sym >= SDLK_KP_0 && keysym.sym <= SDLK_KP_EQUALS)
462         {
463             key.setNumericPad(true);
464         }
465 
466         return key;
467     }
468 }
469