Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2928 was 2710, checked in by rgrieder, 16 years ago

Merged buildsystem3 containing buildsystem2 containing Adi's buildsystem branch back to the trunk.
Please update the media directory if you were not using buildsystem3 before.

  • Property svn:eol-style set to native
File size: 15.8 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 ) const
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        {               XNextEvent(display, &event);            if( KeyPress == event.type )
306                {
307                        unsigned int character = 0;
308
309                        if( mTextMode != Off )
310                        {
311                                unsigned char buffer[6] = {0,0,0,0,0,0};
312                                XLookupString(&event.xkey, (char*)buffer, 6, &key, 0);
313
314                                if( mTextMode == Unicode )
315                                        character = UTF8ToUTF32(buffer);
316                                else if( mTextMode == Ascii)
317                                        character = buffer[0];
318                        }
319
320                        //Mask out the modifier states X11 sets and read again
321                        event.xkey.state &= ~ShiftMask;
322                        event.xkey.state &= ~LockMask;
323                        XLookupString(&event.xkey, 0, 0,&key, 0);
324
325                        _injectKeyDown(key, character);
326
327                        //Just printing out some debugging info.. to verify all chars are mapped
328                        //std::cout << "KEY PRESSED X=" << event.xkey.keycode;
329                        //std::cout << "\n KeySym=" << key << std::endl;
330
331                        //Check for Alt-Tab
332                        if( event.xkey.state & Mod1Mask && key == XK_Tab )
333                                linMan->_setGrabState(false);
334                }               else if( KeyRelease == event.type )
335                {
336                        //Mask out the modifier states X sets.. or we will get improper values
337                        event.xkey.state &= ~ShiftMask;
338                        event.xkey.state &= ~LockMask;
339
340                        //Else, it is a valid key release
341                        XLookupString(&event.xkey,NULL,0,&key,NULL);
342                        _injectKeyUp(key);              }
343        }
344
345        //If grabbing mode is on.. Handle focus lost/gained via Alt-Tab and mouse clicks
346        if( grabKeyboard )
347        {
348                if( linMan->_getGrabState() == false )
349                {
350                        // are no longer grabbing
351                        if( keyFocusLost == false )
352                        {
353                                //UnGrab KeyBoard
354                                XUngrabKeyboard(display, CurrentTime);
355                                keyFocusLost = true;
356                        }
357                }
358                else
359                {
360                        //We are grabbing - and regained focus
361                        if( keyFocusLost == true )
362                        {
363                                //ReGrab KeyBoard
364                                XGrabKeyboard(display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
365                                keyFocusLost = false;
366                        }
367                }
368        }
369}
370
371//-------------------------------------------------------------------//
372void LinuxKeyboard::setBuffered(bool buffered)
373{
374        mBuffered = buffered;
375}
376
377//-------------------------------------------------------------------//
378bool LinuxKeyboard::_injectKeyDown( KeySym key, int text )
379{
380        KeyCode kc = keyConversion[key];
381        KeyBuffer[kc] = 1;
382
383        //Turn on modifier flags
384        if( kc == KC_LCONTROL || kc == KC_RCONTROL)
385                mModifiers |= Ctrl;
386        else if( kc == KC_LSHIFT || kc == KC_RSHIFT )
387                mModifiers |= Shift;
388        else if( kc == KC_LMENU || kc == KC_RMENU )
389                mModifiers |= Alt;
390
391        if( mBuffered && mListener )
392                return mListener->keyPressed(KeyEvent(this,kc,text));
393
394        return true;
395}
396
397//-------------------------------------------------------------------//
398bool LinuxKeyboard::_injectKeyUp( KeySym key )
399{
400        KeyCode kc = keyConversion[key];
401        KeyBuffer[kc] = 0;
402
403        //Turn off modifier flags
404        if( kc == KC_LCONTROL || kc == KC_RCONTROL)
405                mModifiers &= ~Ctrl;
406        else if( kc == KC_LSHIFT || kc == KC_RSHIFT )
407                mModifiers &= ~Shift;
408        else if( kc == KC_LMENU || kc == KC_RMENU )
409                mModifiers &= ~Alt;
410
411        if( mBuffered && mListener )
412                return mListener->keyReleased(KeyEvent(this, kc, 0));
413
414        return true;
415}
416
417//-------------------------------------------------------------------//
418const std::string& LinuxKeyboard::getAsString( KeyCode kc )
419{
420        mGetString = "Unknown";
421        char *temp = 0;
422
423        XtoOIS_KeyMap::iterator i = keyConversion.begin(),
424                                e = keyConversion.end();
425
426        for( ; i != e; ++i )
427        {
428                if( i->second == kc )
429                {
430                        temp = XKeysymToString(i->first);
431                        if( temp )
432                                mGetString = temp;
433                        break;
434                }
435        }
436
437        return mGetString;
438}
439
440//-------------------------------------------------------------------//
441void LinuxKeyboard::copyKeyStates( char keys[256] ) const
442{
443        memcpy( keys, KeyBuffer, 256 );
444}
Note: See TracBrowser for help on using the repository browser.