• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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