Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/external/ois/linux/LinuxKeyboard.cpp

Last change on this file was 12022, checked in by patricwi, 6 years ago

Set locale to minimum locale C and not user-preferred locale, as CEGUI 0.8 requires locale set to C

  • Property svn:eol-style set to native
File size: 15.3 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)
36        : Keyboard(creator->inputSystemName(), buffered, 0, creator)
37{
38        setlocale(LC_CTYPE, "C"); //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//-------------------------------------------------------------------//
190void 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//-------------------------------------------------------------------//
215LinuxKeyboard::~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//-------------------------------------------------------------------//
229unsigned 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//-------------------------------------------------------------------//
272bool LinuxKeyboard::isKeyDown( KeyCode key ) const
273{
274        return (KeyBuffer[key]);
275}
276
277//-------------------------------------------------------------------//
278void 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}
357
358//-------------------------------------------------------------------//
359void LinuxKeyboard::setBuffered(bool buffered)
360{
361        mBuffered = buffered;
362}
363
364//-------------------------------------------------------------------//
365bool 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}
383
384//-------------------------------------------------------------------//
385bool 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}
403
404//-------------------------------------------------------------------//
405const 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}
426
427//-------------------------------------------------------------------//
428void LinuxKeyboard::copyKeyStates( char keys[256] ) const
429{
430        memcpy( keys, KeyBuffer, 256 );
431}
Note: See TracBrowser for help on using the repository browser.