Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/ois/linux/LinuxKeyboard.cpp @ 1344

Last change on this file since 1344 was 1219, checked in by rgrieder, 17 years ago

merged input branch back to trunk. Not yet tested on tardis

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