Home | History | Annotate | Download | only in mac
      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 
     36 using namespace OIS;
     37 
     38 //-------------------------------------------------------------------//
     39 CocoaKeyboard::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 //-------------------------------------------------------------------//
     55 CocoaKeyboard::~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 //-------------------------------------------------------------------//
     68 void CocoaKeyboard::_initialize()
     69 {
     70 	mModifiers = 0;
     71 }
     72 
     73 //-------------------------------------------------------------------//
     74 bool CocoaKeyboard::isKeyDown( KeyCode key ) const
     75 {
     76 	return [mResponder isKeyDown:key];
     77 }
     78 
     79 //-------------------------------------------------------------------//
     80 void CocoaKeyboard::capture()
     81 {
     82     [mResponder capture];
     83 }
     84 
     85 //-------------------------------------------------------------------//
     86 std::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 //-------------------------------------------------------------------//
    112 void CocoaKeyboard::setBuffered( bool buffered )
    113 {
    114 	mBuffered = buffered;
    115 }
    116 
    117 //-------------------------------------------------------------------//
    118 void 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