1 /*
2 The zlib/libpng License
3
4 Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
5
6 This software is provided 'as-is', without any express or implied warranty. In no event will
7 the authors be held liable for any damages arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose, including commercial
10 applications, and to alter it and redistribute it freely, subject to the following
11 restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not claim that
14 you wrote the original software. If you use this software in a product,
15 an acknowledgment in the product documentation would be appreciated but is
16 not required.
17
18 2. Altered source versions must be plainly marked as such, and must not be
19 misrepresented as being the original software.
20
21 3. This notice may not be removed or altered from any source distribution.
22 */
23 #include "linux/LinuxInputManager.h"
24 #include "linux/LinuxKeyboard.h"
25 #include "OISException.h"
26 #include "OISEvents.h"
27
28 #include <X11/keysym.h>
29 #include <X11/Xutil.h>
30 #include <cstring>
31
32 using namespace OIS;
33 #include <iostream>
34 //-------------------------------------------------------------------//
LinuxKeyboard(InputManager * creator,bool buffered,bool grab)35 LinuxKeyboard::LinuxKeyboard(InputManager* creator, bool buffered, bool grab)
36 : Keyboard(creator->inputSystemName(), buffered, 0, creator)
37 {
38 setlocale(LC_CTYPE, ""); //Set the locale to (hopefully) the users LANG UTF-8 Env var
39
40 display = 0;
41 window = 0;
42
43 grabKeyboard = grab;
44 keyFocusLost = false;
45
46 //X Key Map to KeyCode
47 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_1, KC_1));
48 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_2, KC_2));
49 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_3, KC_3));
50 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_4, KC_4));
51 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_5, KC_5));
52 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_6, KC_6));
53 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_7, KC_7));
54 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_8, KC_8));
55 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_9, KC_9));
56 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_0, KC_0));
57
58 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_BackSpace, KC_BACK));
59
60 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_minus, KC_MINUS));
61 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_equal, KC_EQUALS));
62 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_space, KC_SPACE));
63 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_comma, KC_COMMA));
64 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_period, KC_PERIOD));
65
66 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_backslash, KC_BACKSLASH));
67 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_slash, KC_SLASH));
68 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_bracketleft, KC_LBRACKET));
69 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_bracketright, KC_RBRACKET));
70
71 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Escape,KC_ESCAPE));
72 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Caps_Lock, KC_CAPITAL));
73
74 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Tab, KC_TAB));
75 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Return, KC_RETURN));
76 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Control_L, KC_LCONTROL));
77 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Control_R, KC_RCONTROL));
78
79 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_colon, KC_COLON));
80 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_semicolon, KC_SEMICOLON));
81 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_apostrophe, KC_APOSTROPHE));
82 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_grave, KC_GRAVE));
83
84 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_b, KC_B));
85 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_a, KC_A));
86 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_c, KC_C));
87 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_d, KC_D));
88 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_e, KC_E));
89 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_f, KC_F));
90 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_g, KC_G));
91 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_h, KC_H));
92 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_i, KC_I));
93 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_j, KC_J));
94 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_k, KC_K));
95 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_l, KC_L));
96 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_m, KC_M));
97 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_n, KC_N));
98 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_o, KC_O));
99 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_p, KC_P));
100 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_q, KC_Q));
101 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_r, KC_R));
102 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_s, KC_S));
103 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_t, KC_T));
104 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_u, KC_U));
105 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_v, KC_V));
106 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_w, KC_W));
107 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_x, KC_X));
108 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_y, KC_Y));
109 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_z, KC_Z));
110
111 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F1, KC_F1));
112 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F2, KC_F2));
113 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F3, KC_F3));
114 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F4, KC_F4));
115 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F5, KC_F5));
116 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F6, KC_F6));
117 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F7, KC_F7));
118 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F8, KC_F8));
119 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F9, KC_F9));
120 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F10, KC_F10));
121 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F11, KC_F11));
122 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F12, KC_F12));
123 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F13, KC_F13));
124 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F14, KC_F14));
125 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_F15, KC_F15));
126
127 //Keypad
128 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_0, KC_NUMPAD0));
129 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_1, KC_NUMPAD1));
130 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_2, KC_NUMPAD2));
131 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_3, KC_NUMPAD3));
132 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_4, KC_NUMPAD4));
133 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_5, KC_NUMPAD5));
134 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_6, KC_NUMPAD6));
135 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_7, KC_NUMPAD7));
136 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_8, KC_NUMPAD8));
137 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_9, KC_NUMPAD9));
138 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Add, KC_ADD));
139 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Subtract, KC_SUBTRACT));
140 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Decimal, KC_DECIMAL));
141 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Equal, KC_NUMPADEQUALS));
142 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Divide, KC_DIVIDE));
143 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Multiply, KC_MULTIPLY));
144 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Enter, KC_NUMPADENTER));
145
146 //Keypad with numlock off
147 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Home, KC_NUMPAD7));
148 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Up, KC_NUMPAD8));
149 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Page_Up, KC_NUMPAD9));
150 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Left, KC_NUMPAD4));
151 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Begin, KC_NUMPAD5));
152 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Right, KC_NUMPAD6));
153 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_End, KC_NUMPAD1));
154 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Down, KC_NUMPAD2));
155 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Page_Down, KC_NUMPAD3));
156 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Insert, KC_NUMPAD0));
157 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_KP_Delete, KC_DECIMAL));
158
159 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Up, KC_UP));
160 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Down, KC_DOWN));
161 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Left, KC_LEFT));
162 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Right, KC_RIGHT));
163
164 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Page_Up, KC_PGUP));
165 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Page_Down, KC_PGDOWN));
166 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Home, KC_HOME));
167 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_End, KC_END));
168
169 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Num_Lock, KC_NUMLOCK));
170 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Print, KC_SYSRQ));
171 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Scroll_Lock, KC_SCROLL));
172 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Pause, KC_PAUSE));
173
174 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Shift_R, KC_RSHIFT));
175 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Shift_L, KC_LSHIFT));
176 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Alt_R, KC_RMENU));
177 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Alt_L, KC_LMENU));
178
179 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Insert, KC_INSERT));
180 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Delete, KC_DELETE));
181
182 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Super_L, KC_LWIN));
183 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Super_R, KC_RWIN));
184 keyConversion.insert(XtoOIS_KeyMap::value_type(XK_Menu, KC_APPS));
185
186 static_cast<LinuxInputManager*>(mCreator)->_setKeyboardUsed(true);
187 }
188
189 //-------------------------------------------------------------------//
_initialize()190 void LinuxKeyboard::_initialize()
191 {
192 //Clear our keyboard state buffer
193 memset( &KeyBuffer, 0, 256 );
194 mModifiers = 0;
195
196 if( display ) XCloseDisplay(display);
197 display = 0;
198 window = static_cast<LinuxInputManager*>(mCreator)->_getWindow();
199
200 //Create our local X mListener connection
201 if( !(display = XOpenDisplay(0)) )
202 OIS_EXCEPT(E_General, "LinuxKeyboard::_initialize >> Error opening X!");
203
204 //Set it to recieve Input events
205 if( XSelectInput(display, window, KeyPressMask | KeyReleaseMask) == BadWindow )
206 OIS_EXCEPT(E_General, "LinuxKeyboard::_initialize: X error!");
207
208 if( grabKeyboard )
209 XGrabKeyboard(display,window,True,GrabModeAsync,GrabModeAsync,CurrentTime);
210
211 keyFocusLost = false;
212 }
213
214 //-------------------------------------------------------------------//
~LinuxKeyboard()215 LinuxKeyboard::~LinuxKeyboard()
216 {
217 if( display )
218 {
219 if( grabKeyboard )
220 XUngrabKeyboard(display, CurrentTime);
221
222 XCloseDisplay(display);
223 }
224
225 static_cast<LinuxInputManager*>(mCreator)->_setKeyboardUsed(true);
226 }
227
228 //-------------------------------------------------------------------//
UTF8ToUTF32(unsigned char * buf)229 unsigned int UTF8ToUTF32(unsigned char* buf)
230 {
231 unsigned char &FirstChar = buf[0];
232
233 if(FirstChar < 128)
234 return FirstChar;
235
236 unsigned int val = 0;
237 unsigned int len = 0;
238
239 if((FirstChar & 0xE0) == 0xC0) //2 Chars
240 {
241 len = 2;
242 val = FirstChar & 0x1F;
243 }
244 else if((FirstChar & 0xF0) == 0xE0) //3 Chars
245 {
246 len = 3;
247 val = FirstChar & 0x0F;
248 }
249 else if((FirstChar & 0xF8) == 0xF0) //4 Chars
250 {
251 len = 4;
252 val = FirstChar & 0x07;
253 }
254 else if((FirstChar & 0xFC) == 0xF8) //5 Chars
255 {
256 len = 5;
257 val = FirstChar & 0x03;
258 }
259 else // if((FirstChar & 0xFE) == 0xFC) //6 Chars
260 {
261 len = 6;
262 val = FirstChar & 0x01;
263 }
264
265 for(int i = 1; i < len; i++)
266 val = (val << 6) | (buf[i] & 0x3F);
267
268 return val;
269 }
270
271 //-------------------------------------------------------------------//
isKeyDown(KeyCode key) const272 bool LinuxKeyboard::isKeyDown( KeyCode key ) const
273 {
274 return (KeyBuffer[key]);
275 }
276
277 //-------------------------------------------------------------------//
capture()278 void LinuxKeyboard::capture()
279 {
280 KeySym key;
281 XEvent event;
282 LinuxInputManager* linMan = static_cast<LinuxInputManager*>(mCreator);
283
284 while( XPending(display) > 0 )
285 {
286 XNextEvent(display, &event);
287
288 if(KeyPress == event.type)
289 {
290 unsigned int character = 0;
291
292 if(mTextMode != Off)
293 {
294 unsigned char buffer[6] = {0,0,0,0,0,0};
295 XLookupString(&event.xkey, (char*)buffer, 6, &key, 0);
296
297 if( mTextMode == Unicode )
298 character = UTF8ToUTF32(buffer);
299 else if( mTextMode == Ascii)
300 character = buffer[0];
301 }
302
303 //Mask out the modifier states X11 sets and read again
304 event.xkey.state &= ~ShiftMask;
305 event.xkey.state &= ~LockMask;
306 XLookupString(&event.xkey, 0, 0,&key, 0);
307
308 _injectKeyDown(key, character);
309
310 //Just printing out some debugging info.. to verify all chars are mapped
311 //std::cout << "KEY PRESSED X=" << event.xkey.keycode;
312 //std::cout << "\n KeySym=" << key << std::endl;
313
314 //Check for Alt-Tab
315 if( event.xkey.state & Mod1Mask && key == XK_Tab )
316 linMan->_setGrabState(false);
317 }
318 else if(KeyRelease == event.type)
319 {
320 if(!_isKeyRepeat(event))
321 {
322 //Mask out the modifier states X sets.. or we will get improper values
323 event.xkey.state &= ~ShiftMask;
324 event.xkey.state &= ~LockMask;
325
326 XLookupString(&event.xkey,NULL,0,&key,NULL);
327 _injectKeyUp(key);
328 }
329 }
330 }
331
332 //If grabbing mode is on.. Handle focus lost/gained via Alt-Tab and mouse clicks
333 if( grabKeyboard )
334 {
335 if( linMan->_getGrabState() == false )
336 {
337 // are no longer grabbing
338 if( keyFocusLost == false )
339 {
340 //UnGrab KeyBoard
341 XUngrabKeyboard(display, CurrentTime);
342 keyFocusLost = true;
343 }
344 }
345 else
346 {
347 //We are grabbing - and regained focus
348 if( keyFocusLost == true )
349 {
350 //ReGrab KeyBoard
351 XGrabKeyboard(display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
352 keyFocusLost = false;
353 }
354 }
355 }
356 }
setBuffered(bool buffered)357
358 //-------------------------------------------------------------------//
359 void LinuxKeyboard::setBuffered(bool buffered)
360 {
361 mBuffered = buffered;
362 }
_injectKeyDown(KeySym key,int text)363
364 //-------------------------------------------------------------------//
365 bool LinuxKeyboard::_injectKeyDown( KeySym key, int text )
366 {
367 KeyCode kc = keyConversion[key];
368 KeyBuffer[kc] = 1;
369
370 //Turn on modifier flags
371 if( kc == KC_LCONTROL || kc == KC_RCONTROL)
372 mModifiers |= Ctrl;
373 else if( kc == KC_LSHIFT || kc == KC_RSHIFT )
374 mModifiers |= Shift;
375 else if( kc == KC_LMENU || kc == KC_RMENU )
376 mModifiers |= Alt;
377
378 if( mBuffered && mListener )
379 return mListener->keyPressed(KeyEvent(this,kc,text));
380
381 return true;
382 }
_injectKeyUp(KeySym key)383
384 //-------------------------------------------------------------------//
385 bool LinuxKeyboard::_injectKeyUp( KeySym key )
386 {
387 KeyCode kc = keyConversion[key];
388 KeyBuffer[kc] = 0;
389
390 //Turn off modifier flags
391 if( kc == KC_LCONTROL || kc == KC_RCONTROL)
392 mModifiers &= ~Ctrl;
393 else if( kc == KC_LSHIFT || kc == KC_RSHIFT )
394 mModifiers &= ~Shift;
395 else if( kc == KC_LMENU || kc == KC_RMENU )
396 mModifiers &= ~Alt;
397
398 if( mBuffered && mListener )
399 return mListener->keyReleased(KeyEvent(this, kc, 0));
400
401 return true;
402 }
getAsString(KeyCode kc)403
404 //-------------------------------------------------------------------//
405 const std::string& LinuxKeyboard::getAsString( KeyCode kc )
406 {
407 mGetString = "Unknown";
408 char *temp = 0;
409
410 XtoOIS_KeyMap::iterator i = keyConversion.begin(),
411 e = keyConversion.end();
412
413 for( ; i != e; ++i )
414 {
415 if( i->second == kc )
416 {
417 temp = XKeysymToString(i->first);
418 if( temp )
419 mGetString = temp;
420 break;
421 }
422 }
423
424 return mGetString;
425 }
copyKeyStates(char keys[256]) const426
427 //-------------------------------------------------------------------//
428 void LinuxKeyboard::copyKeyStates( char keys[256] ) const
429 {
430 memcpy( keys, KeyBuffer, 256 );
431 }
432