Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/ois/win32/Win32KeyBoard.cpp @ 2748

Last change on this file since 2748 was 1505, checked in by rgrieder, 16 years ago

f* svn: It doesn't even inform you if you attempt to set a non existing property. It is svn:eol-style and not eol-style when using the command by the way…

  • Property svn:eol-style set to native
File size: 9.6 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        unsigned char buff[3] = {0,0,0};
241        int ascii = ToAsciiEx(vk, kc, keyState, (LPWORD) buff, 0, layout);
242        //WCHAR wide[3];
243        //int ascii = ToUnicodeEx(vk, kc, keyState, wide, 3, 0, layout);
244        if(ascii == 1 && deadKey != '\0' )
245        {
246                // A dead key is stored and we have just converted a character key
247                // Combine the two into a single character
248                WCHAR wcBuff[3] = {buff[0], deadKey, '\0'};
249                WCHAR out[3];
250               
251                deadKey = '\0';
252                if(FoldStringW(MAP_PRECOMPOSED, (LPWSTR)wcBuff, 3, (LPWSTR)out, 3))
253                        return out[0];
254        }
255        else if (ascii == 1)
256        {       // We have a single character
257                deadKey = '\0';
258                return buff[0];
259        }
260        else if(ascii == 2)
261        {       // Convert a non-combining diacritical mark into a combining diacritical mark
262                // Combining versions range from 0x300 to 0x36F; only 5 (for French) have been mapped below
263                // http://www.fileformat.info/info/unicode/block/combining_diacritical_marks/images.htm
264                switch(buff[0]) {
265                case 0x5E: // Circumflex accent: â
266                        deadKey = 0x302; break;
267                case 0x60: // Grave accent: à
268                        deadKey = 0x300; break;
269                case 0xA8: // Diaeresis: ü
270                        deadKey = 0x308; break;
271                case 0xB4: // Acute accent: é
272                        deadKey = 0x301; break;
273                case 0xB8: // Cedilla: ç
274                        deadKey = 0x327; break;
275                default:
276                        deadKey = buff[0]; break;
277                }
278        }
279
280        return 0;
281}
282
283//--------------------------------------------------------------------------------------------------//
284bool Win32Keyboard::isKeyDown( KeyCode key ) const
285{
286        return (KeyBuffer[key] & 0x80) != 0;
287}
288
289//--------------------------------------------------------------------------------------------------//
290const std::string& Win32Keyboard::getAsString( KeyCode kc )
291{
292        char temp[256];
293
294        DIPROPSTRING prop;
295        prop.diph.dwSize = sizeof(DIPROPSTRING);
296        prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
297        prop.diph.dwObj = static_cast<DWORD>(kc);
298        prop.diph.dwHow = DIPH_BYOFFSET;
299
300        if ( SUCCEEDED( mKeyboard->GetProperty( DIPROP_KEYNAME, &prop.diph ) ) )
301        {
302                // convert the WCHAR in "wsz" to multibyte
303                if ( WideCharToMultiByte( CP_ACP, 0, prop.wsz, -1, temp, sizeof(temp), NULL, NULL) )
304                        return mGetString.assign( temp );
305        }
306
307        std::stringstream ss;
308        ss << "Key_" << (int)kc;
309        return mGetString.assign( ss.str() );
310}
311
312//--------------------------------------------------------------------------------------------------//
313void Win32Keyboard::copyKeyStates( char keys[256] ) const
314{
315        for(int i = 0; i < 256; ++i)
316                keys[i] = KeyBuffer[i] > 0; //Normalise the DX values (0x80)
317}
318
319//--------------------------------------------------------------------------------------------------//
320void Win32Keyboard::setBuffered(bool buffered)
321{
322        if( buffered != mBuffered )
323        {
324                if(mKeyboard)
325                {
326                        mKeyboard->Unacquire();
327                        mKeyboard->Release();
328                        mKeyboard = 0;
329                }
330               
331                mBuffered = buffered;
332                _initialize();
333        }
334}
Note: See TracBrowser for help on using the repository browser.