Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2366 was 1786, checked in by rgrieder, 16 years ago

Corrected types when using 'const Type' constants

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