Ticket #31974: patch-src_mac_CocoaKeyboard.mm.diff

File patch-src_mac_CocoaKeyboard.mm.diff, 17.3 KB (added by marin.saric@…, 12 years ago)
  • src/mac/CocoaKeyboard.mm

     
     1/*
     2 The zlib/libpng License
     3 
     4 Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
     5 
     6 This software is provided 'as-is', without any express or implied warranty. In no event will
     7 the authors be held liable for any damages arising from the use of this software.
     8 
     9 Permission is granted to anyone to use this software for any purpose, including commercial
     10 applications, and to alter it and redistribute it freely, subject to the following
     11 restrictions:
     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
     24#include "mac/CocoaKeyboard.h"
     25#include "mac/CocoaInputManager.h"
     26#include "mac/CocoaHelpers.h"
     27#include "OISException.h"
     28#include "OISEvents.h"
     29
     30#include <Cocoa/Cocoa.h>
     31
     32#include <list>
     33#include <string>
     34#include <iostream>
     35
     36using namespace OIS;
     37
     38//-------------------------------------------------------------------//
     39CocoaKeyboard::CocoaKeyboard( InputManager* creator, bool buffered, bool repeat )
     40        : Keyboard(creator->inputSystemName(), buffered, 0, creator)
     41{
     42        CocoaInputManager *man = static_cast<CocoaInputManager*>(mCreator);
     43    mResponder = [[CocoaKeyboardView alloc] init];
     44    if(!mResponder)
     45        OIS_EXCEPT( E_General, "CocoaKeyboardView::CocoaKeyboardView >> Error creating event responder" );
     46
     47    [man->_getWindow() makeFirstResponder:mResponder];
     48    [mResponder setUseRepeat:repeat];
     49    [mResponder setOISKeyboardObj:this];
     50
     51        static_cast<CocoaInputManager*>(mCreator)->_setKeyboardUsed(true);
     52}
     53
     54//-------------------------------------------------------------------//
     55CocoaKeyboard::~CocoaKeyboard()
     56{
     57    if (mResponder)
     58    {
     59        [mResponder release];
     60        mResponder = nil;
     61    }
     62
     63        // Free the input managers keyboard
     64        static_cast<CocoaInputManager*>(mCreator)->_setKeyboardUsed(false);
     65}
     66
     67//-------------------------------------------------------------------//
     68void CocoaKeyboard::_initialize()
     69{
     70        mModifiers = 0;
     71}
     72
     73//-------------------------------------------------------------------//
     74bool CocoaKeyboard::isKeyDown( KeyCode key ) const
     75{
     76        return [mResponder isKeyDown:key];
     77}
     78
     79//-------------------------------------------------------------------//
     80void CocoaKeyboard::capture()
     81{
     82    [mResponder capture];
     83}
     84
     85//-------------------------------------------------------------------//
     86std::string& CocoaKeyboard::getAsString( KeyCode key )
     87{
     88        getString = "";
     89   
     90    CGKeyCode deviceKeycode;
     91   
     92    // Convert OIS KeyCode back into device keycode
     93    VirtualtoOIS_KeyMap keyMap = [mResponder keyConversionMap];
     94    for(VirtualtoOIS_KeyMap::iterator it = keyMap.begin(); it != keyMap.end(); ++it)
     95    {
     96        if(it->second == key)
     97            deviceKeycode = it->first;
     98    }
     99
     100    UniChar unicodeString[1];
     101    UniCharCount actualStringLength;
     102
     103    CGEventSourceRef sref = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
     104    CGEventRef ref = CGEventCreateKeyboardEvent(sref, deviceKeycode, true);
     105    CGEventKeyboardGetUnicodeString(ref, sizeof(unicodeString) / sizeof(*unicodeString), &actualStringLength, unicodeString);
     106    getString = unicodeString[0];
     107
     108    return getString;
     109}
     110
     111//-------------------------------------------------------------------//
     112void CocoaKeyboard::setBuffered( bool buffered )
     113{
     114        mBuffered = buffered;
     115}
     116
     117//-------------------------------------------------------------------//
     118void CocoaKeyboard::copyKeyStates( char keys[256] ) const
     119{
     120        [mResponder copyKeyStates:keys];
     121}
     122
     123@implementation CocoaKeyboardView
     124
     125- (id)init
     126{
     127    self = [super init];
     128    if (self) {
     129        [self populateKeyConversion];
     130        memset( &KeyBuffer, 0, 256 );
     131        prevModMask = 0;
     132    }
     133    return self;
     134}
     135
     136- (BOOL)acceptsFirstResponder
     137{
     138    return YES;
     139}
     140
     141- (BOOL)canBecomeKeyView
     142{
     143    return YES;
     144}
     145
     146- (void)setOISKeyboardObj:(CocoaKeyboard *)obj
     147{
     148    oisKeyboardObj = obj;
     149}
     150
     151- (void)capture
     152{
     153        // If not buffered just return, we update the unbuffered automatically
     154        if ( !oisKeyboardObj->buffered() && !oisKeyboardObj->getEventCallback() )
     155                return;
     156
     157        // Run through our event stack
     158        eventStack::iterator cur_it;
     159       
     160        for (cur_it = pendingEvents.begin(); cur_it != pendingEvents.end(); cur_it++)
     161        {
     162                if ( (*cur_it).type() == MAC_KEYDOWN || (*cur_it).type() == MAC_KEYREPEAT)
     163                        oisKeyboardObj->getEventCallback()->keyPressed( (*cur_it).event() );
     164                else if ( (*cur_it).type() == MAC_KEYUP )
     165                        oisKeyboardObj->getEventCallback()->keyReleased( (*cur_it).event() );
     166        }
     167       
     168        pendingEvents.clear();
     169}
     170
     171- (void)setUseRepeat:(bool)repeat
     172{
     173    useRepeat = repeat;
     174}
     175
     176- (bool)isKeyDown:(KeyCode)key
     177{
     178    return KeyBuffer[key];
     179}
     180
     181- (void)copyKeyStates:(char [256])keys
     182{
     183        memcpy( keys, KeyBuffer, 256 );
     184}
     185
     186- (void)populateKeyConversion
     187{
     188        // Virtual Key Map to KeyCode
     189        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x12, KC_1));
     190        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x13, KC_2));
     191        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x14, KC_3));
     192        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x15, KC_4));
     193        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x17, KC_5));
     194        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x16, KC_6));
     195        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x1A, KC_7));
     196        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x1C, KC_8));
     197        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x19, KC_9));
     198        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x1D, KC_0));
     199       
     200        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x33, KC_BACK));  // might be wrong
     201       
     202        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x1B, KC_MINUS));
     203        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x18, KC_EQUALS));
     204        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x31, KC_SPACE));
     205        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x2B, KC_COMMA));
     206        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x2F, KC_PERIOD));
     207       
     208        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x2A, KC_BACKSLASH));
     209        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x2C, KC_SLASH));
     210        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x21, KC_LBRACKET));
     211        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x1E, KC_RBRACKET));
     212       
     213        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x35, KC_ESCAPE));
     214        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x39, KC_CAPITAL));
     215       
     216        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x30, KC_TAB));
     217        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x24, KC_RETURN));  // double check return/enter
     218       
     219        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_colon, KC_COLON));     // no colon?
     220        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x29, KC_SEMICOLON));
     221        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x27, KC_APOSTROPHE));
     222        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x32, KC_GRAVE));
     223       
     224        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x0B, KC_B));
     225        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x00, KC_A));
     226        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x08, KC_C));
     227        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x02, KC_D));
     228        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x0E, KC_E));
     229        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x03, KC_F));
     230        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x05, KC_G));
     231        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x04, KC_H));
     232        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x22, KC_I));
     233        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x26, KC_J));
     234        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x28, KC_K));
     235        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x25, KC_L));
     236        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x2E, KC_M));
     237        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x2D, KC_N));
     238        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x1F, KC_O));
     239        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x23, KC_P));
     240        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x0C, KC_Q));
     241        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x0F, KC_R));
     242        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x01, KC_S));
     243        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x11, KC_T));
     244        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x20, KC_U));
     245        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x09, KC_V));
     246        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x0D, KC_W));
     247        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x07, KC_X));
     248        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x10, KC_Y));
     249        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x06, KC_Z));
     250       
     251        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x7A, KC_F1));
     252        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x78, KC_F2));
     253        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x63, KC_F3));
     254        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x76, KC_F4));
     255        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x60, KC_F5));
     256        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x61, KC_F6));
     257        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x62, KC_F7));
     258        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x64, KC_F8));
     259        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x65, KC_F9));
     260        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x6D, KC_F10));
     261        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x67, KC_F11));
     262        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x6F, KC_F12));
     263        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x69, KC_F13));
     264        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x6B, KC_F14));
     265        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x71, KC_F15));
     266       
     267        // Keypad
     268        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x52, KC_NUMPAD0));
     269        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x53, KC_NUMPAD1));
     270        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x54, KC_NUMPAD2));
     271        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x55, KC_NUMPAD3));
     272        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x56, KC_NUMPAD4));
     273        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x57, KC_NUMPAD5));
     274        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x58, KC_NUMPAD6));
     275        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x59, KC_NUMPAD7));
     276        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x5B, KC_NUMPAD8));
     277        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x5C, KC_NUMPAD9));
     278        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x45, KC_ADD));
     279        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x4E, KC_SUBTRACT));
     280        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x41, KC_DECIMAL));
     281        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x51, KC_NUMPADEQUALS));
     282        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x4B, KC_DIVIDE));
     283        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x43, KC_MULTIPLY));
     284        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x4C, KC_NUMPADENTER));
     285       
     286        // Keypad with numlock off
     287        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x73, KC_NUMPAD7));  // not sure of these
     288        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_KP_Up, KC_NUMPAD8)); // check on a non-laptop
     289        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_KP_Page_Up, KC_NUMPAD9));
     290        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_KP_Left, KC_NUMPAD4));
     291        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_KP_Begin, KC_NUMPAD5));
     292        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_KP_Right, KC_NUMPAD6));
     293        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_KP_End, KC_NUMPAD1));
     294        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_KP_Down, KC_NUMPAD2));
     295        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_KP_Page_Down, KC_NUMPAD3));
     296        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_KP_Insert, KC_NUMPAD0));
     297        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_KP_Delete, KC_DECIMAL));
     298       
     299        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x7E, KC_UP));
     300        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x7D, KC_DOWN));
     301        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x7B, KC_LEFT));
     302        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x7C, KC_RIGHT));
     303       
     304        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x74, KC_PGUP));
     305        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x79, KC_PGDOWN));
     306        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x73, KC_HOME));
     307        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x77, KC_END));
     308       
     309        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_Print, KC_SYSRQ));            // ??
     310        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_Scroll_Lock, KC_SCROLL)); // ??
     311        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_Pause, KC_PAUSE));            // ??
     312       
     313       
     314        //keyConversion.insert(VirtualtoOIS_KeyMap::value_type(XK_Insert, KC_INSERT));    // ??
     315        keyConversion.insert(VirtualtoOIS_KeyMap::value_type(0x75, KC_DELETE)); // del under help key?
     316}
     317
     318- (void)injectEvent:(KeyCode)kc eventTime:(unsigned int)time eventType:(MacEventType)type
     319{
     320    [self injectEvent:kc eventTime:time eventType:type eventText:0];
     321}
     322
     323- (void)injectEvent:(KeyCode)kc eventTime:(unsigned int)time eventType:(MacEventType)type eventText:(unsigned int)txt
     324{
     325        // set to 1 if this is either a keydown or repeat
     326        KeyBuffer[kc] = ( type == MAC_KEYUP ) ? 0 : 1;
     327       
     328        if ( oisKeyboardObj->buffered() && oisKeyboardObj->getEventCallback() )
     329                pendingEvents.push_back( CocoaKeyStackEvent( KeyEvent(oisKeyboardObj, kc, txt), type) );
     330}
     331
     332#pragma mark Key Event overrides
     333- (void)keyDown:(NSEvent *)theEvent
     334{
     335        unsigned short virtualKey = [theEvent keyCode];
     336        unsigned int time = (unsigned int)[theEvent timestamp];
     337        KeyCode kc = keyConversion[virtualKey];
     338   
     339        // Record what kind of text we should pass the KeyEvent
     340        unichar text[10];
     341        char macChar;
     342        if (oisKeyboardObj->getTextTranslation() == OIS::Keyboard::Unicode)
     343        {
     344                // Get string size
     345                NSUInteger stringsize = [[theEvent charactersIgnoringModifiers] length];
     346        [[theEvent charactersIgnoringModifiers] getCharacters:text range:NSMakeRange(0, stringsize)];
     347//              NSLog(@"Characters: %ls", text);
     348//              std::cout << "String length: " << stringsize << std::endl;
     349
     350                if(stringsize > 0)
     351                {
     352                        // For each unicode char, send an event
     353                        for ( unsigned int i = 0; i < stringsize; i++ )
     354                        {
     355                [self injectEvent:kc eventTime:time eventType:MAC_KEYDOWN eventText:(unsigned int)text[i]];
     356                        }
     357                }
     358        }
     359        else if (oisKeyboardObj->getTextTranslation() == OIS::Keyboard::Ascii)
     360        {
     361        macChar = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
     362                [self injectEvent:kc eventTime:time eventType:MAC_KEYDOWN eventText:(unsigned int)macChar];
     363        }
     364        else
     365        {
     366                [self injectEvent:kc eventTime:time eventType:MAC_KEYDOWN];
     367        }
     368}
     369
     370- (void)keyUp:(NSEvent *)theEvent
     371{
     372    unsigned short virtualKey = [theEvent keyCode];
     373
     374        KeyCode kc = keyConversion[virtualKey];
     375    [self injectEvent:kc eventTime:[theEvent timestamp] eventType:MAC_KEYUP];
     376}
     377
     378- (void)flagsChanged:(NSEvent *)theEvent
     379{
     380        NSUInteger mods = [theEvent modifierFlags];
     381       
     382        // Find the changed bit
     383        NSUInteger change = prevModMask ^ mods;
     384        MacEventType newstate = ((change & prevModMask) > 0) ? MAC_KEYUP : MAC_KEYDOWN;
     385        unsigned int time = (unsigned int)[theEvent timestamp];
     386       
     387        //cout << "preMask: " << hex << prevModMask << endl;
     388        //cout << "ModMask: " << hex << mods << endl;
     389        //cout << "Change:  " << hex << (change & prevModMask) << endl << endl;
     390       
     391        // TODO test modifiers on a full keyboard to check if different mask for left/right
     392        switch (change)
     393        {
     394                case (NSShiftKeyMask): // shift
     395                        oisKeyboardObj->_getModifiers() &= (newstate == MAC_KEYDOWN) ? OIS::Keyboard::Shift : ~OIS::Keyboard::Shift;
     396            [self injectEvent:KC_LSHIFT eventTime:time eventType:newstate];
     397                        break;
     398                       
     399                case (NSAlternateKeyMask): // option (alt)
     400                        oisKeyboardObj->_getModifiers() &= (newstate == MAC_KEYDOWN) ? OIS::Keyboard::Alt : -OIS::Keyboard::Alt;
     401            [self injectEvent:KC_LMENU eventTime:time eventType:newstate];
     402                        break;
     403                       
     404                case (NSControlKeyMask): // Ctrl
     405                        oisKeyboardObj->_getModifiers() += (newstate == MAC_KEYDOWN) ? OIS::Keyboard::Ctrl : -OIS::Keyboard::Ctrl;
     406            [self injectEvent:KC_LCONTROL eventTime:time eventType:newstate];
     407                        break;
     408           
     409                case (NSCommandKeyMask): // apple
     410            [self injectEvent:KC_LWIN eventTime:time eventType:newstate];
     411                        break;
     412           
     413                case (NSFunctionKeyMask): // fn key
     414            [self injectEvent:KC_APPS eventTime:time eventType:newstate];
     415                        break;
     416
     417                case (NSAlphaShiftKeyMask): // caps lock
     418            [self injectEvent:KC_CAPITAL eventTime:time eventType:newstate];
     419                        break;
     420        }
     421   
     422    if([theEvent keyCode] == NSClearLineFunctionKey) // numlock
     423        [self injectEvent:KC_NUMLOCK eventTime:time eventType:newstate];
     424       
     425        prevModMask = mods;
     426}
     427
     428- (VirtualtoOIS_KeyMap)keyConversionMap
     429{
     430    return keyConversion;
     431}
     432
     433@end