Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/resource2/src/ois/win32/Win32KeyBoard.cpp @ 5846

Last change on this file since 5846 was 5668, checked in by rgrieder, 15 years ago

Updated OIS library (still 1.2, but CVS version).
There have been some little fixes and support for force feedback on Linux (but this doesn't concern us for now…)

  • Property svn:eol-style set to native
File size: 9.5 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 "Win32/Win32InputManager.h"
24#include "Win32/Win32KeyBoard.h"
25#include "OISException.h"
26#include "OISEvents.h"
27#include <sstream>
28
29using namespace OIS;
30
31//--------------------------------------------------------------------------------------------------//
32Win32Keyboard::Win32Keyboard( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings )
33        : Keyboard(creator->inputSystemName(), buffered, 0, creator)
34{
35        mKeyboard = 0;
36        mDirectInput = pDI;
37        coopSetting = coopSettings;
38
39        //Clear our keyboard state buffer
40        memset( &KeyBuffer, 0, 256 );
41        deadKey = '\0';
42        static_cast<Win32InputManager*>(mCreator)->_setKeyboardUsed(true);
43}
44
45//--------------------------------------------------------------------------------------------------//
46void Win32Keyboard::_initialize()
47{
48        mModifiers = 0;
49        deadKey = '\0';
50
51        if(FAILED(mDirectInput->CreateDevice(GUID_SysKeyboard, &mKeyboard, NULL)))
52                OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> Could not init device!");
53
54        if(FAILED(mKeyboard->SetDataFormat(&c_dfDIKeyboard)))
55                OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> format error!");
56
57        HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle();
58
59        if(FAILED(mKeyboard->SetCooperativeLevel( hwin, coopSetting)))
60                OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> coop error!");
61
62        if( mBuffered )
63        {
64                DIPROPDWORD dipdw;
65                dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
66                dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
67                dipdw.diph.dwObj        = 0;
68                dipdw.diph.dwHow        = DIPH_DEVICE;
69                dipdw.dwData            = KEYBOARD_DX_BUFFERSIZE;
70
71                if (FAILED(mKeyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph )))
72                        OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> buffer error!");
73        }
74
75        HRESULT hr = mKeyboard->Acquire();
76        if(FAILED(hr) && hr != DIERR_OTHERAPPHASPRIO)
77                OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> aquire error!");
78}
79
80//--------------------------------------------------------------------------------------------------//
81Win32Keyboard::~Win32Keyboard()
82{
83        if(mKeyboard)
84        {
85                mKeyboard->Unacquire();
86                mKeyboard->Release();
87                mKeyboard = 0;
88        }
89        static_cast<Win32InputManager*>(mCreator)->_setKeyboardUsed(false);
90}
91
92//--------------------------------------------------------------------------------------------------//
93void Win32Keyboard::capture()
94{
95        if( mBuffered )
96                _readBuffered();
97        else
98                _read();
99}
100
101//--------------------------------------------------------------------------------------------------//
102void Win32Keyboard::_readBuffered()
103{
104        DIDEVICEOBJECTDATA diBuff[KEYBOARD_DX_BUFFERSIZE];
105        DWORD entries = KEYBOARD_DX_BUFFERSIZE;
106        HRESULT hr;
107        //Only one keyboard allowed per app, so static is ok
108        static bool verifyAfterAltTab = false;
109
110        hr = mKeyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
111        if( hr != DI_OK )
112        {
113                hr = mKeyboard->Acquire();
114                if (hr == E_ACCESSDENIED)
115                        verifyAfterAltTab = true;
116
117                while( hr == DIERR_INPUTLOST )
118                        hr = mKeyboard->Acquire();
119
120                return;
121        }
122
123        if( FAILED(hr) )
124                OIS_EXCEPT( E_General, "Win32Keyboard::_readBuffered() >> Problem with Device!" );
125
126        //Update keyboard and modifier states.. And, if mListener, fire events
127        for(unsigned int i = 0; i < entries; ++i )
128        {
129                //If the listener returns false, that means that we are probably deleted...
130                //send no more events and just leave as the this pointer is invalid now...
131                bool ret = true;
132                KeyCode kc = (KeyCode)diBuff[ i ].dwOfs;
133                       
134                //Store result in our keyBuffer too
135                KeyBuffer[kc] = static_cast<unsigned char>(diBuff[ i ].dwData);
136                       
137                if( diBuff[ i ].dwData & 0x80 )
138                {
139                        //Turn on modifier
140                        if( kc == KC_LCONTROL || kc == KC_RCONTROL )
141                                mModifiers |= Ctrl;
142                        else if( kc == KC_LSHIFT || kc == KC_RSHIFT )
143                                mModifiers |= Shift;
144                        else if( kc == KC_LMENU || kc == KC_RMENU )
145                                mModifiers |= Alt;
146
147                        if( mListener )
148                                ret = mListener->keyPressed( KeyEvent( this, kc, _translateText(kc) ) );
149                }
150                else
151                {
152                        //Turn off modifier
153                        if( kc == KC_LCONTROL || kc == KC_RCONTROL )
154                                mModifiers &= ~Ctrl;
155                        else if( kc == KC_LSHIFT || kc == KC_RSHIFT )
156                                mModifiers &= ~Shift;
157                        else if( kc == KC_LMENU || kc == KC_RMENU )
158                                mModifiers &= ~Alt;
159
160                        //Fire off event
161                        if( mListener )
162                                ret = mListener->keyReleased( KeyEvent( this, kc, 0 ) );
163                }
164
165                if(ret == false)
166                        break;
167        }
168
169        // If a lost device/access denied was detected, recover gracefully with new events
170        if(verifyAfterAltTab)
171        {
172                bool ret = true;
173               
174                //Copy old buffer to temp location to compare against
175                unsigned char keyBufferCopy[256];
176                memcpy(keyBufferCopy, KeyBuffer, 256);
177
178                //Update new state
179                _read();
180
181                for (unsigned i = 0; i < 256; i++)
182                {
183                        if (keyBufferCopy[i] != KeyBuffer[i])
184                        {
185                                if (mListener)
186                                {
187                                        if (KeyBuffer[i])
188                                                ret = mListener->keyPressed( KeyEvent( this, (KeyCode)i, _translateText((KeyCode)i) ) );
189                                        else
190                                                ret = mListener->keyReleased( KeyEvent( this, (KeyCode)i, 0 ) );
191                                }
192                        }
193
194                        //If user returned false from callback, return immediately
195                        if(ret == false)
196                                return;
197                }
198
199                verifyAfterAltTab = false;
200        }
201}
202
203//--------------------------------------------------------------------------------------------------//
204void Win32Keyboard::_read()
205{
206    HRESULT  hr = mKeyboard->GetDeviceState( sizeof(KeyBuffer), &KeyBuffer );
207
208        if( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED )
209        {
210                hr = mKeyboard->Acquire();
211                if (hr != DIERR_OTHERAPPHASPRIO)
212                        mKeyboard->GetDeviceState(sizeof(KeyBuffer), &KeyBuffer);
213        }
214
215        //Set Shift, Ctrl, Alt
216        mModifiers = 0;
217        if( isKeyDown(KC_LCONTROL) || isKeyDown(KC_RCONTROL) )
218                mModifiers |= Ctrl;
219        if( isKeyDown(KC_LSHIFT) || isKeyDown(KC_RSHIFT) )
220                mModifiers |= Shift;
221        if( isKeyDown(KC_LMENU) || isKeyDown(KC_RMENU) )
222                mModifiers |= Alt;
223}
224
225//--------------------------------------------------------------------------------------------------//
226int Win32Keyboard::_translateText( KeyCode kc )
227{
228        if( mTextMode == Off )
229                return 0;
230
231        BYTE keyState[256];
232        HKL  layout = GetKeyboardLayout(0);
233        if( GetKeyboardState(keyState) == 0 )
234                return 0;
235
236        unsigned int vk = MapVirtualKeyEx(kc, 3, layout);
237        if( vk == 0 )
238                return 0;
239
240        WCHAR buff[3] = {0};
241        int ascii = ToUnicodeEx(vk, kc, keyState, buff, 3, 0, layout);
242
243        if(ascii == 1 && deadKey != '\0' )
244        {
245                // A dead key is stored and we have just converted a character key
246                // Combine the two into a single character
247                WCHAR wcBuff[3] = {buff[0], deadKey, '\0'};
248                WCHAR out[3];
249               
250                deadKey = '\0';
251                if(FoldStringW(MAP_PRECOMPOSED, (LPWSTR)wcBuff, 3, (LPWSTR)out, 3))
252                        return out[0];
253        }
254        else if (ascii == 1)
255        {       // We have a single character
256                deadKey = '\0';
257                return buff[0];
258        }
259        else if(ascii == 2)
260        {       // Convert a non-combining diacritical mark into a combining diacritical mark
261                // Combining versions range from 0x300 to 0x36F; only 5 (for French) have been mapped below
262                // http://www.fileformat.info/info/unicode/block/combining_diacritical_marks/images.htm
263                switch(buff[0]) {
264                case 0x5E: // Circumflex accent: â
265                        deadKey = 0x302; break;
266                case 0x60: // Grave accent: à
267                        deadKey = 0x300; break;
268                case 0xA8: // Diaeresis: ü
269                        deadKey = 0x308; break;
270                case 0xB4: // Acute accent: é
271                        deadKey = 0x301; break;
272                case 0xB8: // Cedilla: ç
273                        deadKey = 0x327; break;
274                default:
275                        deadKey = buff[0]; break;
276                }
277        }
278
279        return 0;
280}
281
282//--------------------------------------------------------------------------------------------------//
283bool Win32Keyboard::isKeyDown( KeyCode key ) const
284{
285        return (KeyBuffer[key] & 0x80) != 0;
286}
287
288//--------------------------------------------------------------------------------------------------//
289const std::string& Win32Keyboard::getAsString( KeyCode kc )
290{
291        char temp[256];
292
293        DIPROPSTRING prop;
294        prop.diph.dwSize = sizeof(DIPROPSTRING);
295        prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
296        prop.diph.dwObj = static_cast<DWORD>(kc);
297        prop.diph.dwHow = DIPH_BYOFFSET;
298
299        if ( SUCCEEDED( mKeyboard->GetProperty( DIPROP_KEYNAME, &prop.diph ) ) )
300        {
301                // convert the WCHAR in "wsz" to multibyte
302                if ( WideCharToMultiByte( CP_ACP, 0, prop.wsz, -1, temp, sizeof(temp), NULL, NULL) )
303                        return mGetString.assign( temp );
304        }
305
306        std::stringstream ss;
307        ss << "Key_" << (int)kc;
308        return mGetString.assign( ss.str() );
309}
310
311//--------------------------------------------------------------------------------------------------//
312void Win32Keyboard::copyKeyStates( char keys[256] ) const
313{
314        for(int i = 0; i < 256; ++i)
315                keys[i] = KeyBuffer[i] > 0; //Normalise the DX values (0x80)
316}
317
318//--------------------------------------------------------------------------------------------------//
319void Win32Keyboard::setBuffered(bool buffered)
320{
321        if( buffered != mBuffered )
322        {
323                if(mKeyboard)
324                {
325                        mKeyboard->Unacquire();
326                        mKeyboard->Release();
327                        mKeyboard = 0;
328                }
329               
330                mBuffered = buffered;
331                _initialize();
332        }
333}
Note: See TracBrowser for help on using the repository browser.