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 434