• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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