1 /*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.cs.princeton.edu/
7 http://soundlab.cs.princeton.edu/
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
27 // desc: refactored HID joystick, keyboard, mouse support
29 // author: Spencer Salazar (ssalazar@cs.princeton.edu)
31 //-----------------------------------------------------------------------------
33 #include "chuck_def.h"
34 #include "chuck_errmsg.h"
36 #include "hidio_sdl.h"
45 const t_CKUINT CK_HID_DEV_NONE
= 0;
46 const t_CKUINT CK_HID_DEV_JOYSTICK
= 1;
47 const t_CKUINT CK_HID_DEV_MOUSE
= 2;
48 const t_CKUINT CK_HID_DEV_KEYBOARD
= 3;
49 const t_CKUINT CK_HID_DEV_WIIREMOTE
= 4;
50 const t_CKUINT CK_HID_DEV_TILTSENSOR
= 5;
51 const t_CKUINT CK_HID_DEV_TABLET
= 6;
52 const t_CKUINT CK_HID_DEV_COUNT
= 7;
55 const t_CKUINT CK_HID_JOYSTICK_AXIS
= 0;
56 const t_CKUINT CK_HID_BUTTON_DOWN
= 1;
57 const t_CKUINT CK_HID_BUTTON_UP
= 2;
58 const t_CKUINT CK_HID_JOYSTICK_HAT
= 3;
59 const t_CKUINT CK_HID_JOYSTICK_BALL
= 4;
60 const t_CKUINT CK_HID_MOUSE_MOTION
= 5;
61 const t_CKUINT CK_HID_MOUSE_WHEEL
= 6;
62 const t_CKUINT CK_HID_DEVICE_CONNECTED
= 7;
63 const t_CKUINT CK_HID_DEVICE_DISCONNECTED
= 8;
64 const t_CKUINT CK_HID_ACCELEROMETER
= 9;
65 const t_CKUINT CK_HID_WIIREMOTE_IR
= 10;
66 const t_CKUINT CK_HID_LED
= 11;
67 const t_CKUINT CK_HID_FORCE_FEEDBACK
= 12;
68 const t_CKUINT CK_HID_SPEAKER
= 13;
69 const t_CKUINT CK_HID_TABLET_PRESSURE
= 14;
70 const t_CKUINT CK_HID_TABLET_MOTION
= 15;
71 const t_CKUINT CK_HID_TABLET_ROTATION
= 16;
72 const t_CKUINT CK_HID_MSG_COUNT
= 17;
74 #if defined(__PLATFORM_MACOSX__) && !defined(__CHIP_MODE__)
75 #pragma mark OS X General HID support
77 /* TODO: ***********************************************************************
79 Make Joystick/Mouse/Keyboard_open/_close thread safe (i.e., do all ->configure
80 and ->startQueue calls on the Hid thread). *** DONE
82 Make ->disconnect delete the element list *** worked around
84 Make Keyboard, Mouse dis/reattachment work *** DONE
88 *******************************************************************************/
91 #include <mach/mach.h>
92 #include <mach/mach_error.h>
93 #include <IOKit/IOKitLib.h>
94 #include <IOKit/IOCFPlugIn.h>
95 #include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
96 #include <IOKit/hid/IOHIDLib.h>
97 #include <IOKit/hid/IOHIDKeys.h>
98 #include <IOKit/IOMessage.h>
99 #include <CoreFoundation/CoreFoundation.h>
100 #include <Carbon/Carbon.h>
102 // check for OS X 10.4/CGEvent
103 #include <AvailabilityMacros.h>
104 #undef MAC_OS_X_VERSION_MIN_REQUIRED
105 #undef MAC_OS_X_VERSION_MAX_ALLOWED
106 #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_3
107 #define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_4
108 #include <ApplicationServices/ApplicationServices.h>
110 #define __CK_HID_CURSOR_TRACK__
114 #undef __CK_HID_CURSOR_TRACK__
117 #ifdef __CK_HID_WIIREMOTE__
118 #include <IOBluetooth/IOBluetoothUserLib.h>
119 #include "util_buffers.h"
120 #endif // __CK_HID_WIIREMOTE__
140 template< typename _Tp
, typename _Alloc
= allocator
< _Tp
> >
141 class xvector
: public vector
< _Tp
, _Alloc
>, public lockable
145 template <typename _Key
, typename _Tp
, typename _Compare
= less
<_Key
>,
146 typename _Alloc
= allocator
<pair
<const _Key
, _Tp
> > >
147 class xmultimap
: public multimap
< _Key
, _Tp
, _Compare
, _Alloc
>, public lockable
151 class OSX_Device
: public lockable
159 virtual ~OSX_Device() {}
161 virtual void open() {};
162 virtual void close() {};
164 t_CKUINT refcount
; // incremented on open, decremented on close
167 class OSX_Hid_Device_Element
170 OSX_Hid_Device_Element()
175 usage
= usage_page
= 0;
180 IOHIDElementCookie cookie
;
193 class OSX_Hid_Device
: public OSX_Device
198 configed
= preconfiged
= FALSE
;
199 plugInInterface
= NULL
;
202 strncpy( name
, "Device", 256 );
205 usage
= usage_page
= 0;
212 hidProperties
= NULL
;
213 removal_notification
= NULL
;
214 vendorID
= productID
= locationID
= NULL
;
215 manufacturer
= product
= NULL
;
223 t_CKINT
preconfigure( io_object_t ioHIDDeviceObject
);
225 void enumerate_elements( CFArrayRef cfElements
);
228 t_CKBOOL
is_connected() const;
229 t_CKBOOL
is_same_as( io_object_t ioHIDDeviceObject
) const;
233 IOCFPlugInInterface
** plugInInterface
;
234 IOHIDDeviceInterface
** interface
; // device interface
235 IOHIDQueueInterface
** queue
; // device event queue
239 // uniquely identifying information
240 /* For ChucK's purposes, HID devices are uniquely identified by the tuple of
241 (USB device location, vendor ID, product ID,
242 manufacturer name, product name ) */
243 CFNumberRef locationID
;
244 CFNumberRef vendorID
;
245 CFNumberRef productID
;
246 CFStringRef manufacturer
;
249 t_CKBOOL preconfiged
, configed
;
256 map
< IOHIDElementCookie
, OSX_Hid_Device_Element
* > * elements
;
258 /* Note: setting any of these to -1 informs the element enumerating
259 method that we are not interested in that particular element type */
265 /* outputs are stored in a map of vectors of OSX_Hid_Device_Elements
266 Thus if ( *outputs )[CK_HID_OUTPUT_TYPE] != NULL &&
267 ( *outputs )[CK_HID_OUTPUT_TYPE]->size() > n,
268 ( *outputs )[CK_HID_OUTPUT_TYPE]->at( n ) is the nth output of type
269 CK_HID_OUTPUT_TYPE. */
270 map
< unsigned int, vector
< OSX_Hid_Device_Element
* > * > * outputs
;
272 CFRunLoopSourceRef eventSource
;
274 CFMutableDictionaryRef hidProperties
;
276 io_object_t removal_notification
;
278 const static t_CKINT event_queue_size
= 50;
279 // queues use wired kernel memory so should be set to as small as possible
280 // but should account for the maximum possible events in the queue
281 // USB updates will likely occur at 100 Hz so one must account for this rate
282 // if states change quickly (updates are only posted on state changes)
293 xvector
< OSX_Hid_Device
* > * v
;
294 xvector
< OSX_Hid_Device
* >::size_type index
;
297 #pragma mark global variables
299 // hid run loop (event dispatcher)
300 static CFRunLoopRef rlHid
= NULL
;
301 // special hid run loop mode (limits events to hid device events only)
302 //static const CFStringRef kCFRunLoopChuckHidMode = CFSTR( "ChucKHid" );
303 static const CFStringRef kCFRunLoopChuckHidMode
= kCFRunLoopDefaultMode
;
305 // general hid callback for device events
306 static void Hid_callback( void * target
, IOReturn result
,
307 void * refcon
, void * sender
);
309 // CFRunLoop source for open/close device operations
310 static CFRunLoopSourceRef hidOpSource
= NULL
;
311 // cbuffer for open/close device operations
312 static CBufferSimple
* hid_operation_buffer
= NULL
;
313 // callback for open/close device operations
314 static void Hid_do_operation( void * info
);
316 // IO iterator for new hid devices
317 // we only keep track of this so we can release it later
318 io_iterator_t hid_iterator
= NULL
;
320 // notification port for device add/remove events
321 static IONotificationPortRef newDeviceNotificationPort
= NULL
;
322 // callback for new devices
323 static void Hid_new_devices( void * refcon
, io_iterator_t iterator
);
324 // callback for device removal
325 static void Hid_device_removed( void * refcon
, io_service_t service
,
326 natural_t messageType
, void * messageArgument
);
328 /* the mutexes should be acquired whenever making changes to the corresponding
329 vectors or accessing them from a non-hid thread after the hid thread has
331 static xvector
< OSX_Hid_Device
* > * joysticks
= NULL
;
332 static xvector
< OSX_Hid_Device
* > * mice
= NULL
;
333 static xvector
< OSX_Hid_Device
* > * keyboards
= NULL
;
335 static xmultimap
< string
, OSX_Hid_Device
* > * joystick_names
= NULL
;
336 static xmultimap
< string
, OSX_Hid_Device
* > * mouse_names
= NULL
;
337 static xmultimap
< string
, OSX_Hid_Device
* > * keyboard_names
= NULL
;
339 // has hid been initialized?
340 static t_CKBOOL g_hid_init
= FALSE
;
341 // table to translate keys to ASCII
342 static t_CKBYTE g_hid_key_table
[256];
344 // cursor track stuff
345 #ifdef __CK_HID_CURSOR_TRACK__
346 static t_CKINT cursorX
= 0;
347 static t_CKINT cursorY
= 0;
348 static t_CKFLOAT scaledCursorX
= 0;
349 static t_CKFLOAT scaledCursorY
= 0;
350 static CFRunLoopRef rlCursorTrack
= NULL
;
351 static t_CKBOOL g_ct_go
= FALSE
;
352 #endif // __CK_HID_CURSOR_TRACK__
354 #ifdef __CK_HID_WIIREMOTE__
356 static CFRunLoopSourceRef cfrlWiiRemoteSource
= NULL
;
357 static void WiiRemote_cfrl_callback( void * info
);
360 t_CKINT
OSX_Hid_Device::preconfigure( io_object_t ioHIDDeviceObject
)
362 // can only be called in Hid thread, or if the hid thread hasnt started
363 assert( rlHid
== CFRunLoopGetCurrent() || rlHid
== NULL
);
370 case CK_HID_DEV_NONE
:
371 strncpy( name
, "Human Interface Device", 256 );
378 case CK_HID_DEV_JOYSTICK
:
379 strncpy( name
, "Joystick", 256 );
386 case CK_HID_DEV_MOUSE
:
387 strncpy( name
, "Mouse", 256 );
394 case CK_HID_DEV_KEYBOARD
:
395 strncpy( name
, "Keyboard", 256 );
403 // retrieve a dictionary of device properties
404 kern_return_t kern_result
= IORegistryEntryCreateCFProperties( ioHIDDeviceObject
,
409 if( kern_result
!= KERN_SUCCESS
|| hidProperties
== NULL
)
411 hidProperties
= NULL
;
415 // get the device name, and copy it into the device record
416 CFTypeRef refCF
= CFDictionaryGetValue( hidProperties
,
417 CFSTR( kIOHIDProductKey
) );
419 CFStringGetCString( ( CFStringRef
)refCF
, name
, 256,
420 kCFStringEncodingASCII
);
422 // retrieve uniquely identifying information
425 locationID
= ( CFNumberRef
) CFDictionaryGetValue( hidProperties
,
426 CFSTR( kIOHIDLocationIDKey
) );
428 CFRetain( locationID
);
433 vendorID
= ( CFNumberRef
) CFDictionaryGetValue( hidProperties
,
434 CFSTR( kIOHIDVendorIDKey
) );
436 CFRetain( vendorID
);
441 productID
= ( CFNumberRef
) CFDictionaryGetValue( hidProperties
,
442 CFSTR( kIOHIDProductIDKey
) );
444 CFRetain( productID
);
449 manufacturer
= ( CFStringRef
) CFDictionaryGetValue( hidProperties
,
450 CFSTR( kIOHIDManufacturerKey
) );
452 CFRetain( manufacturer
);
457 product
= ( CFStringRef
) CFDictionaryGetValue( hidProperties
,
458 CFSTR( kIOHIDProductKey
) );
463 // create plugin interface
466 result
= IOCreatePlugInInterfaceForService( ioHIDDeviceObject
,
467 kIOHIDDeviceUserClientTypeID
,
468 kIOCFPlugInInterfaceID
,
472 if( result
!= kIOReturnSuccess
)
474 CFRelease( hidProperties
);
475 hidProperties
= NULL
;
479 #ifdef __LITTLE_ENDIAN__
480 /* MacBooks and MacBook Pros have some sort of "phantom" trackpad, which
481 shows up in the HID registry and claims to have no wheels. The device
482 name is usually Trackpad with the manufacturer being Apple. This may
483 disable legitimate Trackpads, but hopefully not... */
484 if( type
== CK_HID_DEV_MOUSE
&& strncmp( "Trackpad", name
, 256 ) == 0 )
486 refCF
= CFDictionaryGetValue( hidProperties
,
487 CFSTR( kIOHIDManufacturerKey
) );
489 CFStringCompare( ( CFStringRef
) refCF
, CFSTR( "Apple" ), 0 ) == 0 )
495 // this is the "phantom" trackpad
497 // iterate through the element map, delete device element records
498 map
< IOHIDElementCookie
, OSX_Hid_Device_Element
* >::iterator iter
, end
;
499 end
= elements
->end();
500 for( iter
= elements
->begin(); iter
!= end
; iter
++ )
507 ( *queue
)->dispose( queue
);
508 ( *queue
)->Release( queue
);
514 ( *interface
)->close( interface
);
515 ( *interface
)->Release( interface
);
523 #endif // __LITTLE_ENDIAN__
525 // register callback for removal notification, among a few other things
526 result
= IOServiceAddInterestNotification( newDeviceNotificationPort
,
531 &removal_notification
);
538 t_CKINT
OSX_Hid_Device::configure()
540 // can only be called in Hid thread, or if the hid thread hasnt started
541 assert( rlHid
== NULL
|| rlHid
== CFRunLoopGetCurrent() );
549 EM_log( CK_LOG_INFO
, "hid: configuring %s", name
);
551 // create the device interface
552 HRESULT plugInResult
= S_OK
;
553 plugInResult
= (*plugInInterface
)->QueryInterface( plugInInterface
,
554 CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID
),
555 ( LPVOID
* ) &interface
);
556 (*plugInInterface
)->Release( plugInInterface
);
557 plugInInterface
= NULL
;
558 if( plugInResult
!= S_OK
)
560 CFRelease( hidProperties
);
561 hidProperties
= NULL
;
565 // open the interface
567 result
= (*interface
)->open( interface
, 0 );
568 if( result
!= kIOReturnSuccess
)
570 CFRelease( hidProperties
);
571 hidProperties
= NULL
;
572 (*interface
)->Release( interface
);
577 // create an event queue, so we dont have to poll individual elements
578 queue
= (*interface
)->allocQueue( interface
);
581 CFRelease( hidProperties
);
582 hidProperties
= NULL
;
583 (*interface
)->close( interface
);
584 (*interface
)->Release( interface
);
589 result
= (*queue
)->create( queue
, 0, event_queue_size
);
590 if( result
!= kIOReturnSuccess
)
592 CFRelease( hidProperties
);
593 hidProperties
= NULL
;
594 (*queue
)->Release( queue
);
596 (*interface
)->close( interface
);
597 (*interface
)->Release( interface
);
602 // set up the call back mechanism
603 result
= (*queue
)->createAsyncEventSource( queue
, &eventSource
);
604 if( result
!= kIOReturnSuccess
)
606 CFRelease( hidProperties
);
607 hidProperties
= NULL
;
608 (*queue
)->dispose( queue
);
609 (*queue
)->Release( queue
);
611 (*interface
)->close( interface
);
612 (*interface
)->Release( interface
);
617 result
= (*queue
)->setEventCallout( queue
, Hid_callback
, NULL
, this );
618 if( result
!= kIOReturnSuccess
)
620 CFRelease( hidProperties
);
621 hidProperties
= NULL
;
622 (*queue
)->dispose( queue
);
623 (*queue
)->Release( queue
);
625 (*interface
)->close( interface
);
626 (*interface
)->Release( interface
);
631 if( hidProperties
!= NULL
)
633 if( elements
== NULL
)
635 // retrieve the array of elements...
636 CFTypeRef refCF
= CFDictionaryGetValue( hidProperties
,
637 CFSTR( kIOHIDElementKey
) );
640 CFRelease( hidProperties
);
641 hidProperties
= NULL
;
642 (*queue
)->dispose( queue
);
643 (*queue
)->Release( queue
);
645 (*interface
)->close( interface
);
646 (*interface
)->Release( interface
);
651 // ...allocate space for element records...
652 elements
= new map
< IOHIDElementCookie
, OSX_Hid_Device_Element
* >;
657 // ...and parse the element array recursively
658 enumerate_elements( ( CFArrayRef
) refCF
);
663 map
< IOHIDElementCookie
, OSX_Hid_Device_Element
* >::iterator iter
, end
;
664 end
= elements
->end();
665 for( iter
= elements
->begin(); iter
!= end
; iter
++ )
666 ( *queue
)->addElement( queue
, iter
->second
->cookie
, 0 );
669 CFRelease( hidProperties
);
670 hidProperties
= NULL
;
678 //------------------------------------------------------------------------------
679 // name: enumerate_device_elements
680 // desc: perform depth depth first search on potentially nested arrays of
681 // elements on the device, add found elements to the vector
682 //------------------------------------------------------------------------------
683 void OSX_Hid_Device::enumerate_elements( CFArrayRef cfElements
)
685 // can only be called in Hid thread, or if the hid thread hasnt started
686 assert( rlHid
== NULL
|| rlHid
== CFRunLoopGetCurrent() );
689 CFDictionaryRef element_dictionary
;
690 OSX_Hid_Device_Element
* element
;
691 t_CKINT usage_page
, usage
, element_type
;
694 CFIndex i
, len
= CFArrayGetCount( cfElements
);
695 for( i
= 0; i
< len
; i
++ )
697 // retrieve the dictionary of the ith element's data
698 refCF
= CFArrayGetValueAtIndex( cfElements
, i
);
699 element_dictionary
= ( CFDictionaryRef
) refCF
;
702 refCF
= CFDictionaryGetValue( element_dictionary
,
703 CFSTR( kIOHIDElementTypeKey
) );
705 !CFNumberGetValue( ( CFNumberRef
) refCF
, kCFNumberLongType
,
709 // get element usage page
710 refCF
= CFDictionaryGetValue( element_dictionary
,
711 CFSTR( kIOHIDElementUsagePageKey
) );
713 !CFNumberGetValue( ( CFNumberRef
) refCF
, kCFNumberLongType
,
718 refCF
= CFDictionaryGetValue( element_dictionary
,
719 CFSTR( kIOHIDElementUsageKey
) );
721 !CFNumberGetValue( ( CFNumberRef
) refCF
, kCFNumberLongType
,
725 switch( element_type
)
727 case kIOHIDElementTypeInput_Misc
:
728 case kIOHIDElementTypeInput_Button
:
729 case kIOHIDElementTypeInput_Axis
:
730 case kIOHIDElementTypeInput_ScanCodes
:
731 // an input of some sort
734 case kHIDPage_GenericDesktop
:
740 case kHIDUsage_GD_Rx
:
741 case kHIDUsage_GD_Ry
:
742 case kHIDUsage_GD_Rz
:
743 case kHIDUsage_GD_Slider
:
744 case kHIDUsage_GD_Dial
:
749 element
= new OSX_Hid_Device_Element
;
752 if( this->type
== CK_HID_DEV_JOYSTICK
)
753 element
->type
= CK_HID_JOYSTICK_AXIS
;
755 element
->type
= CK_HID_MOUSE_MOTION
;
756 element
->usage
= usage
;
757 element
->usage_page
= usage_page
;
759 refCF
= CFDictionaryGetValue( element_dictionary
,
760 CFSTR( kIOHIDElementCookieKey
) );
762 !CFNumberGetValue( ( CFNumberRef
) refCF
, kCFNumberLongType
, &element
->cookie
) )
768 refCF
= CFDictionaryGetValue( element_dictionary
,
769 CFSTR( kIOHIDElementMinKey
) );
771 !CFNumberGetValue( ( CFNumberRef
) refCF
, kCFNumberLongType
, &element
->min
) )
777 refCF
= CFDictionaryGetValue( element_dictionary
,
778 CFSTR( kIOHIDElementMaxKey
) );
780 !CFNumberGetValue( ( CFNumberRef
) refCF
, kCFNumberLongType
, &element
->max
) )
786 result
= (*queue
)->addElement( queue
, element
->cookie
, 0 );
787 if( result
!= kIOReturnSuccess
)
793 EM_log( CK_LOG_FINE
, "adding axis %d", axes
);
795 (*elements
)[element
->cookie
] = element
;
800 case kHIDUsage_GD_Wheel
:
805 element
= new OSX_Hid_Device_Element
;
807 element
->num
= wheels
;
808 if( this->type
== CK_HID_DEV_JOYSTICK
)
809 element
->type
= CK_HID_JOYSTICK_AXIS
;
811 element
->type
= CK_HID_MOUSE_WHEEL
;
812 element
->usage
= usage
;
813 element
->usage_page
= usage_page
;
815 refCF
= CFDictionaryGetValue( element_dictionary
,
816 CFSTR( kIOHIDElementCookieKey
) );
818 !CFNumberGetValue( ( CFNumberRef
) refCF
,
826 result
= (*queue
)->addElement( queue
,
829 if( result
!= kIOReturnSuccess
)
835 EM_log( CK_LOG_FINE
, "adding wheel %d", wheels
);
837 (*elements
)[element
->cookie
] = element
;
841 case kHIDUsage_GD_Hatswitch
:
846 element
= new OSX_Hid_Device_Element
;
848 element
->type
= CK_HID_JOYSTICK_HAT
;
850 element
->usage
= usage
;
851 element
->usage_page
= usage_page
;
853 refCF
= CFDictionaryGetValue( element_dictionary
,
854 CFSTR( kIOHIDElementCookieKey
) );
856 !CFNumberGetValue( ( CFNumberRef
) refCF
, kCFNumberLongType
, &element
->cookie
) )
862 result
= (*queue
)->addElement( queue
, element
->cookie
, 0 );
863 if( result
!= kIOReturnSuccess
)
869 EM_log( CK_LOG_FINE
, "adding hat %d", hats
);
871 (*elements
)[element
->cookie
] = element
;
877 EM_log( CK_LOG_INFO
, "unknown page: %i usage: %i", usage_page
, usage
);
882 case kHIDPage_Button
:
883 case kHIDPage_KeyboardOrKeypad
:
888 /* filter out error and reserved usages*/
889 if( usage_page
== kHIDPage_KeyboardOrKeypad
&&
890 !( usage
>= kHIDUsage_KeyboardA
&&
891 usage
<= kHIDUsage_KeyboardRightGUI
) )
894 element
= new OSX_Hid_Device_Element
;
896 element
->type
= CK_HID_BUTTON_DOWN
;
897 element
->num
= buttons
;
898 element
->usage
= usage
;
899 element
->usage_page
= usage_page
;
901 refCF
= CFDictionaryGetValue( element_dictionary
,
902 CFSTR( kIOHIDElementCookieKey
) );
904 !CFNumberGetValue( ( CFNumberRef
) refCF
, kCFNumberLongType
, &element
->cookie
) )
910 result
= (*queue
)->addElement( queue
, element
->cookie
, 0 );
911 if( result
!= kIOReturnSuccess
)
917 EM_log( CK_LOG_FINE
, "adding button %d", buttons
);
919 (*elements
)[element
->cookie
] = element
;
925 EM_log( CK_LOG_FINER
, "unknown page: %i usage: %i", usage_page
, usage
);
930 case kIOHIDElementTypeCollection
:
931 refCF
= CFDictionaryGetValue( element_dictionary
, CFSTR( kIOHIDElementKey
) );
935 enumerate_elements( ( CFArrayRef
) refCF
);
938 case kIOHIDElementTypeOutput
:
942 /* filter out error and reserved usages */
943 if( usage
> kHIDUsage_LED_ExternalPowerConnected
)
946 element
= new OSX_Hid_Device_Element
;
948 refCF
= CFDictionaryGetValue( element_dictionary
,
949 CFSTR( kIOHIDElementCookieKey
) );
951 !CFNumberGetValue( ( CFNumberRef
) refCF
, kCFNumberLongType
, &element
->cookie
) )
957 refCF
= CFDictionaryGetValue( element_dictionary
,
958 CFSTR( kIOHIDElementMinKey
) );
960 !CFNumberGetValue( ( CFNumberRef
) refCF
, kCFNumberLongType
, &element
->min
) )
966 refCF
= CFDictionaryGetValue( element_dictionary
,
967 CFSTR( kIOHIDElementMaxKey
) );
969 !CFNumberGetValue( ( CFNumberRef
) refCF
, kCFNumberLongType
, &element
->max
) )
975 if( outputs
== NULL
)
976 outputs
= new map
< unsigned int, vector
< OSX_Hid_Device_Element
* > * >;
978 if( outputs
->find( CK_HID_LED
) == outputs
->end() )
979 ( *outputs
)[CK_HID_LED
] = new vector
< OSX_Hid_Device_Element
* >;
981 element
->type
= CK_HID_LED
;
982 element
->num
= ( *outputs
)[CK_HID_LED
]->size();
983 element
->usage
= usage
;
984 element
->usage_page
= usage_page
;
986 EM_log( CK_LOG_FINE
, "adding led %d", element
->num
);
988 ( *outputs
)[CK_HID_LED
]->push_back( element
);
998 t_CKINT
OSX_Hid_Device::start()
1000 // can only be called in Hid thread
1001 assert( rlHid
== CFRunLoopGetCurrent() );
1003 EM_log( CK_LOG_INFO
, "hid: starting %s", name
);
1006 // configure if needed
1009 // lock the device so we can mutate it
1015 // error during configuration!
1018 EM_log( CK_LOG_SEVERE
, "hid: error configuring %s", name
);
1027 EM_log( CK_LOG_INFO
, "hid: adding %s to run loop", name
);
1028 CFRunLoopAddSource( rlHid
, eventSource
, kCFRunLoopChuckHidMode
);
1030 IOReturn result
= ( *queue
)->start( queue
);
1031 if( result
!= kIOReturnSuccess
)
1033 EM_log( CK_LOG_SEVERE
, "hid: error starting event queue for %s", name
);
1043 t_CKINT
OSX_Hid_Device::stop()
1045 // can only be called in Hid thread
1046 assert( rlHid
== CFRunLoopGetCurrent() );
1050 IOReturn result
= ( *queue
)->stop( queue
);
1051 if( result
!= kIOReturnSuccess
)
1052 EM_log( CK_LOG_INFO
, "hid: error stopping event queue for %s", name
);
1055 CFRunLoopRemoveSource( rlHid
, eventSource
, kCFRunLoopChuckHidMode
);
1060 t_CKBOOL
OSX_Hid_Device::is_connected() const
1062 if( plugInInterface
== NULL
&& interface
== NULL
)
1067 t_CKBOOL
OSX_Hid_Device::is_same_as( io_object_t ioHIDDeviceObject
) const
1069 CFMutableDictionaryRef hidProperties2
= NULL
;
1070 t_CKBOOL result
= FALSE
;
1072 // retrieve a dictionary of device properties
1073 kern_return_t kern_result
= IORegistryEntryCreateCFProperties( ioHIDDeviceObject
,
1075 kCFAllocatorDefault
,
1078 if( kern_result
!= KERN_SUCCESS
|| hidProperties2
== NULL
)
1083 // gewang: moved these decl's above goto's
1084 CFNumberRef locationID2
= 0;
1085 CFNumberRef vendorID2
= 0;
1086 CFNumberRef productID2
= 0;
1087 CFStringRef manufacturer2
= 0;
1088 CFStringRef product2
= 0;
1090 // if no "uniquely identifying" info is available, then assume its new
1091 if( !locationID
&& !vendorID
&& !productID
&& !manufacturer
&& !product
)
1094 locationID2
= ( CFNumberRef
) CFDictionaryGetValue( hidProperties2
,
1095 CFSTR( kIOHIDLocationIDKey
) );
1096 if( ( locationID
&& !locationID2
) || ( !locationID
&& locationID2
) )
1097 goto end
; // not the same
1098 if( locationID
&& locationID2
&& CFNumberCompare( locationID
, locationID2
, NULL
) )
1099 goto end
; // not the same
1101 vendorID2
= ( CFNumberRef
) CFDictionaryGetValue( hidProperties2
,
1102 CFSTR( kIOHIDVendorIDKey
) );
1103 if( ( vendorID
&& !vendorID2
) || ( !vendorID
&& vendorID2
) )
1104 goto end
; // not the same
1105 if( vendorID
&& vendorID2
&& CFNumberCompare( vendorID
, vendorID2
, NULL
) )
1106 goto end
; // not the same
1108 productID2
= ( CFNumberRef
) CFDictionaryGetValue( hidProperties2
,
1109 CFSTR( kIOHIDProductIDKey
) );
1110 if( ( productID
&& !productID2
) || ( !productID
&& productID2
) )
1111 goto end
; // not the same
1112 if( productID
&& productID2
&& CFNumberCompare( productID
, productID2
, NULL
) )
1113 goto end
; // not the same
1115 manufacturer2
= ( CFStringRef
) CFDictionaryGetValue( hidProperties2
,
1116 CFSTR( kIOHIDManufacturerKey
) );
1117 if( ( manufacturer
&& !manufacturer2
) || ( !manufacturer
&& manufacturer2
) )
1118 goto end
; // not the same
1119 if( manufacturer
&& manufacturer2
&& CFStringCompare( manufacturer
, manufacturer2
, 0 ) )
1120 goto end
; // not the same
1122 product2
= ( CFStringRef
) CFDictionaryGetValue( hidProperties2
,
1123 CFSTR( kIOHIDProductKey
) );
1124 if( ( product
&& !product2
) || ( !product
&& product2
) )
1125 goto end
; // not the same
1126 if( product
&& product2
&& CFStringCompare( product
, product2
, 0 ) )
1127 goto end
; // not the same
1129 // if execution reaches this point, then they are the same
1133 CFRelease( hidProperties2
);
1137 //------------------------------------------------------------------------------
1138 // name: disconnect()
1139 // desc: called when device is physically disconnected from the machine.
1140 // deallocates per-connection resources, but leaves stuff that should be the
1141 // same across connections (element list, name, other general properties, etc)
1142 //------------------------------------------------------------------------------
1143 void OSX_Hid_Device::disconnect()
1145 // can only be called in Hid thread, or if the hid thread hasnt started
1146 assert( rlHid
== NULL
|| rlHid
== CFRunLoopGetCurrent() );
1148 if( plugInInterface
)
1150 ( *plugInInterface
)->Release( plugInInterface
);
1151 plugInInterface
= NULL
;
1158 ( *queue
)->stop( queue
);
1161 CFRunLoopRemoveSource( rlHid
, eventSource
,
1162 kCFRunLoopChuckHidMode
);
1165 ( *queue
)->dispose( queue
);
1166 ( *queue
)->Release( queue
);
1172 ( *interface
)->close( interface
);
1173 ( *interface
)->Release( interface
);
1177 if( removal_notification
)
1179 IOObjectRelease( removal_notification
);
1180 removal_notification
= NULL
;
1184 preconfiged
= FALSE
;
1187 //------------------------------------------------------------------------------
1189 // desc: deallocates all resources associated with the device
1190 //------------------------------------------------------------------------------
1191 void OSX_Hid_Device::cleanup()
1193 // can only be called in Hid thread, or if the hid thread hasnt started
1194 assert( rlHid
== NULL
|| rlHid
== CFRunLoopGetCurrent() );
1198 // delete all elements
1203 // iterate through the axis map, delete device element records
1204 map
< IOHIDElementCookie
, OSX_Hid_Device_Element
* >::iterator iter
, end
;
1205 end
= elements
->end();
1206 for( iter
= elements
->begin(); iter
!= end
; iter
++ )
1207 delete iter
->second
;
1211 // TODO: delete outputs also
1218 CFRelease( hidProperties
);
1219 hidProperties
= NULL
;
1226 CFRelease( locationID
);
1232 CFRelease( vendorID
);
1238 CFRelease( productID
);
1244 CFRelease( manufacturer
);
1245 manufacturer
= NULL
;
1250 CFRelease( product
);
1257 static void Hid_key_table_init()
1259 memset( g_hid_key_table
, 0, sizeof( g_hid_key_table
) );
1262 g_hid_key_table
[kHIDUsage_KeyboardA
] = 'A';
1263 g_hid_key_table
[kHIDUsage_KeyboardB
] = 'B';
1264 g_hid_key_table
[kHIDUsage_KeyboardC
] = 'C';
1265 g_hid_key_table
[kHIDUsage_KeyboardD
] = 'D';
1266 g_hid_key_table
[kHIDUsage_KeyboardE
] = 'E';
1267 g_hid_key_table
[kHIDUsage_KeyboardF
] = 'F';
1268 g_hid_key_table
[kHIDUsage_KeyboardG
] = 'G';
1269 g_hid_key_table
[kHIDUsage_KeyboardH
] = 'H';
1270 g_hid_key_table
[kHIDUsage_KeyboardI
] = 'I';
1271 g_hid_key_table
[kHIDUsage_KeyboardJ
] = 'J';
1272 g_hid_key_table
[kHIDUsage_KeyboardK
] = 'K';
1273 g_hid_key_table
[kHIDUsage_KeyboardL
] = 'L';
1274 g_hid_key_table
[kHIDUsage_KeyboardM
] = 'M';
1275 g_hid_key_table
[kHIDUsage_KeyboardN
] = 'N';
1276 g_hid_key_table
[kHIDUsage_KeyboardO
] = 'O';
1277 g_hid_key_table
[kHIDUsage_KeyboardP
] = 'P';
1278 g_hid_key_table
[kHIDUsage_KeyboardQ
] = 'Q';
1279 g_hid_key_table
[kHIDUsage_KeyboardR
] = 'R';
1280 g_hid_key_table
[kHIDUsage_KeyboardS
] = 'S';
1281 g_hid_key_table
[kHIDUsage_KeyboardT
] = 'T';
1282 g_hid_key_table
[kHIDUsage_KeyboardU
] = 'U';
1283 g_hid_key_table
[kHIDUsage_KeyboardV
] = 'V';
1284 g_hid_key_table
[kHIDUsage_KeyboardW
] = 'W';
1285 g_hid_key_table
[kHIDUsage_KeyboardX
] = 'X';
1286 g_hid_key_table
[kHIDUsage_KeyboardY
] = 'Y';
1287 g_hid_key_table
[kHIDUsage_KeyboardZ
] = 'Z';
1290 g_hid_key_table
[kHIDUsage_Keyboard1
] = '1';
1291 g_hid_key_table
[kHIDUsage_Keyboard2
] = '2';
1292 g_hid_key_table
[kHIDUsage_Keyboard3
] = '3';
1293 g_hid_key_table
[kHIDUsage_Keyboard4
] = '4';
1294 g_hid_key_table
[kHIDUsage_Keyboard5
] = '5';
1295 g_hid_key_table
[kHIDUsage_Keyboard6
] = '6';
1296 g_hid_key_table
[kHIDUsage_Keyboard7
] = '7';
1297 g_hid_key_table
[kHIDUsage_Keyboard8
] = '8';
1298 g_hid_key_table
[kHIDUsage_Keyboard9
] = '9';
1299 g_hid_key_table
[kHIDUsage_Keyboard0
] = '0';
1301 // ASCII whitespace/control characters
1302 g_hid_key_table
[kHIDUsage_KeyboardEscape
] = '\e';
1303 g_hid_key_table
[kHIDUsage_KeyboardDeleteOrBackspace
] = '\b';
1304 g_hid_key_table
[kHIDUsage_KeyboardReturnOrEnter
] = '\n';
1305 g_hid_key_table
[kHIDUsage_KeyboardTab
] = '\t';
1306 g_hid_key_table
[kHIDUsage_KeyboardSpacebar
] = ' ';
1309 g_hid_key_table
[kHIDUsage_KeyboardHyphen
] = '-';
1310 g_hid_key_table
[kHIDUsage_KeyboardEqualSign
] = '=';
1311 g_hid_key_table
[kHIDUsage_KeyboardOpenBracket
] = '[';
1312 g_hid_key_table
[kHIDUsage_KeyboardCloseBracket
] = ']';
1313 g_hid_key_table
[kHIDUsage_KeyboardBackslash
] = '\\';
1314 g_hid_key_table
[kHIDUsage_KeyboardNonUSPound
] = '#';
1315 g_hid_key_table
[kHIDUsage_KeyboardSemicolon
] = ';';
1316 g_hid_key_table
[kHIDUsage_KeyboardQuote
] = '\'';
1317 g_hid_key_table
[kHIDUsage_KeyboardGraveAccentAndTilde
] = '`';
1318 g_hid_key_table
[kHIDUsage_KeyboardComma
] = ',';
1319 g_hid_key_table
[kHIDUsage_KeyboardPeriod
] = '.';
1320 g_hid_key_table
[kHIDUsage_KeyboardSlash
] = '/';
1322 // ASCII keypad symbols/whitespace
1323 g_hid_key_table
[kHIDUsage_KeypadSlash
] = '/';
1324 g_hid_key_table
[kHIDUsage_KeypadAsterisk
] = '*';
1325 g_hid_key_table
[kHIDUsage_KeypadHyphen
] = '-';
1326 g_hid_key_table
[kHIDUsage_KeypadPlus
] = '+';
1327 g_hid_key_table
[kHIDUsage_KeypadEnter
] = '\n';
1329 // ASCII keypad numbers
1330 g_hid_key_table
[kHIDUsage_Keypad1
] = '1';
1331 g_hid_key_table
[kHIDUsage_Keypad2
] = '2';
1332 g_hid_key_table
[kHIDUsage_Keypad3
] = '3';
1333 g_hid_key_table
[kHIDUsage_Keypad4
] = '4';
1334 g_hid_key_table
[kHIDUsage_Keypad5
] = '5';
1335 g_hid_key_table
[kHIDUsage_Keypad6
] = '6';
1336 g_hid_key_table
[kHIDUsage_Keypad7
] = '7';
1337 g_hid_key_table
[kHIDUsage_Keypad8
] = '8';
1338 g_hid_key_table
[kHIDUsage_Keypad9
] = '9';
1339 g_hid_key_table
[kHIDUsage_Keypad0
] = '0';
1341 // ASCII keypad symbols
1342 g_hid_key_table
[kHIDUsage_KeypadPeriod
] = '.';
1343 g_hid_key_table
[kHIDUsage_KeyboardNonUSBackslash
] = '\\';
1344 g_hid_key_table
[kHIDUsage_KeypadEqualSign
] = '=';
1345 g_hid_key_table
[kHIDUsage_KeypadComma
] = ',';
1346 g_hid_key_table
[kHIDUsage_KeypadEqualSignAS400
] = '=';
1349 t_CKINT
Hid_hwkey_to_ascii( t_CKINT hwkey
)
1351 if( hwkey
< 0 || hwkey
>= sizeof( g_hid_key_table
) )
1354 return g_hid_key_table
[hwkey
];
1359 Hid_key_table_init();
1361 rlHid
= CFRunLoopGetCurrent();
1363 // set up notification for new added devices/removed devices
1364 CFRunLoopAddSource( rlHid
,
1365 IONotificationPortGetRunLoopSource( newDeviceNotificationPort
),
1366 kCFRunLoopChuckHidMode
);
1368 // add open/close operation source
1369 CFRunLoopSourceContext opSourceContext
;
1370 opSourceContext
.version
= 0;
1371 opSourceContext
.info
= NULL
;
1372 opSourceContext
.retain
= NULL
;
1373 opSourceContext
.release
= NULL
;
1374 opSourceContext
.copyDescription
= NULL
;
1375 opSourceContext
.equal
= NULL
;
1376 opSourceContext
.hash
= NULL
;
1377 opSourceContext
.schedule
= NULL
;
1378 opSourceContext
.cancel
= NULL
;
1379 opSourceContext
.perform
= Hid_do_operation
;
1380 CFRunLoopSourceRef _hidOpSource
= CFRunLoopSourceCreate( kCFAllocatorDefault
,
1383 CFRunLoopAddSource( rlHid
, _hidOpSource
, kCFRunLoopChuckHidMode
);
1384 hidOpSource
= _hidOpSource
;
1386 Hid_do_operation( NULL
);
1388 #ifdef __CK_HID_WIIREMOTE__
1389 // add wii remote source
1390 CFRunLoopSourceContext wrSourceContext
;
1391 wrSourceContext
.version
= 0;
1392 wrSourceContext
.info
= NULL
;
1393 wrSourceContext
.retain
= NULL
;
1394 wrSourceContext
.release
= NULL
;
1395 wrSourceContext
.copyDescription
= NULL
;
1396 wrSourceContext
.equal
= NULL
;
1397 wrSourceContext
.hash
= NULL
;
1398 wrSourceContext
.schedule
= NULL
;
1399 wrSourceContext
.cancel
= NULL
;
1400 wrSourceContext
.perform
= WiiRemote_cfrl_callback
;
1401 CFRunLoopSourceRef _cfrlWiiRemoteSource
= CFRunLoopSourceCreate( kCFAllocatorDefault
,
1404 CFRunLoopAddSource( rlHid
, _cfrlWiiRemoteSource
, kCFRunLoopChuckHidMode
);
1405 cfrlWiiRemoteSource
= _cfrlWiiRemoteSource
;
1407 WiiRemote_cfrl_callback( NULL
);
1413 // verify that the joystick system has not already been initialized
1414 if( g_hid_init
== TRUE
)
1419 IOReturn result
= kIOReturnSuccess
;
1420 io_iterator_t hidObjectIterator
= 0;
1422 t_CKINT filter_usage_page
= kHIDPage_GenericDesktop
;
1424 // allocate vectors of device records
1425 joysticks
= new xvector
< OSX_Hid_Device
* >;
1426 mice
= new xvector
< OSX_Hid_Device
* >;
1427 keyboards
= new xvector
< OSX_Hid_Device
* >;
1429 joystick_names
= new xmultimap
< string
, OSX_Hid_Device
* >;
1430 mouse_names
= new xmultimap
< string
, OSX_Hid_Device
* >;
1431 keyboard_names
= new xmultimap
< string
, OSX_Hid_Device
* >;
1433 hid_operation_buffer
= new CBufferSimple
;
1434 hid_operation_buffer
->initialize( 20, sizeof( OSX_Hid_op
) );
1436 CFMutableDictionaryRef hidMatchDictionary
= IOServiceMatching( kIOHIDDeviceKey
);
1437 if( !hidMatchDictionary
)
1439 EM_log( CK_LOG_SEVERE
, "hid: error: unable to retrieving hidMatchDictionary, unable to initialize" );
1443 /*refCF = ( CFTypeRef ) CFNumberCreate( kCFAllocatorDefault,
1445 &filter_usage_page );
1446 CFDictionarySetValue( hidMatchDictionary,
1447 CFSTR( kIOHIDPrimaryUsagePageKey ), refCF );*/
1449 newDeviceNotificationPort
= IONotificationPortCreate( kIOMasterPortDefault
);
1451 result
= IOServiceAddMatchingNotification( newDeviceNotificationPort
,
1452 kIOFirstMatchNotification
,
1456 &hidObjectIterator
);
1458 if( result
!= kIOReturnSuccess
|| hidObjectIterator
== 0 )
1460 EM_log( CK_LOG_SEVERE
, "hid: error: unable to retrieving matching services, unable to initialize" );
1464 //CFRelease( refCF );
1466 Hid_new_devices( NULL
, hidObjectIterator
);
1469 static void Hid_new_devices( void * refcon
, io_iterator_t iterator
)
1471 EM_log( CK_LOG_INFO
, "hid: new device(s) found" );
1475 CFTypeRef refCF
= NULL
;
1477 io_object_t ioHIDDeviceObject
= 0;
1478 t_CKINT usage
, usage_page
;
1479 t_CKINT joysticks_seen
= joysticks
->size(),
1480 mice_seen
= mice
->size(),
1481 keyboards_seen
= keyboards
->size();
1485 if( ioHIDDeviceObject
)
1486 IOObjectRelease( ioHIDDeviceObject
);
1488 ioHIDDeviceObject
= IOIteratorNext( iterator
);
1489 if( ioHIDDeviceObject
== 0 )
1492 // ascertain device information
1494 // first, determine the device usage page and usage
1495 usage
= usage_page
= -1;
1497 refCF
= IORegistryEntryCreateCFProperty( ioHIDDeviceObject
,
1498 CFSTR( kIOHIDPrimaryUsagePageKey
),
1499 kCFAllocatorDefault
,
1504 CFNumberGetValue( ( CFNumberRef
)refCF
, kCFNumberLongType
, &usage_page
);
1507 refCF
= IORegistryEntryCreateCFProperty( ioHIDDeviceObject
,
1508 CFSTR( kIOHIDPrimaryUsageKey
),
1509 kCFAllocatorDefault
,
1514 CFNumberGetValue( ( CFNumberRef
)refCF
, kCFNumberLongType
, &usage
);
1517 if( usage_page
!= kHIDPage_GenericDesktop
)
1519 // some sort of HID device we dont recognize
1520 // lets probe its input/output reports and try to categorize it
1521 EM_log( CK_LOG_INFO
, "hid: device not recognized, attempting to determine HID type" );
1523 // allocate the device record, set usage page and usage
1524 OSX_Hid_Device
* new_device
= new OSX_Hid_Device
;
1525 new_device
->type
= CK_HID_DEV_NONE
;
1526 new_device
->num
= 0;
1527 new_device
->usage_page
= usage_page
;
1528 new_device
->usage
= usage
;
1530 if( !new_device
->preconfigure( ioHIDDeviceObject
) && !new_device
->configure() )
1532 if( new_device
->hats
> 0 || new_device
->axes
> 2 )
1533 // make it a joystick
1535 usage_page
= kHIDPage_GenericDesktop
;
1536 usage
= kHIDUsage_GD_Joystick
;
1539 else if( new_device
->axes
== 2 )
1542 usage_page
= kHIDPage_GenericDesktop
;
1543 usage
= kHIDUsage_GD_Mouse
;
1546 else if( new_device
->buttons
> 0 )
1547 // make it a keyboard
1549 usage_page
= kHIDPage_GenericDesktop
;
1550 usage
= kHIDUsage_GD_Keyboard
;
1553 new_device
->cleanup();
1564 if ( usage_page
== kHIDPage_GenericDesktop
)
1566 if( usage
== kHIDUsage_GD_Joystick
||
1567 usage
== kHIDUsage_GD_GamePad
)
1568 // this is a joystick, create a new item in the joystick array
1570 // see if this an device that was disconnected being reconnected
1571 refCF
= IORegistryEntryCreateCFProperty( ioHIDDeviceObject
,
1572 CFSTR( kIOHIDProductKey
),
1573 kCFAllocatorDefault
,
1578 CFStringGetCString( ( CFStringRef
) refCF
, __temp
, 256,
1579 kCFStringEncodingASCII
);
1584 strncpy( __temp
, "Joystick", 256 );
1586 pair
< xmultimap
< string
, OSX_Hid_Device
* >::const_iterator
,
1587 xmultimap
< string
, OSX_Hid_Device
* >::const_iterator
> name_range
1588 = joystick_names
->equal_range( string( __temp
) );
1590 xmultimap
< string
, OSX_Hid_Device
* >::const_iterator
1591 start
= name_range
.first
,
1592 end
= name_range
.second
;
1594 t_CKBOOL match_found
= FALSE
;
1596 for( ; start
!= end
; start
++ )
1598 OSX_Hid_Device
* old_device
= ( *start
).second
;
1599 if( !old_device
->is_connected() &&
1600 old_device
->is_same_as( ioHIDDeviceObject
) )
1604 EM_log( CK_LOG_INFO
, "hid: joystick %s reattached",
1607 if( old_device
->preconfigure( ioHIDDeviceObject
) )
1609 EM_log( CK_LOG_INFO
, "hid: error during reconfiguration of %s",
1614 if( old_device
->refcount
&&
1615 !old_device
->start() )
1618 msg
.device_type
= old_device
->type
;
1619 msg
.device_num
= old_device
->num
;
1620 msg
.type
= CK_HID_DEVICE_CONNECTED
;
1622 HidInManager::push_message( msg
);
1632 // create a new device record for the device
1633 EM_log( CK_LOG_INFO
, "hid: preconfiguring joystick %i", joysticks_seen
);
1636 // allocate the device record, set usage page and usage
1637 OSX_Hid_Device
* new_device
= new OSX_Hid_Device
;
1638 new_device
->type
= CK_HID_DEV_JOYSTICK
;
1639 new_device
->num
= joysticks
->size();
1640 new_device
->usage_page
= usage_page
;
1641 new_device
->usage
= usage
;
1643 if( !new_device
->preconfigure( ioHIDDeviceObject
) )
1646 joysticks
->push_back( new_device
);
1647 joysticks
->unlock();
1649 joystick_names
->lock();
1650 joystick_names
->insert( pair
< string
, OSX_Hid_Device
* >( string( new_device
->name
),
1652 joystick_names
->unlock();
1657 EM_log( CK_LOG_INFO
,
1658 "hid: ignoring %i, invalid joystick",
1668 if( usage
== kHIDUsage_GD_Mouse
)
1671 // see if this an device that was disconnected being reconnected
1672 refCF
= IORegistryEntryCreateCFProperty( ioHIDDeviceObject
,
1673 CFSTR( kIOHIDProductKey
),
1674 kCFAllocatorDefault
,
1679 CFStringGetCString( ( CFStringRef
) refCF
, __temp
, 256,
1680 kCFStringEncodingASCII
);
1685 strncpy( __temp
, "Mouse", 256 );
1687 pair
< xmultimap
< string
, OSX_Hid_Device
* >::const_iterator
,
1688 xmultimap
< string
, OSX_Hid_Device
* >::const_iterator
> name_range
1689 = mouse_names
->equal_range( string( __temp
) );
1691 xmultimap
< string
, OSX_Hid_Device
* >::const_iterator
1692 start
= name_range
.first
,
1693 end
= name_range
.second
;
1695 t_CKBOOL match_found
= FALSE
;
1697 for( ; start
!= end
; start
++ )
1699 OSX_Hid_Device
* old_device
= ( *start
).second
;
1700 if( !old_device
->is_connected() &&
1701 old_device
->is_same_as( ioHIDDeviceObject
) )
1705 EM_log( CK_LOG_INFO
, "hid: mouse %s reattached",
1708 if( old_device
->preconfigure( ioHIDDeviceObject
) )
1710 EM_log( CK_LOG_INFO
, "hid: error during reconfiguration of %s",
1715 if( old_device
->refcount
&&
1716 !old_device
->start() )
1719 msg
.device_type
= old_device
->type
;
1720 msg
.device_num
= old_device
->num
;
1721 msg
.type
= CK_HID_DEVICE_CONNECTED
;
1723 HidInManager::push_message( msg
);
1733 // create a new device record for the device
1734 EM_log( CK_LOG_INFO
, "hid: preconfiguring mouse %i", mice_seen
);
1737 // allocate the device record, set usage page and usage
1738 OSX_Hid_Device
* new_device
= new OSX_Hid_Device
;
1739 new_device
->type
= CK_HID_DEV_MOUSE
;
1740 new_device
->num
= mice
->size();
1741 new_device
->usage_page
= usage_page
;
1742 new_device
->usage
= usage
;
1744 if( !new_device
->preconfigure( ioHIDDeviceObject
) )
1747 mice
->push_back( new_device
);
1750 mouse_names
->lock();
1751 mouse_names
->insert( pair
< string
, OSX_Hid_Device
* >( string( new_device
->name
),
1753 mouse_names
->unlock();
1758 EM_log( CK_LOG_INFO
,
1759 "hid: ignoring %i, invalid mouse",
1769 if( usage
== kHIDUsage_GD_Keyboard
|| usage
== kHIDUsage_GD_Keypad
)
1770 // this is a keyboard
1772 // see if this an device that was disconnected being reconnected
1773 refCF
= IORegistryEntryCreateCFProperty( ioHIDDeviceObject
,
1774 CFSTR( kIOHIDProductKey
),
1775 kCFAllocatorDefault
,
1780 CFStringGetCString( ( CFStringRef
) refCF
, __temp
, 256,
1781 kCFStringEncodingASCII
);
1786 strncpy( __temp
, "Keyboard", 256 );
1788 pair
< xmultimap
< string
, OSX_Hid_Device
* >::const_iterator
,
1789 xmultimap
< string
, OSX_Hid_Device
* >::const_iterator
> name_range
1790 = keyboard_names
->equal_range( string( __temp
) );
1792 xmultimap
< string
, OSX_Hid_Device
* >::const_iterator
1793 start
= name_range
.first
,
1794 end
= name_range
.second
;
1796 t_CKBOOL match_found
= FALSE
;
1798 for( ; start
!= end
; start
++ )
1800 OSX_Hid_Device
* old_device
= ( *start
).second
;
1801 if( !old_device
->is_connected() &&
1802 old_device
->is_same_as( ioHIDDeviceObject
) )
1806 EM_log( CK_LOG_INFO
, "hid: keyboard %s reattached",
1809 if( old_device
->preconfigure( ioHIDDeviceObject
) )
1811 EM_log( CK_LOG_INFO
, "hid: error during reconfiguration of %s",
1816 if( old_device
->refcount
&&
1817 !old_device
->start() )
1820 msg
.device_type
= old_device
->type
;
1821 msg
.device_num
= old_device
->num
;
1822 msg
.type
= CK_HID_DEVICE_CONNECTED
;
1824 HidInManager::push_message( msg
);
1834 // create a new device record for the device
1835 EM_log( CK_LOG_INFO
, "hid: preconfiguring keyboard %i",
1839 // allocate the device record, set usage page and usage
1840 OSX_Hid_Device
* new_device
= new OSX_Hid_Device
;
1841 new_device
->type
= CK_HID_DEV_KEYBOARD
;
1842 new_device
->num
= keyboards
->size();
1843 new_device
->usage_page
= usage_page
;
1844 new_device
->usage
= usage
;
1846 if( !new_device
->preconfigure( ioHIDDeviceObject
) )
1849 keyboards
->push_back( new_device
);
1850 keyboards
->unlock();
1852 keyboard_names
->lock();
1853 keyboard_names
->insert( pair
< string
, OSX_Hid_Device
* >( string( new_device
->name
),
1855 keyboard_names
->unlock();
1860 EM_log( CK_LOG_INFO
,
1861 "hid: ignoring %i, invalid keyboard",
1874 void Hid_device_removed( void * refcon
, io_service_t service
,
1875 natural_t messageType
, void * messageArgument
)
1877 if( messageType
== kIOMessageServiceIsTerminated
&& refcon
)
1879 OSX_Hid_Device
* device
= ( OSX_Hid_Device
* ) refcon
;
1881 if( device
->is_connected() )
1883 EM_log( CK_LOG_INFO
, "hid: %s disconnected", device
->name
);
1886 device
->disconnect();
1890 msg
.device_type
= device
->type
;
1891 msg
.device_num
= device
->num
;
1892 msg
.type
= CK_HID_DEVICE_DISCONNECTED
;
1894 HidInManager::push_message( msg
);
1899 #ifdef __CK_HID_WIIREMOTE__
1901 #include "objc/objc.h"
1902 #include "objc/objc-runtime.h"
1903 #include "objc/objc-class.h"
1905 static id
createAutoReleasePool()
1907 Class NSAutoreleasePoolClass
= ( Class
) objc_getClass( "NSAutoreleasePool" );
1909 id autoReleasePool
= class_createInstance( NSAutoreleasePoolClass
, 0 );
1911 SEL initSelector
= sel_registerName( "init" );
1913 autoReleasePool
= objc_msgSend( autoReleasePool
, initSelector
);
1915 return autoReleasePool
;
1918 static void releaseAutoReleasePool()
1927 #ifdef __CK_HID_WIIREMOTE__
1928 id auto_release_pool
= createAutoReleasePool();
1931 CFRunLoopRunInMode( kCFRunLoopChuckHidMode
, 60 * 60 * 24, false );
1934 void Hid_callback( void * target
, IOReturn result
,
1935 void * refcon
, void * sender
)
1937 OSX_Hid_Device
* device
= ( OSX_Hid_Device
* ) refcon
;
1938 OSX_Hid_Device_Element
* element
;
1939 AbsoluteTime atZero
= { 0, 0 };
1940 IOHIDEventStruct event
;
1943 while( result
== kIOReturnSuccess
)
1945 result
= ( *( device
->queue
) )->getNextEvent( device
->queue
,
1946 &event
, atZero
, 0 );
1947 if( result
== kIOReturnUnderrun
)
1949 if( result
!= kIOReturnSuccess
)
1951 EM_log( CK_LOG_INFO
, "hid: warning: getNextEvent failed" );
1955 element
= ( *( device
->elements
) )[event
.elementCookie
];
1958 msg
.device_type
= device
->type
;
1959 msg
.device_num
= device
->num
;
1960 msg
.type
= element
->type
;
1961 msg
.eid
= element
->num
;
1965 case CK_HID_JOYSTICK_AXIS
:
1966 // scale the value to [-1.0, 1.0]
1967 msg
.fdata
[0] = ((t_CKFLOAT
)(event
.value
- element
->min
)) * 2.0 / ((t_CKFLOAT
)(element
->max
- element
->min
)) - 1.0;
1970 case CK_HID_JOYSTICK_HAT
:
1971 msg
.idata
[0] = event
.value
;
1974 case CK_HID_MOUSE_MOTION
:
1977 if( element
->usage
== kHIDUsage_GD_X
)
1979 msg
.idata
[0] = event
.value
;
1986 msg
.idata
[1] = event
.value
;
1989 #ifndef __CK_HID_CURSOR_TRACK__
1991 GetGlobalMouse( &p
);
1996 CGDirectDisplayID display
;
1997 CGDisplayCount displayCount
;
2003 if( CGGetDisplaysWithPoint( cgp
, 1, &display
, &displayCount
) ==
2006 CGRect bounds
= CGDisplayBounds( display
);
2008 msg
.fdata
[0] = ( ( t_CKFLOAT
) ( p
.h
- bounds
.origin
.x
) ) /
2009 ( bounds
.size
.width
- 1 );
2010 msg
.fdata
[1] = ( ( t_CKFLOAT
) ( p
.v
- bounds
.origin
.y
) ) /
2011 ( bounds
.size
.height
- 1 );
2014 msg
.idata
[2] = cursorX
;
2015 msg
.idata
[3] = cursorY
;
2016 msg
.fdata
[0] = scaledCursorX
;
2017 msg
.fdata
[1] = scaledCursorY
;
2018 #endif // __CK_HID_CURSOR_TRACK__
2022 case CK_HID_MOUSE_WHEEL
:
2025 if( element
->num
== 1 ) // "X" wheel motion
2027 msg
.idata
[0] = event
.value
;
2031 else // "Y" wheel motion - the default for single wheel systems
2034 msg
.idata
[1] = event
.value
;
2039 case CK_HID_BUTTON_DOWN
:
2040 if( event
.value
== 0 )
2041 msg
.type
= CK_HID_BUTTON_UP
;
2043 msg
.idata
[0] = event
.value
;
2045 if( msg
.device_type
== CK_HID_DEV_KEYBOARD
)
2047 msg
.eid
= element
->usage
;
2048 msg
.idata
[1] = element
->usage
;
2049 msg
.idata
[2] = Hid_hwkey_to_ascii( element
->usage
);
2055 HidInManager::push_message( msg
);
2059 static void Hid_do_operation( void * info
)
2063 while( hid_operation_buffer
->get( &op
, 1 ) )
2066 OSX_Hid_Device
* device
= NULL
;
2070 case OSX_Hid_op::open
:
2071 if( op
.index
>= op
.v
->size() )
2073 EM_log( CK_LOG_SEVERE
, "hid: error: no such device %i", op
.index
);
2077 device
= op
.v
->at( op
.index
);
2079 if( device
->refcount
== 0 )
2086 case OSX_Hid_op::close
:
2087 if( op
.index
>= op
.v
->size() )
2089 EM_log( CK_LOG_SEVERE
, "hid: error: no such device %i", op
.index
);
2093 device
= op
.v
->at( op
.index
);
2097 if( device
->refcount
== 0 )
2107 // stop the run loop; since thread_going is FALSE, the poll thread will exit
2109 CFRunLoopStop( rlHid
);
2113 CFRunLoopRemoveSource( rlHid
, hidOpSource
, kCFRunLoopChuckHidMode
);
2114 CFRelease( hidOpSource
);
2118 if( newDeviceNotificationPort
)
2120 IONotificationPortDestroy( newDeviceNotificationPort
);
2121 newDeviceNotificationPort
= NULL
;
2126 #ifdef __CK_HID_CURSOR_TRACK__
2127 Mouse_stop_cursor_track();
2128 #endif // __CK_HID_CURSOR_TRACK__
2133 if( g_hid_init
== FALSE
)
2137 delete hid_operation_buffer
;
2139 xvector
< OSX_Hid_Device
* >::size_type i
, len
;
2141 len
= joysticks
->size();
2142 for( i
= 0; i
< len
; i
++ )
2143 delete joysticks
->at( i
);
2149 for( i
= 0; i
< len
; i
++ )
2150 delete mice
->at( i
);
2155 len
= keyboards
->size();
2156 for( i
= 0; i
< len
; i
++ )
2157 delete keyboards
->at( i
);
2162 // TODO: delete xmultimaps
2165 int Hid_count( xvector
< OSX_Hid_Device
* > * v
)
2172 int count
= v
->size();
2179 int Hid_count_elements( xvector
< OSX_Hid_Device
* > * v
, int i
, int type
)
2181 if( v
== NULL
|| i
< 0 )
2188 if( i
>= v
->size() )
2194 OSX_Hid_Device
* device
= v
->at( i
);
2202 case CK_HID_JOYSTICK_AXIS
:
2203 if( device
->type
== CK_HID_DEV_JOYSTICK
)
2207 case CK_HID_BUTTON_DOWN
:
2208 case CK_HID_BUTTON_UP
:
2209 r
= device
->buttons
;
2212 case CK_HID_JOYSTICK_HAT
:
2216 case CK_HID_JOYSTICK_BALL
:
2220 case CK_HID_MOUSE_MOTION
:
2221 if( device
->type
== CK_HID_DEV_MOUSE
)
2225 case CK_HID_MOUSE_WHEEL
:
2226 if( device
->type
== CK_HID_DEV_MOUSE
)
2231 if( ( *device
->outputs
)[type
] )
2232 r
= ( *device
->outputs
)[type
]->size();
2241 int Hid_open( xvector
< OSX_Hid_Device
* > * v
, int i
)
2243 if( v
== NULL
|| i
< 0 )
2248 if( i
>= v
->size() )
2257 op
.type
= OSX_Hid_op::open
;
2261 hid_operation_buffer
->put( &op
, 1 );
2263 if( hidOpSource
&& rlHid
)
2265 CFRunLoopSourceSignal( hidOpSource
);
2266 CFRunLoopWakeUp( rlHid
);
2272 int Hid_close( xvector
< OSX_Hid_Device
* > * v
, int i
)
2274 if( v
== NULL
|| i
< 0 )
2279 if( i
>= v
->size() )
2288 op
.type
= OSX_Hid_op::close
;
2292 hid_operation_buffer
->put( &op
, 1 );
2294 if( hidOpSource
&& rlHid
)
2296 CFRunLoopSourceSignal( hidOpSource
);
2297 CFRunLoopWakeUp( rlHid
);
2303 const char * Hid_name( xvector
< OSX_Hid_Device
* > * v
, int i
)
2305 if( v
== NULL
|| i
< 0 )
2310 if( i
>= v
->size() )
2316 OSX_Hid_Device
* device
= v
->at( i
);
2322 const char * name
= device
->name
;
2329 #pragma mark OS X Joystick support
2331 void Joystick_init()
2336 void Joystick_poll()
2340 void Joystick_quit()
2345 int Joystick_count()
2347 return Hid_count( joysticks
);
2350 int Joystick_count_elements( int js
, int type
)
2352 return Hid_count_elements( joysticks
, js
, type
);
2355 int Joystick_open( int js
)
2357 return Hid_open( joysticks
, js
);
2360 int Joystick_close( int js
)
2362 return Hid_close( joysticks
, js
);
2365 const char * Joystick_name( int js
)
2367 return Hid_name( joysticks
, js
);
2370 #pragma mark OS X Mouse support
2388 return Hid_count( mice
);
2391 int Mouse_count_elements( int m
, int type
)
2393 return Hid_count_elements( mice
, m
, type
);
2396 int Mouse_open( int m
)
2398 return Hid_open( mice
, m
);
2401 int Mouse_close( int m
)
2403 return Hid_close( mice
, m
);
2406 const char * Mouse_name( int m
)
2408 return Hid_name( mice
, m
);
2411 #ifdef __CK_HID_CURSOR_TRACK__
2412 CGPoint
CGEventGetLocation(CGEventRef event
);
2414 CGEventRef
Mouse_cursor_track_cb( CGEventTapProxy proxy
, CGEventType type
,
2415 CGEventRef event
, void * refcon
)
2417 CGPoint p
= CGEventGetLocation( event
);
2419 cursorX
= ( t_CKINT
) p
.x
;
2420 cursorY
= ( t_CKINT
) p
.y
;
2422 CGDirectDisplayID display
;
2423 CGDisplayCount displayCount
;
2425 if( CGGetDisplaysWithPoint( p
, 1, &display
, &displayCount
) ==
2428 CGRect bounds
= CGDisplayBounds( display
);
2430 scaledCursorX
= ( ( t_CKFLOAT
) ( p
.x
- bounds
.origin
.x
) ) /
2431 ( bounds
.size
.width
- 1 );
2432 scaledCursorY
= ( ( t_CKFLOAT
) ( p
.y
- bounds
.origin
.y
) ) /
2433 ( bounds
.size
.height
- 1 );
2439 void * Mouse_cursor_track( void * )
2441 EM_log( CK_LOG_INFO
, "hid: starting cursor track" );
2446 rlCursorTrack
= CFRunLoopGetCurrent();
2448 CFMachPortRef machPort
= CGEventTapCreate( kCGSessionEventTap
,
2449 kCGHeadInsertEventTap
,
2450 kCGEventTapOptionListenOnly
,
2451 CGEventMaskBit( kCGEventMouseMoved
),
2452 Mouse_cursor_track_cb
, NULL
);
2453 CFRunLoopSourceRef tapSource
;
2454 if( machPort
!= NULL
)
2456 tapSource
= CFMachPortCreateRunLoopSource( NULL
, machPort
, 0 );
2457 CFRunLoopAddSource( rlCursorTrack
, tapSource
, kCFRunLoopChuckHidMode
);
2462 EM_log( CK_LOG_WARNING
, "hid: cursor position listener startup failed" );
2467 CFRunLoopRunInMode( kCFRunLoopChuckHidMode
, 60 * 60 * 24, FALSE
);
2469 CFRelease( machPort
);
2470 CFRelease( tapSource
);
2471 rlCursorTrack
= NULL
;
2473 EM_log( CK_LOG_INFO
, "hid: stopping cursor track" );
2478 #endif // __CK_HID_CURSOR_TRACK__
2480 int Mouse_start_cursor_track()
2482 #ifdef __CK_HID_CURSOR_TRACK__
2483 if( &CGEventTapCreate
== NULL
)
2490 pthread_t ct_thread
;
2492 if( pthread_create( &ct_thread
, NULL
, Mouse_cursor_track
, NULL
) != 0 )
2494 EM_log( CK_LOG_WARNING
, "hid: cursor track thread failed to start" );
2501 #endif // __CK_HID_CURSOR_TRACK__
2504 int Mouse_stop_cursor_track()
2506 #ifdef __CK_HID_CURSOR_TRACK__
2512 CFRunLoopStop( rlCursorTrack
);
2517 #endif // __CK_HID_CURSOR_TRACK__
2521 //#endif /* __CK_HID_CURSORTRACK__ */
2523 #pragma mark OS X Keyboard support
2524 void Keyboard_init()
2529 void Keyboard_poll()
2534 void Keyboard_quit()
2539 int Keyboard_count()
2541 return Hid_count( keyboards
);
2544 int Keyboard_count_elements( int k
, int type
)
2546 return Hid_count_elements( keyboards
, k
, type
);
2549 int Keyboard_open( int k
)
2551 return Hid_open( keyboards
, k
);
2554 int Keyboard_close( int k
)
2556 return Hid_close( keyboards
, k
);
2559 int Keyboard_send( int k
, const HidMsg
* msg
)
2561 if( keyboards
== NULL
|| k
< 0 || k
>= keyboards
->size() )
2564 OSX_Hid_Device
* keyboard
= ( *keyboards
)[k
];
2566 if( keyboard
->outputs
== NULL
|| // no outputs
2567 keyboard
->outputs
->find( msg
->type
) == keyboard
->outputs
->end() )
2568 // no outputs of that type
2571 if( msg
->eid
< 0 || msg
->eid
>= ( *( keyboard
->outputs
) )[msg
->type
]->size() )
2572 // invalid output type element number
2575 OSX_Hid_Device_Element
* output
= ( *( *( keyboard
->outputs
) )[msg
->type
] )[msg
->eid
];
2577 IOHIDEventStruct eventStruct
;
2579 eventStruct
.type
= kIOHIDElementTypeOutput
;
2580 eventStruct
.elementCookie
= output
->cookie
;
2581 eventStruct
.timestamp
= UpTime();
2582 eventStruct
.longValueSize
= 0;
2583 eventStruct
.longValue
= NULL
;
2585 if( msg
->idata
[0] < output
->min
)
2586 eventStruct
.value
= output
->min
;
2587 else if( msg
->idata
[0] > output
->max
)
2588 eventStruct
.value
= output
->max
;
2590 eventStruct
.value
= msg
->idata
[0];
2593 result
= ( *( keyboard
->interface
) )->setElementValue( keyboard
->interface
,
2597 if( result
!= kIOReturnSuccess
)
2603 const char * Keyboard_name( int k
)
2605 return Hid_name( keyboards
, k
);
2608 #pragma mark OS X Tilt/Sudden Motion Sensor support
2612 kSMSPowerbookDataType
,
2613 kSMSMacBookProDataType
2616 static struct t_TiltSensor_data
2640 io_connect_t dataPort
;
2642 int detected
; // 0 = detection not yet run, -1 = no sensor found, 1 = sensor found
2657 // ge: SMS multi-threading
2658 static int TiltSensor_do_read();
2660 //-----------------------------------------------------------------------------
2661 // name: class SMSManager
2663 //-----------------------------------------------------------------------------
2667 static t_CKBOOL
init();
2668 static void shutdown();
2673 static t_CKINT the_onoff
;
2674 static t_CKBOOL the_init
;
2675 static t_CKINT wait_time
;
2676 static XThread
* the_thread
;
2682 // designate new poll rate
2683 t_CKINT
TiltSensor_setPollRate( t_CKINT usec
)
2686 assert( usec
>= 0 );
2688 SMSManager::wait_time
= usec
;
2690 return SMSManager::wait_time
;
2693 // query current poll rate
2694 t_CKINT
TiltSensor_getPollRate( )
2696 return SMSManager::wait_time
;
2700 t_CKINT
SMSManager::the_onoff
= 0;
2701 t_CKBOOL
SMSManager::the_init
= FALSE
;
2702 t_CKINT
SMSManager::wait_time
= 3000;
2703 XThread
* SMSManager::the_thread
= NULL
;
2704 t_CKINT
SMSManager::x
= 0;
2705 t_CKINT
SMSManager::y
= 0;
2706 t_CKINT
SMSManager::z
= 0;
2709 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
2710 static void * sms_loop( void * )
2712 static unsigned int __stdcall
sms_loop( void * )
2716 EM_log( CK_LOG_INFO
, "starting SMS multi-threaded loop..." );
2719 while( SMSManager::the_init
)
2722 if( SMSManager::the_onoff
)
2725 TiltSensor_do_read();
2728 if( TiltSensor_data
.dataType
== kSMSPowerbookDataType
)
2730 SMSManager::x
= TiltSensor_data
.data
.powerbook
.x
;
2731 SMSManager::y
= TiltSensor_data
.data
.powerbook
.y
;
2732 SMSManager::z
= TiltSensor_data
.data
.powerbook
.z
;
2735 else if( TiltSensor_data
.dataType
== kSMSMacBookProDataType
)
2737 SMSManager::x
= TiltSensor_data
.data
.macbookpro
.x
;
2738 SMSManager::y
= TiltSensor_data
.data
.macbookpro
.y
;
2739 SMSManager::z
= TiltSensor_data
.data
.macbookpro
.z
;
2742 usleep( SMSManager::wait_time
);
2752 SAFE_DELETE( SMSManager::the_thread
);
2759 t_CKBOOL
SMSManager::init()
2762 if( the_thread
!= NULL
)
2765 EM_log( CK_LOG_INFO
, "initializing SMSManager..." );
2769 the_thread
= new XThread
;
2770 the_thread
->start( sms_loop
, NULL
);
2777 void SMSManager::shutdown()
2779 EM_log( CK_LOG_INFO
, "shutting down SMSManager..." );
2787 void SMSManager::on()
2794 void SMSManager::off()
2800 static int TiltSensor_test( int kernFunc
, char * servMatch
, int dataType
)
2802 kern_return_t result
;
2803 io_iterator_t iterator
;
2804 io_object_t aDevice
;
2805 io_connect_t dataPort
;
2807 IOItemCount structureInputSize
;
2808 IOByteCount structureOutputSize
;
2811 EM_log( CK_LOG_FINE
, "testing for SMS sensor..." );
2813 CFMutableDictionaryRef matchingDictionary
= IOServiceMatching( servMatch
);
2815 result
= IOServiceGetMatchingServices( kIOMasterPortDefault
, matchingDictionary
, &iterator
);
2817 if( result
!= KERN_SUCCESS
)
2820 aDevice
= IOIteratorNext( iterator
);
2821 IOObjectRelease( iterator
);
2826 result
= IOServiceOpen( aDevice
, mach_task_self(), 0, &dataPort
);
2827 IOObjectRelease( aDevice
);
2829 if ( result
!= KERN_SUCCESS
)
2834 case kSMSPowerbookDataType
:
2835 structureInputSize
= sizeof( TiltSensor_data
.data
.powerbook
);
2836 structureOutputSize
= sizeof( TiltSensor_data
.data
.powerbook
);
2839 case kSMSMacBookProDataType
:
2840 structureInputSize
= sizeof( TiltSensor_data
.data
.macbookpro
);
2841 structureOutputSize
= sizeof( TiltSensor_data
.data
.macbookpro
);
2845 IOServiceClose( dataPort
);
2849 memset( &TiltSensor_data
.data
, 0, sizeof( TiltSensor_data
.data
) );
2850 memset( &TiltSensor_data
.data
, 0, sizeof( TiltSensor_data
.data
) );
2852 result
= IOConnectMethodStructureIStructureO( dataPort
,
2855 &structureOutputSize
,
2856 &TiltSensor_data
.data
,
2857 &TiltSensor_data
.data
);
2859 if ( result
!= KERN_SUCCESS
)
2861 IOServiceClose( dataPort
);
2865 // leave dataPort open for future use
2866 TiltSensor_data
.dataPort
= dataPort
;
2871 static int TiltSensor_do_read()
2873 kern_return_t result
;
2874 IOItemCount structureInputSize
;
2875 IOByteCount structureOutputSize
;
2878 EM_log( CK_LOG_FINE
, "reading SMS sensor..." );
2880 switch( TiltSensor_data
.dataType
)
2882 case kSMSPowerbookDataType
:
2883 structureInputSize
= sizeof( TiltSensor_data
.data
.powerbook
);
2884 structureOutputSize
= sizeof( TiltSensor_data
.data
.powerbook
);
2887 case kSMSMacBookProDataType
:
2888 structureInputSize
= sizeof( TiltSensor_data
.data
.macbookpro
);
2889 structureOutputSize
= sizeof( TiltSensor_data
.data
.macbookpro
);
2896 memset( &TiltSensor_data
.data
, 0, sizeof( TiltSensor_data
.data
) );
2897 memset( &TiltSensor_data
.data
, 0, sizeof( TiltSensor_data
.data
) );
2899 result
= IOConnectMethodStructureIStructureO( TiltSensor_data
.dataPort
,
2900 TiltSensor_data
.kernFunc
,
2902 &structureOutputSize
,
2903 &TiltSensor_data
.data
,
2904 &TiltSensor_data
.data
);
2909 static int TiltSensor_detect()
2911 // try different interfaces until we find one that works
2914 int powerbookKernFunc
= 0;
2917 EM_log( CK_LOG_FINE
, "detecting SMS sensor..." );
2919 Gestalt( gestaltSystemVersion
, &osx_version
);
2921 if( osx_version
== 0x1040 ||
2922 osx_version
== 0x1041 ||
2923 osx_version
== 0x1042 ||
2924 osx_version
== 0x1043 )
2925 powerbookKernFunc
= 24;
2928 powerbookKernFunc
= 21;
2930 fprintf( stdout
, "osx_version = %d \n", osx_version
);
2932 // ibook/powerbook (OS X 10.4.x) tilt sensor interface
2933 if( TiltSensor_test( powerbookKernFunc
, "IOI2CMotionSensor", kSMSPowerbookDataType
) )
2935 TiltSensor_data
.kernFunc
= powerbookKernFunc
;
2936 TiltSensor_data
.dataType
= kSMSPowerbookDataType
;
2937 TiltSensor_data
.detected
= 1;
2941 // hi resolution powerbook tilt sensor interface
2942 if( TiltSensor_test( powerbookKernFunc
, "PMUMotionSensor", kSMSPowerbookDataType
) )
2944 TiltSensor_data
.kernFunc
= powerbookKernFunc
;
2945 TiltSensor_data
.dataType
= kSMSPowerbookDataType
;
2946 TiltSensor_data
.detected
= 1;
2950 // mac book (pro) tilt sensor interface
2951 if( TiltSensor_test( 5, "SMCMotionSensor", kSMSMacBookProDataType
) )
2953 TiltSensor_data
.kernFunc
= 5;
2954 TiltSensor_data
.dataType
= kSMSMacBookProDataType
;
2955 TiltSensor_data
.detected
= 1;
2959 TiltSensor_data
.detected
= -1;
2964 void TiltSensor_init()
2969 void TiltSensor_quit()
2972 EM_log( CK_LOG_FINE
, "quiting SMS bridge..." );
2974 if( TiltSensor_data
.dataPort
== 0 )
2975 IOServiceClose( TiltSensor_data
.dataPort
);
2978 void TiltSensor_probe()
2983 int TiltSensor_count()
2986 EM_log( CK_LOG_FINE
, "counting SMS sensors..." );
2988 if( TiltSensor_data
.detected
== 0 )
2989 TiltSensor_detect();
2991 if( TiltSensor_data
.detected
== -1 )
2994 else if( TiltSensor_data
.detected
== 1 )
3000 int TiltSensor_open( int ts
)
3003 EM_log( CK_LOG_FINE
, "opening SMS sensor..." );
3006 if( TiltSensor_data
.detected
== 0 )
3007 TiltSensor_detect();
3009 if( TiltSensor_data
.detected
== -1 )
3012 TiltSensor_data
.refcount
++;
3024 int TiltSensor_close( int ts
)
3026 TiltSensor_data
.refcount
--;
3030 if( TiltSensor_data
.refcount
<= 0 )
3031 SMSManager::shutdown();
3036 const char * TiltSensor_name( int ts
)
3038 return "Apple Sudden Motion Sensor";
3041 int TiltSensor_read( int ts
, int type
, int num
, HidMsg
* msg
)
3043 if( type
!= CK_HID_ACCELEROMETER
)
3046 if( TiltSensor_data
.detected
== -1 )
3049 // ge: no longer need in the multi-threaded case...
3050 // if( !TiltSensor_do_read() )
3053 // ge: use sms multi-threaded
3054 msg
->idata
[0] = SMSManager::x
;
3055 msg
->idata
[1] = SMSManager::y
;
3056 msg
->idata
[2] = SMSManager::z
;
3061 #ifdef __CK_HID_WIIREMOTE__
3062 #pragma mark OS X Wii Remote support
3064 class Bluetooth_Device
: public lockable
3070 memset( &address
, 0, sizeof( address
) );
3071 strncpy( name
, "Bluetooth Device", 256 );
3072 interrupt_channel
= NULL
;
3073 control_channel
= NULL
;
3074 disconnect_notification
= NULL
;
3082 virtual ~Bluetooth_Device()
3087 virtual t_CKINT
open() { return -1; }
3088 virtual t_CKINT
connect() { return -1; }
3089 virtual t_CKINT
control_init() { return -1; }
3090 virtual t_CKINT
interrupt_init() { return -1; }
3091 virtual t_CKINT
disconnect() { return -1; }
3092 virtual t_CKINT
close() { return -1; }
3093 virtual t_CKBOOL
is_connected() { return FALSE
; }
3095 virtual void control_receive( void * data
, size_t size
) {};
3096 virtual void interrupt_receive( void * data
, size_t size
) {};
3098 virtual void control_send( void * data
, size_t size
) {};
3099 virtual void interrupt_send( void * data
, size_t size
) {};
3101 IOBluetoothDeviceRef device
;
3102 BluetoothDeviceAddress address
;
3103 IOBluetoothL2CAPChannelRef interrupt_channel
;
3104 IOBluetoothL2CAPChannelRef control_channel
;
3105 IOBluetoothUserNotificationRef disconnect_notification
;
3113 class WiiRemote
: public Bluetooth_Device
3120 ExtensionClassicController
3127 force_feedback_enabled
= FALSE
;
3128 motion_sensor_enabled
= FALSE
;
3129 ir_sensor_enabled
= FALSE
;
3130 ir_sensor_initialized
= FALSE
;
3131 extension_enabled
= FALSE
;
3132 led1
= led2
= led3
= led4
= FALSE
;
3133 speaker_enabled
= FALSE
;
3134 connected_extension
= ExtensionNone
;
3136 audio_buffer
= NULL
;
3137 memset( &buttons
, 0, sizeof( buttons
) );
3138 memset( &accels
, 0, sizeof( accels
) );
3139 memset( &ir
, 0xff, sizeof( ir
) );
3140 memset( &extension
, 0, sizeof( extension
) );
3141 extension
[5] |= 0x03;
3144 virtual t_CKINT
open();
3145 virtual t_CKINT
connect();
3146 virtual t_CKINT
control_init();
3147 virtual t_CKINT
disconnect();
3148 virtual t_CKINT
close();
3149 virtual t_CKBOOL
is_connected();
3151 virtual void control_receive( void * data
, size_t size
);
3152 virtual void interrupt_receive( void * data
, size_t size
);
3154 virtual void control_send( const void * data
, unsigned int size
);
3155 virtual void write_memory( const void * data
, unsigned int size
, unsigned int address
);
3156 virtual void read_memory( unsigned int address
, unsigned int size
);
3158 virtual void check_extension();
3160 virtual void enable_peripherals( t_CKBOOL force_feedback
,
3161 t_CKBOOL motion_sensor
,
3163 t_CKBOOL extension
);
3164 virtual void enable_force_feedback( t_CKBOOL enable
);
3165 virtual void enable_motion_sensor( t_CKBOOL enable
);
3166 virtual void enable_ir_sensor( t_CKBOOL enable
);
3167 virtual void enable_extension( t_CKBOOL enable
);
3168 virtual void enable_leds( t_CKBOOL l1
, t_CKBOOL l2
,
3169 t_CKBOOL l3
, t_CKBOOL l4
);
3170 virtual void set_led( t_CKUINT led
, t_CKBOOL state
);
3171 virtual void enable_speaker( t_CKBOOL enable
);
3173 CFRunLoopTimerRef timer
;
3174 CBufferSimple
* audio_buffer
;
3175 virtual void send_audio_data();
3179 virtual void initialize_ir_sensor();
3181 t_CKBOOL force_feedback_enabled
;
3182 t_CKBOOL motion_sensor_enabled
;
3183 t_CKBOOL ir_sensor_enabled
;
3184 t_CKBOOL ir_sensor_initialized
;
3185 t_CKBOOL extension_enabled
;
3186 t_CKBOOL led1
, led2
, led3
, led4
;
3187 t_CKBOOL speaker_enabled
;
3189 t_CKBYTE buttons
[2];
3192 t_CKBYTE extension
[6];
3194 Extension connected_extension
;
3214 bool operator< ( BluetoothDeviceAddress a
, BluetoothDeviceAddress b
)
3216 for( int i
= 0; i
< 6; i
++ )
3218 if( a
.data
[i
] < b
.data
[i
] )
3220 if( a
.data
[i
] > b
.data
[i
] )
3227 static xvector
< WiiRemote
* > * wiiremotes
= NULL
;
3229 /* the user can open a wiimote with any id number he chooses without an error,
3230 and will then be sent the appropriate message when that wiimote is connected.
3231 The nth wiimote is simply the nth wiimote that chuck hid detects, and since
3232 there is absolutely no way to determine how many wiimotes will connect in
3233 advance, this number must be left unbounded. To support this, WiiRemote_open
3234 will add empty WiiRemotes to wiiremotes with refcount of 1 if it the wiimote
3235 its opening isnt there yet, and hope it will be opened at some future time.
3236 Thus when discovering wiimotes we have to distinguish between wiimotes that have
3237 been discovered and wiimotes that have been opened but have not yet been
3238 discovered. all wiimotes with indices less than g_wr_next_real_wiimote have
3239 actually been discovered, and anything at or above that index in wiiremotes has
3240 not actually been discovered, but (if its non-NULL) has been opened. */
3241 static xvector
< WiiRemote
* >::size_type g_next_real_wiimote
= 0;
3243 static map
< BluetoothDeviceAddress
, WiiRemote
* > * wr_addresses
= NULL
;
3244 static t_CKBOOL g_bt_query_active
= FALSE
; // is a query currently active?
3246 void Bluetooth_device_connected( void * userRefCon
,
3247 IOBluetoothDeviceRef deviceRef
,
3250 if( status
== noErr
)
3251 ( ( Bluetooth_Device
* ) userRefCon
)->connect();
3253 EM_log( CK_LOG_WARNING
, "hid: error: opening Wii Remote Controller connection" );
3256 void Bluetooth_device_control_event( IOBluetoothL2CAPChannelRef l2capChannel
,
3258 IOBluetoothL2CAPChannelEvent
* event
)
3260 switch( event
->eventType
)
3262 case kIOBluetoothL2CAPChannelEventTypeOpenComplete
:
3263 ( ( Bluetooth_Device
* ) refCon
)->control_init();
3266 case kIOBluetoothL2CAPChannelEventTypeData
:
3267 ( ( Bluetooth_Device
* ) refCon
)->control_receive( event
->u
.data
.dataPtr
,
3268 event
->u
.data
.dataSize
);
3271 case kIOBluetoothL2CAPChannelEventTypeWriteComplete
:
3272 if( event
->status
!= noErr
)
3274 EM_log( CK_LOG_WARNING
, "hid: error: writing data to control L2CAP channel for '%s'",
3275 ( ( Bluetooth_Device
* ) refCon
)->name
);
3280 case kIOBluetoothL2CAPChannelEventTypeClosed
:
3281 EM_log( CK_LOG_FINE
, "hid: error: control L2CAP channel for '%s' closed",
3282 ( ( Bluetooth_Device
* ) refCon
)->name
);
3287 void Bluetooth_device_interrupt_event( IOBluetoothL2CAPChannelRef l2capChannel
,
3289 IOBluetoothL2CAPChannelEvent
* event
)
3291 switch( event
->eventType
)
3293 case kIOBluetoothL2CAPChannelEventTypeData
:
3294 ( ( Bluetooth_Device
* ) refCon
)->control_receive( event
->u
.data
.dataPtr
,
3295 event
->u
.data
.dataSize
);
3300 void Bluetooth_device_disconnected( void * userRefCon
,
3301 IOBluetoothUserNotificationRef inRef
,
3302 IOBluetoothObjectRef objectRef
)
3304 ( ( Bluetooth_Device
* ) userRefCon
)->disconnect();
3307 void WiiRemote_send_audio_data( CFRunLoopTimerRef timer
, void *info
)
3309 WiiRemote
* wr
= ( WiiRemote
* ) info
;
3310 wr
->send_audio_data();
3313 t_CKINT
WiiRemote::open()
3315 // see if its already connected, reconnect if so
3316 if( IOBluetoothDeviceIsConnected( device
) )
3318 if( IOBluetoothDeviceCloseConnection( device
) != noErr
)
3320 EM_log( CK_LOG_WARNING
, "hid: error: closing Wii Remote Controller connection" );
3325 if( IOBluetoothDeviceOpenConnection( device
, Bluetooth_device_connected
,
3328 EM_log( CK_LOG_WARNING
, "hid: error: opening Wii Remote Controller connection" );
3335 t_CKINT
WiiRemote::connect()
3337 disconnect_notification
= IOBluetoothDeviceRegisterForDisconnectNotification( device
,
3338 Bluetooth_device_disconnected
,
3341 if( disconnect_notification
== NULL
)
3343 EM_log( CK_LOG_WARNING
, "hid: error: registering for Wii Remote Controller disconnection notification" );
3347 if( IOBluetoothDeviceOpenL2CAPChannelAsync( device
, &control_channel
, 17,
3348 Bluetooth_device_control_event
,
3349 this ) != kIOReturnSuccess
)
3351 EM_log( CK_LOG_WARNING
, "hid: error: opening Wii Remote Controller L2CAP connection" );
3354 //fprintf( stderr, "l2cap control channel ref: 0x%x\n", control_channel );
3355 if( IOBluetoothDeviceOpenL2CAPChannelAsync( device
, &interrupt_channel
, 19,
3356 Bluetooth_device_interrupt_event
,
3357 this ) != kIOReturnSuccess
)
3359 EM_log( CK_LOG_WARNING
, "hid: error: opening Wii Remote Controller L2CAP connection" );
3366 t_CKINT
WiiRemote::control_init()
3370 //enable_motion_sensor( TRUE );
3371 //enable_ir_sensor( TRUE );
3372 //enable_force_feedback( FALSE );
3373 //enable_extension( TRUE );
3375 enable_peripherals( FALSE
, TRUE
, TRUE
, TRUE
);
3378 enable_leds( ( num
% 4 ) == 0, ( ( num
- 1 ) % 4 ) == 0,
3379 ( ( num
- 2 ) % 4 ) == 0, ( ( num
- 3 ) % 4 ) == 0 );
3382 enable_speaker( FALSE
);
3386 msg
.device_num
= num
;
3387 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3388 msg
.type
= CK_HID_DEVICE_CONNECTED
;
3390 HidInManager::push_message( msg
);
3395 t_CKINT
WiiRemote::disconnect()
3397 if( interrupt_channel
)
3399 IOBluetoothL2CAPChannelCloseChannel( interrupt_channel
);
3400 IOBluetoothObjectRelease( interrupt_channel
);
3401 interrupt_channel
= NULL
;
3404 if( control_channel
)
3406 IOBluetoothL2CAPChannelCloseChannel( control_channel
);
3407 IOBluetoothObjectRelease( control_channel
);
3408 control_channel
= NULL
;
3413 IOBluetoothDeviceCloseConnection( device
);
3414 IOBluetoothObjectRelease( device
);
3418 if( disconnect_notification
)
3420 IOBluetoothUserNotificationUnregister( disconnect_notification
);
3421 disconnect_notification
= NULL
;
3426 msg
.device_num
= num
;
3427 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3428 msg
.type
= CK_HID_DEVICE_DISCONNECTED
;
3430 HidInManager::push_message( msg
);
3435 t_CKINT
WiiRemote::close()
3437 if( is_connected() )
3442 t_CKBOOL
WiiRemote::is_connected()
3444 if( device
== NULL
)
3449 static inline unsigned char wii_remote_extension_decrypt( unsigned char b
)
3451 return ( ( b
^ 0x17 ) + 0x17 & 0xFF );
3454 void WiiRemote::control_receive( void * data
, size_t size
)
3456 unsigned char * d
= ( unsigned char * ) data
;
3459 if( ( d
[1] & 0xf0 ) == 0x30 )
3463 if( ( d
[3] & 0x80 ) ^ ( buttons
[1] & 0x80 ) )
3465 msg
.device_num
= num
;
3466 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3467 msg
.type
= ( d
[3] & 0x80 ) ? CK_HID_BUTTON_DOWN
: CK_HID_BUTTON_UP
;
3468 msg
.eid
= ButtonHome
;
3470 HidInManager::push_message( msg
);
3475 if( ( d
[3] & 0x02 ) ^ ( buttons
[1] & 0x02 ) )
3477 msg
.device_num
= num
;
3478 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3479 msg
.type
= ( d
[3] & 0x02 ) ? CK_HID_BUTTON_DOWN
: CK_HID_BUTTON_UP
;
3482 HidInManager::push_message( msg
);
3487 if( ( d
[3] & 0x01 ) ^ ( buttons
[1] & 0x01 ) )
3489 msg
.device_num
= num
;
3490 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3491 msg
.type
= ( d
[3] & 0x01 ) ? CK_HID_BUTTON_DOWN
: CK_HID_BUTTON_UP
;
3494 HidInManager::push_message( msg
);
3499 if( ( d
[2] & 0x10 ) ^ ( buttons
[0] & 0x10 ) )
3501 msg
.device_num
= num
;
3502 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3503 msg
.type
= ( d
[2] & 0x10 ) ? CK_HID_BUTTON_DOWN
: CK_HID_BUTTON_UP
;
3504 msg
.eid
= ButtonPlus
;
3506 HidInManager::push_message( msg
);
3511 if( ( d
[3] & 0x10 ) ^ ( buttons
[1] & 0x10 ) )
3513 msg
.device_num
= num
;
3514 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3515 msg
.type
= ( d
[3] & 0x10 ) ? CK_HID_BUTTON_DOWN
: CK_HID_BUTTON_UP
;
3516 msg
.eid
= ButtonMinus
;
3518 HidInManager::push_message( msg
);
3523 if( ( d
[3] & 0x08 ) ^ ( buttons
[1] & 0x08 ) )
3525 msg
.device_num
= num
;
3526 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3527 msg
.type
= ( d
[3] & 0x08 ) ? CK_HID_BUTTON_DOWN
: CK_HID_BUTTON_UP
;
3530 HidInManager::push_message( msg
);
3535 if( ( d
[3] & 0x04 ) ^ ( buttons
[1] & 0x04 ) )
3537 msg
.device_num
= num
;
3538 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3539 msg
.type
= ( d
[3] & 0x04 ) ? CK_HID_BUTTON_DOWN
: CK_HID_BUTTON_UP
;
3542 HidInManager::push_message( msg
);
3547 if( ( d
[2] & 0x08 ) ^ ( buttons
[0] & 0x08 ) )
3549 msg
.device_num
= num
;
3550 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3551 msg
.type
= ( d
[2] & 0x08 ) ? CK_HID_BUTTON_DOWN
: CK_HID_BUTTON_UP
;
3554 HidInManager::push_message( msg
);
3559 if( ( d
[2] & 0x02 ) ^ ( buttons
[0] & 0x02 ) )
3561 msg
.device_num
= num
;
3562 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3563 msg
.type
= ( d
[2] & 0x02 ) ? CK_HID_BUTTON_DOWN
: CK_HID_BUTTON_UP
;
3564 msg
.eid
= ButtonRight
;
3566 HidInManager::push_message( msg
);
3571 if( ( d
[2] & 0x04 ) ^ ( buttons
[0] & 0x04 ) )
3573 msg
.device_num
= num
;
3574 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3575 msg
.type
= ( d
[2] & 0x04 ) ? CK_HID_BUTTON_DOWN
: CK_HID_BUTTON_UP
;
3576 msg
.eid
= ButtonDown
;
3578 HidInManager::push_message( msg
);
3583 if( ( d
[2] & 0x01 ) ^ ( buttons
[0] & 0x01 ) )
3585 msg
.device_num
= num
;
3586 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3587 msg
.type
= ( d
[2] & 0x01 ) ? CK_HID_BUTTON_DOWN
: CK_HID_BUTTON_UP
;
3588 msg
.eid
= ButtonLeft
;
3590 HidInManager::push_message( msg
);
3595 memcpy( buttons
, d
+ 2, sizeof( buttons
) );
3597 /* accelerometers */
3600 if( d
[4] ^ accels
[0] ||
3604 msg
.device_num
= num
;
3605 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3606 msg
.type
= CK_HID_ACCELEROMETER
;
3608 msg
.idata
[0] = d
[4];
3609 msg
.idata
[1] = d
[5];
3610 msg
.idata
[2] = d
[6];
3612 HidInManager::push_message( msg
);
3617 memcpy( accels
, d
+ 4, sizeof( accels
) );
3625 if( !( d
[1] & 0x04 ) )
3627 for( i
= 0; i
< 4; i
++ )
3629 // 12 byte extended IR data format
3630 // available when there are no extension bytes
3631 if( ( d
[7 + i
* 3] ^ ir
[i
* 3] ||
3632 d
[7 + i
* 3 + 1] ^ ir
[i
* 3 + 1] ||
3633 d
[7 + i
* 3 + 2] ^ ir
[i
* 3 + 2] ) &&
3634 ( d
[7 + i
* 3] != 0xff ) &&
3635 ( d
[7 + i
* 3 + 1] != 0xff ) &&
3636 ( d
[7 + i
* 3 + 2] != 0xff ) )
3638 msg
.device_num
= num
;
3639 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3640 msg
.type
= CK_HID_WIIREMOTE_IR
;
3643 msg
.idata
[0] = d
[7 + 3 * i
] + ( ( d
[7 + 3 * i
+ 2] << 4 ) & 0x300 );
3645 msg
.idata
[1] = d
[7 + 3 * i
+ 1] + ( ( d
[7 + 3 * i
+ 2] << 2 ) & 0x300 );
3647 msg
.idata
[2] = d
[7 + 3 * i
+ 2] & 0xffff;
3649 HidInManager::push_message( msg
);
3658 // 9 byte basic IR data format
3659 // available when there are no extension bytes
3662 memcpy( ir
, d
+ 7, sizeof( ir
) );
3668 for( int i
= 0; i
< 6; i
++ )
3669 d
[17 + i
] = wii_remote_extension_decrypt( d
[17 + i
] );
3671 switch( connected_extension
)
3673 case ExtensionNunchuk
:
3674 if( d
[17] ^ extension
[0] ||
3675 d
[18] ^ extension
[1] )
3678 msg
.device_num
= num
;
3679 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3680 msg
.type
= CK_HID_JOYSTICK_AXIS
;
3684 msg
.idata
[0] = d
[17];
3686 msg
.idata
[1] = d
[18];
3688 HidInManager::push_message( msg
);
3693 if( d
[19] ^ extension
[2] ||
3694 d
[20] ^ extension
[3] ||
3695 d
[21] ^ extension
[4] )
3697 msg
.device_num
= num
;
3698 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3699 msg
.type
= CK_HID_ACCELEROMETER
;
3703 msg
.idata
[0] = d
[19];
3705 msg
.idata
[1] = d
[20];
3707 msg
.idata
[2] = d
[21];
3709 HidInManager::push_message( msg
);
3714 if( ( d
[22] & ( 1 << 0 ) ) ^ ( extension
[5] & ( 1 << 0 ) ) )
3716 msg
.device_num
= num
;
3717 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3718 msg
.type
= ( d
[22] & ( 1 << 0 ) ) ? CK_HID_BUTTON_UP
: CK_HID_BUTTON_DOWN
;
3721 HidInManager::push_message( msg
);
3726 if( ( d
[22] & ( 1 << 1 ) ) ^ ( extension
[5] & ( 1 << 1 ) ) )
3728 msg
.device_num
= num
;
3729 msg
.device_type
= CK_HID_DEV_WIIREMOTE
;
3730 msg
.type
= ( d
[22] & ( 1 << 1 ) ) ? CK_HID_BUTTON_UP
: CK_HID_BUTTON_DOWN
;
3733 HidInManager::push_message( msg
);
3741 memcpy( extension
, d
+ 17, 6 );
3745 else if( d
[1] == 0x21 )
3749 // read memory packet
3750 if( ( d
[4] & 0xf0 ) == 0x10 && // size = 2
3751 d
[5] == 0x00 && // address = 0x04a400fe (but we only have the first 2 bytes of that here)
3754 unsigned char ext0
= wii_remote_extension_decrypt( d
[7] );
3755 unsigned char ext1
= wii_remote_extension_decrypt( d
[8] );
3757 if( ext0
== 0x00 && ext1
== 0x00 )
3758 connected_extension
= ExtensionNunchuk
;
3759 else if( ext0
== 0x01 && ext1
== 0x01 )
3760 connected_extension
= ExtensionClassicController
;
3762 connected_extension
= ExtensionNone
;
3767 void WiiRemote::interrupt_receive( void * data
, size_t size
)
3772 void WiiRemote::control_send( const void * data
, unsigned int size
)
3774 assert( size
<= 22 );
3776 unsigned char buf
[23];
3778 memset( buf
, 0, 23 );
3780 memcpy( buf
+1, data
, size
);
3784 //printf( "send (%i):", size );
3785 //for( int i = 0; i < size; i++ )
3786 // printf( " %02x", buf[i] );
3788 //fprintf( stderr, "l2cap control channel ref: 0x%x\n", control_channel );
3791 result
= IOBluetoothL2CAPChannelWriteSync( control_channel
, buf
, size
);
3792 //IOReturn result = IOBluetoothL2CAPChannelWriteAsync( control_channel, buf, size, NULL );
3794 if( result
!= kIOReturnSuccess
)
3795 EM_log( CK_LOG_WARNING
,
3796 "hid: error: sending data to Wii Remote Controller %i (error 0x%x)",
3800 void WiiRemote::write_memory( const void * data
, unsigned int size
,
3801 unsigned int address
)
3803 assert( size
<= 16 );
3805 unsigned char cmd
[22];
3807 memset( cmd
, 0, 22 );
3810 cmd
[1] = ( address
>> 24 ) & 0xff;
3811 cmd
[2] = ( address
>> 16 ) & 0xff;
3812 cmd
[3] = ( address
>> 8 ) & 0xff;
3813 cmd
[4] = address
& 0xff;
3816 memcpy( cmd
+ 6, data
, size
);
3818 if( force_feedback_enabled
)
3821 control_send( cmd
, 22 );
3824 void WiiRemote::read_memory( unsigned int address
, unsigned int size
)
3826 unsigned char cmd
[7];
3829 cmd
[1] = ( address
>> 24 ) & 0xff;
3830 cmd
[2] = ( address
>> 16 ) & 0xff;
3831 cmd
[3] = ( address
>> 8 ) & 0xff;
3832 cmd
[4] = address
& 0xff;
3833 cmd
[5] = ( size
>> 8 ) & 0xff;
3834 cmd
[6] = ( size
>> 0 ) & 0xff;
3836 if( force_feedback_enabled
)
3839 control_send( cmd
, 7 );
3842 void WiiRemote::check_extension()
3844 unsigned char key
[] = { 0x00 };
3847 write_memory( key
, 1, 0x04a40040 );
3849 // read extension id
3850 read_memory( 0x04a400fe, 2 );
3853 void WiiRemote::enable_peripherals( t_CKBOOL force_feedback
,
3854 t_CKBOOL motion_sensor
,
3856 t_CKBOOL extension
)
3858 force_feedback_enabled
= force_feedback
;
3859 motion_sensor_enabled
= motion_sensor
;
3860 ir_sensor_enabled
= ir_sensor
;
3861 extension_enabled
= extension
;
3863 unsigned char cmd
[] = { 0x12, 0x00, 0x30 };
3864 if( motion_sensor_enabled
)
3866 if( ir_sensor_enabled
)
3868 if( extension_enabled
)
3870 if( force_feedback_enabled
)
3873 control_send( cmd
, 3 );
3875 unsigned char cmd2
[] = { 0x13, 0x00 };
3876 if( force_feedback_enabled
)
3878 if( ir_sensor_enabled
)
3881 control_send( cmd2
, 2 );
3883 if( ir_sensor_enabled
&& !ir_sensor_initialized
)
3884 initialize_ir_sensor();
3887 void WiiRemote::enable_force_feedback( t_CKBOOL enable
)
3889 force_feedback_enabled
= enable
;
3891 unsigned char cmd
[] = { 0x13, 0x00 };
3894 if( ir_sensor_enabled
)
3897 control_send( cmd
, 2 );
3900 void WiiRemote::enable_motion_sensor( t_CKBOOL enable
)
3902 motion_sensor_enabled
= enable
;
3904 unsigned char cmd
[] = { 0x12, 0x00, 0x30 };
3905 if( motion_sensor_enabled
)
3907 if( ir_sensor_enabled
)
3909 if( extension_enabled
)
3911 if( force_feedback_enabled
)
3914 control_send( cmd
, 3 );
3917 void WiiRemote::enable_ir_sensor( t_CKBOOL enable
)
3919 ir_sensor_enabled
= enable
;
3921 enable_motion_sensor( motion_sensor_enabled
);
3922 enable_force_feedback( force_feedback_enabled
);
3924 unsigned char cmd
[] = { 0x1a, 0x00 };
3925 if( ir_sensor_enabled
)
3927 if( force_feedback_enabled
)
3930 control_send( cmd
, 2 );
3932 if( ir_sensor_enabled
&& !ir_sensor_initialized
)
3933 initialize_ir_sensor();
3936 void WiiRemote::initialize_ir_sensor()
3938 ir_sensor_initialized
= TRUE
;
3940 unsigned char en0
[] = { 0x01 };
3941 write_memory( en0
, 1, 0x04b00030 );
3944 unsigned char en
[] = { 0x08 };
3945 write_memory( en
, 1, 0x04b00030 );
3948 unsigned char sensitivity_block1
[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0xc0 };
3949 write_memory( sensitivity_block1
, 9, 0x04b00000 );
3952 unsigned char sensitivity_block2
[] = { 0x40, 0x00 };
3953 write_memory( sensitivity_block2
, 2, 0x04b0001a );
3956 unsigned char mode
[] = { 0x03 };
3957 write_memory( mode
, 1, 0x04b00033 );
3960 unsigned char what
[] = { 0x08 };
3961 write_memory( what
, 1, 0x04b00030 );
3965 void WiiRemote::enable_extension( t_CKBOOL enable
)
3967 extension_enabled
= enable
;
3969 enable_motion_sensor( motion_sensor_enabled
);
3972 void WiiRemote::set_led( t_CKUINT led
, t_CKBOOL state
)
3993 enable_leds( led1
, led2
, led3
, led4
);
3996 void WiiRemote::enable_leds( t_CKBOOL l1
, t_CKBOOL l2
,
3997 t_CKBOOL l3
, t_CKBOOL l4
)
4004 unsigned char cmd
[] = { 0x11, 0x00 };
4005 if( force_feedback_enabled
)
4016 control_send( cmd
, 2 );
4019 void WiiRemote::enable_speaker( t_CKBOOL enable
)
4021 speaker_enabled
= enable
;
4023 if( speaker_enabled
)
4026 unsigned char cmd
[] = { 0x14, 0x04 };
4027 if( force_feedback_enabled
)
4029 control_send( cmd
, 2 );
4032 unsigned char mute
[] = { 0x19, 0x04 };
4033 if( force_feedback_enabled
)
4035 control_send( mute
, 2 );
4037 unsigned char mem1
[] = { 0x01 };
4038 write_memory( mem1
, 1, 0x04a20009 );
4040 unsigned char mem2
[] = { 0x08 };
4041 write_memory( mem2
, 1, 0x04a20001 );
4044 unsigned char config
[] = { 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00 };
4049 // 3: sample rate -{ 0x0B = 4200 Hz
4054 // 4: speaker volume
4058 write_memory( config
, 7, 0x04a20001 );
4060 unsigned char mem3
[] = { 0x01 };
4061 write_memory( mem3
, 1, 0x04a20008 );
4064 unsigned char unmute
[] = { 0x19, 0x00 };
4065 if( force_feedback_enabled
)
4067 control_send( unmute
, 2 );
4069 // initialize audio buffer, if necessary
4070 if( audio_buffer
== NULL
)
4072 audio_buffer
= new CBufferSimple
;
4073 audio_buffer
->initialize( 20 * 5, sizeof( SAMPLE
) );
4076 // set up audio timer callback, if necessary
4079 CFRunLoopTimerContext timerContext
= { 0, this, NULL
, NULL
, NULL
};
4080 timer
= CFRunLoopTimerCreate( NULL
, CFAbsoluteTimeGetCurrent(),
4082 WiiRemote_send_audio_data
,
4084 CFRunLoopAddTimer( rlHid
, timer
, kCFRunLoopChuckHidMode
);
4089 void WiiRemote::send_audio_data()
4091 unsigned char cmd
[] = { 0x18, ( 20 << 3 ),
4092 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4093 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
4095 if( force_feedback_enabled
)
4098 control_send( cmd
, 22 );
4101 void Bluetooth_inquiry_device_found( void * userRefCon
,
4102 IOBluetoothDeviceInquiryRef inquiryRef
,
4103 IOBluetoothDeviceRef deviceRef
)
4105 CFStringRef device_name
= IOBluetoothDeviceGetName( deviceRef
);
4106 const BluetoothDeviceAddress
* address
= IOBluetoothDeviceGetAddress( deviceRef
);
4108 if( device_name
== NULL
)
4111 // is device Nintendo Wii Remote controller?
4112 if( CFStringCompare( device_name
, CFSTR( "Nintendo RVL-CNT-01" ), 0 ) == 0 )
4114 // has this already been detected?
4115 if( wr_addresses
->find( *address
) == wr_addresses
->end() )
4119 if( g_next_real_wiimote
>= wiiremotes
->size() )
4122 wiiremotes
->push_back( wr
);
4125 else if( ( *wiiremotes
)[g_next_real_wiimote
] == NULL
)
4128 ( *wiiremotes
)[g_next_real_wiimote
] = wr
;
4133 wr
= ( *wiiremotes
)[g_next_real_wiimote
];
4137 wr
->device
= deviceRef
;
4138 memcpy( &wr
->address
, address
, sizeof( BluetoothDeviceAddress
) );
4139 strncpy( wr
->name
, "Nintendo RVL-CNT-01", 256 );
4140 wr
->num
= g_next_real_wiimote
;
4141 wr
->type
= CK_HID_DEV_WIIREMOTE
;
4143 ( *wr_addresses
)[wr
->address
] = wr
;
4145 EM_log( CK_LOG_INFO
, "hid: found Wii Remote Controller" );
4150 g_next_real_wiimote
++;
4153 else if( !( *wr_addresses
)[*address
]->is_connected() )
4155 WiiRemote
* wr
= ( *wr_addresses
)[*address
];
4164 EM_log( CK_LOG_INFO
, "hid: found bluetooth device" );
4168 int WiiRemote_query();
4170 void Bluetooth_inquiry_complete( void * userRefCon
,
4171 IOBluetoothDeviceInquiryRef inquiryRef
,
4175 g_bt_query_active
= FALSE
;
4177 IOBluetoothDeviceInquiryDelete( inquiryRef
);
4179 t_CKBOOL do_query
= FALSE
;
4180 WiiRemote
* wiiremote
;
4182 for( int i
= 0; i
< wiiremotes
->size(); i
++ )
4184 wiiremote
= ( *wiiremotes
)[i
];
4185 if( wiiremote
->refcount
> 0 && !wiiremote
->is_connected() )
4194 EM_log( CK_LOG_INFO
, "hid: continuing bluetooth query" );
4198 EM_log( CK_LOG_INFO
, "hid: ending bluetooth query" );
4201 int WiiRemote_query()
4203 EM_log( CK_LOG_INFO
, "hid: performing bluetooth query" );
4204 if( g_bt_query_active
)
4207 if( IOBluetoothLocalDeviceAvailable() == FALSE
)
4209 EM_log( CK_LOG_WARNING
, "hid: error: bluetooth unavailable" );
4213 IOBluetoothDeviceInquiryRef btDeviceInquiry
= IOBluetoothDeviceInquiryCreateWithCallbackRefCon( NULL
);
4215 if( btDeviceInquiry
== NULL
)
4217 EM_log( CK_LOG_WARNING
, "hid: error: creating bluetooth device inquiry" );
4221 if( IOBluetoothDeviceInquirySetDeviceFoundCallback( btDeviceInquiry
,
4222 Bluetooth_inquiry_device_found
)
4225 EM_log( CK_LOG_WARNING
, "hid: error: setting bluetooth device inquiry callback" );
4229 if( IOBluetoothDeviceInquirySetCompleteCallback( btDeviceInquiry
,
4230 Bluetooth_inquiry_complete
)
4233 EM_log( CK_LOG_WARNING
, "hid: error: setting bluetooth device inquiry completion callback" );
4237 if( IOBluetoothDeviceInquirySetUpdateNewDeviceNames( btDeviceInquiry
,
4241 EM_log( CK_LOG_WARNING
, "hid: error: setting bluetooth device inquiry name update flag" );
4245 if( IOBluetoothDeviceInquirySetInquiryLength( btDeviceInquiry
, 20 ) != noErr
)
4247 EM_log( CK_LOG_WARNING
, "hid: error: setting bluetooth inquiry length" );
4251 if( IOBluetoothDeviceInquiryStart( btDeviceInquiry
) != noErr
)
4253 EM_log( CK_LOG_WARNING
, "hid: error: starting bluetooth device inquiry" );
4257 g_bt_query_active
= TRUE
;
4262 /* -- WiiRemote inter-thread communication --
4263 Every IOBluetooth function needs to be called from the HID thread because none
4264 of it is thread safe, and it also requires a CFRunLoop to be running at some
4265 point. So, WiiRemote_open and _close, which are called from the VM thread, put
4266 open and close messages into a thread-safe circular buffer and then signal the
4267 hid thread to indicate that new info is available on the cbuf. The hid thread
4268 will then process any pending open/close messages in the cbuf.
4270 send messages now also are carried out in the hid thread through this mechanism.
4285 static CBufferSimple
* WiiRemoteOp_cbuf
= NULL
;
4286 static CBufferSimple
* WiiRemoteOp_msgbuf
= NULL
;
4288 static void WiiRemote_cfrl_callback( void * info
)
4292 t_CKBOOL do_query
= FALSE
;
4294 while( WiiRemoteOp_cbuf
->get( &wro
, 1 ) )
4298 case WiiRemoteOp::open
:
4299 // does it exist already?
4300 if( wro
.index
< wiiremotes
->size() )
4303 // is the device connected?
4304 if( !( *wiiremotes
)[wro
.index
]->is_connected() )
4305 // no, so do a query
4312 while( wro
.index
> wiiremotes
->size() )
4313 wiiremotes
->push_back( NULL
);
4314 wiiremotes
->push_back( new WiiRemote
);
4319 ( *wiiremotes
)[wro
.index
]->refcount
++;
4323 case WiiRemoteOp::close
:
4324 if( wro
.index
< wiiremotes
->size() )
4326 if( --( *wiiremotes
)[wro
.index
]->refcount
== 0 )
4327 ( *wiiremotes
)[wro
.index
]->close();
4332 case WiiRemoteOp::send
:
4333 if( WiiRemoteOp_msgbuf
->get( &msg
, 1 ) )
4335 // double-check remote number for validity
4336 if( wro
.index
< 0 || wro
.index
>= wiiremotes
->size() ||
4337 ( *wiiremotes
)[wro
.index
] == NULL
||
4338 !( *wiiremotes
)[wro
.index
]->is_connected() )
4341 HidInManager::push_message( msg
);
4348 if( msg
.eid
< 0 || msg
.eid
>= 4 )
4351 HidInManager::push_message( msg
);
4355 ( *wiiremotes
)[wro
.index
]->set_led( msg
.eid
, msg
.idata
[0] );
4359 case CK_HID_FORCE_FEEDBACK
:
4360 ( *wiiremotes
)[wro
.index
]->enable_force_feedback( msg
.idata
[0] );
4374 static void WiiRemote_signal()
4376 if( cfrlWiiRemoteSource
&& rlHid
)
4378 CFRunLoopSourceSignal( cfrlWiiRemoteSource
);
4379 CFRunLoopWakeUp( rlHid
);
4383 #endif // __CK_HID_WIIREMOTE
4385 void WiiRemote_init()
4387 #ifdef __CK_HID_WIIREMOTE__
4390 wiiremotes
= new xvector
< WiiRemote
* >;
4391 wr_addresses
= new map
< BluetoothDeviceAddress
, WiiRemote
* >;
4393 WiiRemoteOp_cbuf
= new CBufferSimple
;
4394 WiiRemoteOp_cbuf
->initialize( 20, sizeof( WiiRemoteOp
) );
4396 WiiRemoteOp_msgbuf
= new CBufferSimple
;
4397 WiiRemoteOp_msgbuf
->initialize( 100, sizeof( HidMsg
) );
4398 #endif // __CK_HID_WIIREMOTE
4401 void WiiRemote_poll()
4405 void WiiRemote_quit()
4407 #ifdef __CK_HID_WIIREMOTE__
4408 for( xvector
< WiiRemote
* >::size_type i
= 0; i
< wiiremotes
->size(); i
++ )
4410 if( ( *wiiremotes
)[i
] )
4411 SAFE_DELETE( ( *wiiremotes
)[i
] );
4413 SAFE_DELETE( wiiremotes
);
4414 SAFE_DELETE( wr_addresses
);
4415 SAFE_DELETE( WiiRemoteOp_cbuf
);
4418 #endif // __CK_HID_WIIREMOTE__
4421 int WiiRemote_count()
4423 #ifdef __CK_HID_WIIREMOTE__
4424 return wiiremotes
->size();
4427 #endif // __CK_HID_WIIREMOTE__
4430 int WiiRemote_open( int wr
)
4432 #ifdef __CK_HID_WIIREMOTE__
4434 wro
.op
= WiiRemoteOp::open
;
4437 WiiRemoteOp_cbuf
->put( &wro
, 1 );
4444 #endif // __CK_HID_WIIREMOTE__
4447 int WiiRemote_close( int wr
)
4449 #ifdef __CK_HID_WIIREMOTE__
4451 wro
.op
= WiiRemoteOp::close
;
4454 WiiRemoteOp_cbuf
->put( &wro
, 1 );
4461 #endif // __CK_HID_WIIREMOTE__
4464 int WiiRemote_send( int wr
, const HidMsg
* msg
)
4466 #ifdef __CK_HID_WIIREMOTE__
4469 if( wr
< 0 || wr
>= wiiremotes
->size() )
4471 wiiremotes
->unlock();
4475 WiiRemote
* wiiremote
= ( *wiiremotes
)[wr
];
4477 wiiremotes
->unlock();
4479 if( wiiremote
== NULL
)
4485 if( !wiiremote
->is_connected() )
4487 wiiremote
->unlock();
4491 wiiremote
->unlock();
4493 WiiRemoteOp_msgbuf
->put( ( void * )msg
, 1 );
4496 wro
.op
= WiiRemoteOp::send
;
4499 WiiRemoteOp_cbuf
->put( &wro
, 1 );
4509 const char * WiiRemote_name( int wr
)
4511 #ifdef __CK_HID_WIIREMOTE__
4512 return "Nintendo Wii Remote";
4515 #endif // __CK_HID_WIIREMOTE__
4518 #elif ( defined( __PLATFORM_WIN32__ ) || defined( __WINDOWS_PTHREAD__ ) ) && !defined( USE_RAWINPUT )
4519 /*****************************************************************************
4520 Windows general HID support
4521 *****************************************************************************/
4522 #pragma mark Windows general HID support
4524 #include <windows.h>
4525 #define DIRECTINPUT_VERSION 0x0500
4528 /* for performance, we use device event notifications to tell us when a device
4529 has new data. However, serial devices don't seem to support event
4530 notification, so we have to fall back to the periodic sleeping and polling.
4531 g_wait_function is usually set to call WaitForSingleObject (wait for event
4532 notification), but devices for which SetEventNotification fails will replace
4533 it with a wrapper around usleep. */
4534 static HANDLE g_device_event
= NULL
;
4535 static void (*g_wait_function
)() = NULL
;
4537 static void Hid_wait_usleep()
4542 static void Hid_wait_event()
4544 WaitForSingleObject( g_device_event
, INFINITE
);
4549 if( g_device_event
!= NULL
)
4552 g_device_event
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
4553 if( g_device_event
== NULL
)
4554 EM_log( CK_LOG_SEVERE
, "hid: error: unable to create event (win32 error %i)", GetLastError() );
4555 g_wait_function
= Hid_wait_event
;
4568 SetEvent( g_device_event
);
4569 /*if( g_device_event != NULL )
4571 CloseHandle( g_device_event );
4572 g_device_event = NULL;
4579 /*****************************************************************************
4580 ge: Windows tiltsensor non-support
4581 *****************************************************************************/
4582 // designate new poll rate
4583 t_CKINT
TiltSensor_setPollRate( t_CKINT usec
)
4586 assert( usec
>= 0 );
4588 fprintf( stderr
, "TiltSensor - setPollRate is not (yet) supported on this platform...\n" );
4592 // query current poll rate
4593 t_CKINT
TiltSensor_getPollRate( )
4596 fprintf( stderr
, "TiltSensor - getPollRate is not (yet) supported on this platform...\n" );
4603 /*****************************************************************************
4604 Windows joystick support
4605 *****************************************************************************/
4606 #pragma mark Windows joystick support
4608 static LPDIRECTINPUT lpdi
= NULL
;
4610 struct win32_joystick
4614 lpdiJoystick
= NULL
;
4616 needs_close
= FALSE
;
4617 strncpy( name
, "Joystick", MAX_PATH
);
4618 memset( &last_state
, 0, sizeof( last_state
) );
4619 memset( &caps
, 0, sizeof( caps
) );
4620 caps
.dwSize
= sizeof( DIDEVCAPS
);
4623 LPDIRECTINPUTDEVICE2 lpdiJoystick
;
4624 DIJOYSTATE2 last_state
;
4627 char name
[MAX_PATH
];
4630 t_CKBOOL needs_close
;
4634 const static LONG axis_min
= -32767;
4635 const static LONG axis_max
= 32767;
4638 static vector
< win32_joystick
* > * joysticks
;
4640 static BOOL CALLBACK
DIEnumJoystickProc( LPCDIDEVICEINSTANCE lpddi
,
4643 GUID guid
= lpddi
->guidInstance
;
4644 win32_joystick
* js
= new win32_joystick
;
4646 EM_log( CK_LOG_INFO
, "found %s", lpddi
->tszProductName
);
4648 strncpy( js
->name
, lpddi
->tszProductName
, MAX_PATH
);
4650 if( lpdi
->CreateDevice( guid
, ( LPDIRECTINPUTDEVICE
* )&js
->lpdiJoystick
, NULL
) != DI_OK
)
4653 return DIENUM_CONTINUE
;
4656 joysticks
->push_back( js
);
4658 return DIENUM_CONTINUE
;
4661 static BOOL CALLBACK
DIEnumJoystickObjectsProc( LPCDIDEVICEOBJECTINSTANCE lpdidoi
,
4664 LPDIRECTINPUTDEVICE lpdiJoystick
= ( LPDIRECTINPUTDEVICE
) pvRef
;
4668 // set axis minimum and maximum range
4669 diprg
.diph
.dwSize
= sizeof(DIPROPRANGE
);
4670 diprg
.diph
.dwHeaderSize
= sizeof(DIPROPHEADER
);
4671 diprg
.diph
.dwHow
= DIPH_BYID
;
4672 diprg
.diph
.dwObj
= lpdidoi
->dwType
;
4673 diprg
.lMin
= axis_min
;
4674 diprg
.lMax
= axis_max
;
4676 if( lpdiJoystick
->SetProperty( DIPROP_RANGE
, &diprg
.diph
) != DI_OK
)
4681 return DIENUM_CONTINUE
;
4684 void Joystick_init()
4686 if( joysticks
!= NULL
)
4689 EM_log( CK_LOG_INFO
, "initializing joystick" );
4692 HINSTANCE hInstance
= GetModuleHandle( NULL
);
4696 if( DirectInputCreate( hInstance
, DIRECTINPUT_VERSION
,
4697 &lpdi
, NULL
) != DI_OK
)
4700 EM_log( CK_LOG_SEVERE
, "error: unable to initialize DirectInput, initialization failed" );
4706 joysticks
= new vector
< win32_joystick
* >;
4707 if( lpdi
->EnumDevices( DIDEVTYPE_JOYSTICK
, DIEnumJoystickProc
,
4708 NULL
, DIEDFL_ATTACHEDONLY
) != DI_OK
)
4714 EM_log( CK_LOG_SEVERE
, "error: unable to enumerate devices, initialization failed" );
4722 t_CKINT
Joystick_translate_POV( DWORD v
)
4724 #define CK_POV_CENTER 0
4726 #define CK_POV_RIGHT 2
4727 #define CK_POV_DOWN 4
4728 #define CK_POV_LEFT 8
4730 #define CK_POV_UP_LBORDER 29250
4731 #define CK_POV_UP_RBORDER 6750
4732 #define CK_POV_RIGHT_LBORDER 2250
4733 #define CK_POV_RIGHT_RBORDER 15750
4734 #define CK_POV_DOWN_LBORDER 11250
4735 #define CK_POV_DOWN_RBORDER 24750
4736 #define CK_POV_LEFT_LBORDER 20250
4737 #define CK_POV_LEFT_RBORDER 33750
4741 if( LOWORD(v
) == 0xffff )
4742 return CK_POV_CENTER
;
4744 if( v
> CK_POV_UP_LBORDER
|| v
< CK_POV_UP_RBORDER
)
4746 if( v
> CK_POV_RIGHT_LBORDER
&& v
< CK_POV_RIGHT_RBORDER
)
4748 if( v
> CK_POV_DOWN_LBORDER
&& v
< CK_POV_DOWN_RBORDER
)
4750 if( v
> CK_POV_LEFT_LBORDER
&& v
< CK_POV_LEFT_RBORDER
)
4756 void Joystick_poll()
4761 win32_joystick
* joystick
;
4763 vector
< win32_joystick
* >::size_type i
, len
= joysticks
->size();
4765 for( i
= 0; i
< len
; i
++ )
4767 joystick
= joysticks
->at( i
);
4768 if( joystick
->refcount
)
4770 // TODO: convert this to buffered input, or maybe notifications
4773 joystick
->lpdiJoystick
->Poll();
4775 if( joystick
->lpdiJoystick
->GetDeviceState( sizeof( DIJOYSTATE2
), &state
)
4778 EM_log( CK_LOG_WARNING
, "joystick: GetDeviceState failed for %s", joystick
->name
);
4782 if( state
.lX
!= joystick
->last_state
.lX
)
4786 msg
.device_type
= CK_HID_DEV_JOYSTICK
;
4788 msg
.type
= CK_HID_JOYSTICK_AXIS
;
4789 msg
.fdata
[0] = ((float)state
.lX
)/((float)axis_max
);
4790 HidInManager::push_message( msg
);
4793 if( state
.lY
!= joystick
->last_state
.lY
)
4797 msg
.device_type
= CK_HID_DEV_JOYSTICK
;
4799 msg
.type
= CK_HID_JOYSTICK_AXIS
;
4800 msg
.fdata
[0] = ((float)state
.lY
)/((float)axis_max
);
4801 HidInManager::push_message( msg
);
4804 if( state
.lZ
!= joystick
->last_state
.lZ
)
4808 msg
.device_type
= CK_HID_DEV_JOYSTICK
;
4810 msg
.type
= CK_HID_JOYSTICK_AXIS
;
4811 msg
.fdata
[0] = ((float)state
.lZ
)/((float)axis_max
);
4812 HidInManager::push_message( msg
);
4815 if( state
.lRx
!= joystick
->last_state
.lRx
)
4819 msg
.device_type
= CK_HID_DEV_JOYSTICK
;
4821 msg
.type
= CK_HID_JOYSTICK_AXIS
;
4822 msg
.fdata
[0] = ((float)state
.lRx
)/((float)axis_max
);
4823 HidInManager::push_message( msg
);
4826 if( state
.lRy
!= joystick
->last_state
.lRy
)
4830 msg
.device_type
= CK_HID_DEV_JOYSTICK
;
4832 msg
.type
= CK_HID_JOYSTICK_AXIS
;
4833 msg
.fdata
[0] = ((float)state
.lRy
)/((float)axis_max
);
4834 HidInManager::push_message( msg
);
4837 if( state
.lRz
!= joystick
->last_state
.lRz
)
4841 msg
.device_type
= CK_HID_DEV_JOYSTICK
;
4843 msg
.type
= CK_HID_JOYSTICK_AXIS
;
4844 msg
.fdata
[0] = ((float)state
.lRz
)/((float)axis_max
);
4845 HidInManager::push_message( msg
);
4848 for( j
= 0; j
< 2; j
++ )
4850 if( state
.rglSlider
[j
] != joystick
->last_state
.rglSlider
[j
] )
4854 msg
.device_type
= CK_HID_DEV_JOYSTICK
;
4856 msg
.type
= CK_HID_JOYSTICK_AXIS
;
4857 msg
.fdata
[0] = ((float)state
.rglSlider
[j
])/((float)axis_max
);
4858 HidInManager::push_message( msg
);
4862 for( j
= 0; j
< joystick
->caps
.dwPOVs
&& j
< 4; j
++ )
4864 if( state
.rgdwPOV
[j
] != joystick
->last_state
.rgdwPOV
[j
] )
4868 msg
.device_type
= CK_HID_DEV_JOYSTICK
;
4870 msg
.type
= CK_HID_JOYSTICK_HAT
;
4871 msg
.idata
[0] = Joystick_translate_POV( state
.rgdwPOV
[j
] );
4872 msg
.fdata
[0] = (t_CKFLOAT
)state
.rgdwPOV
[j
];
4873 HidInManager::push_message( msg
);
4877 for( j
= 0; j
< joystick
->caps
.dwButtons
&& j
< 128; j
++ )
4879 if( ( state
.rgbButtons
[j
] & 0x80 ) ^
4880 ( joystick
->last_state
.rgbButtons
[j
] & 0x80 ) )
4884 msg
.device_type
= CK_HID_DEV_JOYSTICK
;
4886 msg
.type
= ( state
.rgbButtons
[j
] & 0x80 ) ? CK_HID_BUTTON_DOWN
:
4888 msg
.idata
[0] = ( state
.rgbButtons
[j
] & 0x80 ) ? 1 : 0;
4889 HidInManager::push_message( msg
);
4893 joystick
->last_state
= state
;
4896 else if( joystick
->needs_close
)
4898 joystick
->needs_close
= FALSE
;
4899 joystick
->lpdiJoystick
->Unacquire();
4900 joystick
->lpdiJoystick
->SetEventNotification( NULL
);
4906 void Joystick_quit()
4910 win32_joystick
* joystick
;
4911 vector
< win32_joystick
* >::size_type i
, len
= joysticks
->size();
4912 for( i
= 0; i
< len
; i
++ )
4914 joystick
= joysticks
->at( i
);
4916 if( joystick
->refcount
> 0 || joystick
->needs_close
)
4918 joystick
->needs_close
= FALSE
;
4919 joystick
->refcount
= 0;
4920 joystick
->lpdiJoystick
->Unacquire();
4921 joystick
->lpdiJoystick
->SetEventNotification( NULL
);
4924 joystick
->lpdiJoystick
->Release();
4939 int Joystick_count()
4943 return joysticks
->size();
4946 int Joystick_open( int js
)
4948 if( !joysticks
|| js
< 0 || js
>= joysticks
->size() )
4951 win32_joystick
* joystick
= joysticks
->at( js
);
4953 if( joystick
->refcount
== 0 )
4955 if( joystick
->lpdiJoystick
->EnumObjects( DIEnumJoystickObjectsProc
,
4956 joystick
->lpdiJoystick
,
4957 DIDFT_AXIS
) != DI_OK
)
4962 if( joystick
->lpdiJoystick
->GetCapabilities( &joystick
->caps
) != DI_OK
)
4967 if( joystick
->lpdiJoystick
->SetDataFormat( &c_dfDIJoystick2
) != DI_OK
)
4972 if( joystick
->lpdiJoystick
->SetEventNotification( g_device_event
) != DI_OK
)
4974 // fallback to sleep+poll mode
4975 g_wait_function
= Hid_wait_usleep
;
4976 SetEvent( g_device_event
);
4979 if( joystick
->lpdiJoystick
->Acquire() != DI_OK
)
4981 joystick
->lpdiJoystick
->SetEventNotification( NULL
);
4986 joystick
->refcount
++;
4991 int Joystick_close( int js
)
4993 if( !joysticks
|| js
< 0 || js
>= joysticks
->size() )
4996 win32_joystick
* joystick
= joysticks
->at( js
);
4998 joystick
->refcount
--;
5000 if( joystick
->refcount
< 1 )
5001 joystick
->needs_close
= TRUE
;
5006 const char * Joystick_name( int js
)
5008 if( !joysticks
|| js
< 0 || js
>= joysticks
->size() )
5011 return joysticks
->at( js
)->name
;
5014 /*****************************************************************************
5015 Windows keyboard support
5016 *****************************************************************************/
5017 #pragma mark Windows keyboards support
5019 #define DINPUT_KEYBUFFER_SIZE 256
5021 struct win32_keyboard
5025 lpdiKeyboard
= NULL
;
5027 needs_close
= FALSE
;
5028 strncpy( name
, "Keyboard", MAX_PATH
);
5029 memset( &last_state
, 0, DINPUT_KEYBUFFER_SIZE
);
5032 LPDIRECTINPUTDEVICE2 lpdiKeyboard
;
5033 char last_state
[DINPUT_KEYBUFFER_SIZE
];
5036 char name
[MAX_PATH
];
5039 t_CKBOOL needs_close
;
5043 static vector
< win32_keyboard
* > * keyboards
;
5045 // table to translate DirectInput keybuffer offsets to ASCII and USB usages
5046 // first element is ASCII
5047 // second element is USB usage
5048 static unsigned short kb_translation_table
[DINPUT_KEYBUFFER_SIZE
];
5050 static void Keyboard_init_translation_table()
5052 memset( &kb_translation_table
, 0, sizeof( kb_translation_table
) );
5054 kb_translation_table
[DIK_0
] = '0';
5055 kb_translation_table
[DIK_0
] |= 0x27 << 8;
5057 kb_translation_table
[DIK_1
] = '1';
5058 kb_translation_table
[DIK_1
] |= 0x1e << 8;
5060 kb_translation_table
[DIK_2
] = '2';
5061 kb_translation_table
[DIK_2
] |= 0x1f << 8;
5063 kb_translation_table
[DIK_3
] = '3';
5064 kb_translation_table
[DIK_3
] |= 0x20 << 8;
5066 kb_translation_table
[DIK_4
] = '4';
5067 kb_translation_table
[DIK_4
] |= 0x21 << 8;
5069 kb_translation_table
[DIK_5
] = '5';
5070 kb_translation_table
[DIK_5
] |= 0x22 << 8;
5072 kb_translation_table
[DIK_6
] = '6';
5073 kb_translation_table
[DIK_6
] |= 0x23 << 8;
5075 kb_translation_table
[DIK_7
] = '7';
5076 kb_translation_table
[DIK_7
] |= 0x24 << 8;
5078 kb_translation_table
[DIK_8
] = '8';
5079 kb_translation_table
[DIK_8
] |= 0x25 << 8;
5081 kb_translation_table
[DIK_9
] = '9';
5082 kb_translation_table
[DIK_9
] |= 0x26 << 8;
5084 kb_translation_table
[DIK_A
] = 'A';
5085 kb_translation_table
[DIK_A
] |= 0x04 << 8;
5087 kb_translation_table
[DIK_B
] = 'B';
5088 kb_translation_table
[DIK_B
] |= 0x05 << 8;
5090 kb_translation_table
[DIK_C
] = 'C';
5091 kb_translation_table
[DIK_C
] |= 0x06 << 8;
5093 kb_translation_table
[DIK_D
] = 'D';
5094 kb_translation_table
[DIK_D
] |= 0x07 << 8;
5096 kb_translation_table
[DIK_E
] = 'E';
5097 kb_translation_table
[DIK_E
] |= 0x08 << 8;
5099 kb_translation_table
[DIK_F
] = 'F';
5100 kb_translation_table
[DIK_F
] |= 0x09 << 8;
5102 kb_translation_table
[DIK_G
] = 'G';
5103 kb_translation_table
[DIK_G
] |= 0x0a << 8;
5105 kb_translation_table
[DIK_H
] = 'H';
5106 kb_translation_table
[DIK_H
] |= 0x0b << 8;
5108 kb_translation_table
[DIK_I
] = 'I';
5109 kb_translation_table
[DIK_I
] |= 0x0c << 8;
5111 kb_translation_table
[DIK_J
] = 'J';
5112 kb_translation_table
[DIK_J
] |= 0x0d << 8;
5114 kb_translation_table
[DIK_K
] = 'K';
5115 kb_translation_table
[DIK_K
] |= 0x0e << 8;
5117 kb_translation_table
[DIK_L
] = 'L';
5118 kb_translation_table
[DIK_L
] |= 0x0f << 8;
5120 kb_translation_table
[DIK_M
] = 'M';
5121 kb_translation_table
[DIK_M
] |= 0x10 << 8;
5123 kb_translation_table
[DIK_N
] = 'N';
5124 kb_translation_table
[DIK_N
] |= 0x11 << 8;
5126 kb_translation_table
[DIK_O
] = 'O';
5127 kb_translation_table
[DIK_O
] |= 0x12 << 8;
5129 kb_translation_table
[DIK_P
] = 'P';
5130 kb_translation_table
[DIK_P
] |= 0x13 << 8;
5132 kb_translation_table
[DIK_Q
] = 'Q';
5133 kb_translation_table
[DIK_Q
] |= 0x14 << 8;
5135 kb_translation_table
[DIK_R
] = 'R';
5136 kb_translation_table
[DIK_R
] |= 0x15 << 8;
5138 kb_translation_table
[DIK_S
] = 'S';
5139 kb_translation_table
[DIK_S
] |= 0x16 << 8;
5141 kb_translation_table
[DIK_T
] = 'T';
5142 kb_translation_table
[DIK_T
] |= 0x17 << 8;
5144 kb_translation_table
[DIK_U
] = 'U';
5145 kb_translation_table
[DIK_U
] |= 0x18 << 8;
5147 kb_translation_table
[DIK_V
] = 'V';
5148 kb_translation_table
[DIK_V
] |= 0x19 << 8;
5150 kb_translation_table
[DIK_W
] = 'W';
5151 kb_translation_table
[DIK_W
] |= 0x1a << 8;
5153 kb_translation_table
[DIK_X
] = 'X';
5154 kb_translation_table
[DIK_X
] |= 0x1b << 8;
5156 kb_translation_table
[DIK_Y
] = 'Y';
5157 kb_translation_table
[DIK_Y
] |= 0x1c << 8;
5159 kb_translation_table
[DIK_Z
] = 'Z';
5160 kb_translation_table
[DIK_Z
] |= 0x1d << 8;
5162 kb_translation_table
[DIK_ADD
] = '+';
5163 kb_translation_table
[DIK_ADD
] |= 0x57 << 8;
5165 kb_translation_table
[DIK_APOSTROPHE
] = '\'';
5166 kb_translation_table
[DIK_APOSTROPHE
] |= 0x34 << 8;
5168 kb_translation_table
[DIK_APPS
] = 0;
5169 kb_translation_table
[DIK_APPS
] |= 0x65 << 8;
5171 kb_translation_table
[DIK_BACK
] = '\b';
5172 kb_translation_table
[DIK_BACK
] |= 0x2a << 8;
5174 kb_translation_table
[DIK_BACKSLASH
] = '\\';
5175 kb_translation_table
[DIK_BACKSLASH
] |= 0x31 << 8;
5177 kb_translation_table
[DIK_CAPITAL
] = 0;
5178 kb_translation_table
[DIK_CAPITAL
] |= 0x39 << 8;
5180 kb_translation_table
[DIK_COLON
] = ':';
5181 kb_translation_table
[DIK_COLON
] |= 0x00 << 8;
5183 kb_translation_table
[DIK_COMMA
] = ',';
5184 kb_translation_table
[DIK_COMMA
] |= 0x36 << 8;
5186 kb_translation_table
[DIK_DECIMAL
] = '.';
5187 kb_translation_table
[DIK_DECIMAL
] |= 0x63 << 8;
5189 kb_translation_table
[DIK_DELETE
] = 0x7f;
5190 kb_translation_table
[DIK_DELETE
] |= 0x4c << 8;
5192 kb_translation_table
[DIK_DIVIDE
] = '/';
5193 kb_translation_table
[DIK_DIVIDE
] |= 0x54 << 8;
5195 kb_translation_table
[DIK_DOWN
] = 0;
5196 kb_translation_table
[DIK_DOWN
] |= 0x51 << 8;
5198 kb_translation_table
[DIK_END
] = 0;
5199 kb_translation_table
[DIK_END
] |= 0x4d << 8;
5201 kb_translation_table
[DIK_EQUALS
] = '=';
5202 kb_translation_table
[DIK_EQUALS
] |= 0x2e << 8;
5204 kb_translation_table
[DIK_ESCAPE
] = 0x1b;
5205 kb_translation_table
[DIK_ESCAPE
] |= 0x29 << 8;
5207 kb_translation_table
[DIK_F1
] = 0;
5208 kb_translation_table
[DIK_F1
] |= 0x3a << 8;
5210 kb_translation_table
[DIK_F2
] = 0;
5211 kb_translation_table
[DIK_F2
] |= 0x3b << 8;
5213 kb_translation_table
[DIK_F3
] = 0;
5214 kb_translation_table
[DIK_F3
] |= 0x3c << 8;
5216 kb_translation_table
[DIK_F4
] = 0;
5217 kb_translation_table
[DIK_F4
] |= 0x3d << 8;
5219 kb_translation_table
[DIK_F5
] = 0;
5220 kb_translation_table
[DIK_F5
] |= 0x3e << 8;
5222 kb_translation_table
[DIK_F6
] = 0;
5223 kb_translation_table
[DIK_F6
] |= 0x3f << 8;
5225 kb_translation_table
[DIK_F7
] = 0;
5226 kb_translation_table
[DIK_F7
] |= 0x40 << 8;
5228 kb_translation_table
[DIK_F8
] = 0;
5229 kb_translation_table
[DIK_F8
] |= 0x41 << 8;
5231 kb_translation_table
[DIK_F9
] = 0;
5232 kb_translation_table
[DIK_F9
] |= 0x42 << 8;
5234 kb_translation_table
[DIK_F10
] = 0;
5235 kb_translation_table
[DIK_F10
] |= 0x43 << 8;
5237 kb_translation_table
[DIK_F11
] = 0;
5238 kb_translation_table
[DIK_F11
] |= 0x44 << 8;
5240 kb_translation_table
[DIK_F12
] = 0;
5241 kb_translation_table
[DIK_F12
] |= 0x45 << 8;
5243 kb_translation_table
[DIK_F13
] = 0;
5244 kb_translation_table
[DIK_F13
] |= 0x68 << 8;
5246 kb_translation_table
[DIK_F14
] = 0;
5247 kb_translation_table
[DIK_F14
] |= 0x69 << 8;
5249 kb_translation_table
[DIK_F15
] = 0;
5250 kb_translation_table
[DIK_F15
] |= 0x6a << 8;
5252 kb_translation_table
[DIK_GRAVE
] = '`';
5253 kb_translation_table
[DIK_GRAVE
] |= 0x35 << 8;
5255 kb_translation_table
[DIK_HOME
] = 0;
5256 kb_translation_table
[DIK_HOME
] |= 0x4a << 8;
5258 kb_translation_table
[DIK_INSERT
] = 0;
5259 kb_translation_table
[DIK_INSERT
] |= 0x49 << 8;
5261 kb_translation_table
[DIK_LBRACKET
] = '[';
5262 kb_translation_table
[DIK_LBRACKET
] |= 0x2f << 8;
5264 kb_translation_table
[DIK_LCONTROL
] = 0;
5265 kb_translation_table
[DIK_LCONTROL
] |= 0xe0 << 8;
5267 kb_translation_table
[DIK_LEFT
] = 0;
5268 kb_translation_table
[DIK_LEFT
] |= 0x50 << 8;
5270 kb_translation_table
[DIK_LMENU
] = 0;
5271 kb_translation_table
[DIK_LMENU
] |= 0xe2 << 8;
5273 kb_translation_table
[DIK_LSHIFT
] = 0;
5274 kb_translation_table
[DIK_LSHIFT
] |= 0xe1 << 8;
5276 kb_translation_table
[DIK_LWIN
] = 0;
5277 kb_translation_table
[DIK_LWIN
] |= 0xe3 << 8;
5279 kb_translation_table
[DIK_MINUS
] = '-';
5280 kb_translation_table
[DIK_MINUS
] |= 0x2d << 8;
5282 kb_translation_table
[DIK_MULTIPLY
] = '*';
5283 kb_translation_table
[DIK_MULTIPLY
] |= 0x55 << 8;
5285 // kb_translation_table[DIK_MUTE] = 0;
5286 // kb_translation_table[DIK_MUTE] |= 0x7f;
5288 kb_translation_table
[DIK_NEXT
] = 0;
5289 kb_translation_table
[DIK_NEXT
] |= 0x4e << 8;
5291 kb_translation_table
[DIK_NUMLOCK
] = 0;
5292 kb_translation_table
[DIK_NUMLOCK
] |= 0x53 << 8;
5294 kb_translation_table
[DIK_NUMPAD0
] = '0';
5295 kb_translation_table
[DIK_NUMPAD0
] |= 0x62 << 8;
5297 kb_translation_table
[DIK_NUMPAD1
] = '1';
5298 kb_translation_table
[DIK_NUMPAD1
] |= 0x59 << 8;
5300 kb_translation_table
[DIK_NUMPAD2
] = '2';
5301 kb_translation_table
[DIK_NUMPAD2
] |= 0x5a << 8;
5303 kb_translation_table
[DIK_NUMPAD3
] = '3';
5304 kb_translation_table
[DIK_NUMPAD3
] |= 0x5b << 8;
5306 kb_translation_table
[DIK_NUMPAD4
] = '4';
5307 kb_translation_table
[DIK_NUMPAD4
] |= 0x5c << 8;
5309 kb_translation_table
[DIK_NUMPAD5
] = '5';
5310 kb_translation_table
[DIK_NUMPAD5
] |= 0x5d << 8;
5312 kb_translation_table
[DIK_NUMPAD6
] = '6';
5313 kb_translation_table
[DIK_NUMPAD6
] |= 0x5e << 8;
5315 kb_translation_table
[DIK_NUMPAD7
] = '7';
5316 kb_translation_table
[DIK_NUMPAD7
] |= 0x5f << 8;
5318 kb_translation_table
[DIK_NUMPAD8
] = '8';
5319 kb_translation_table
[DIK_NUMPAD8
] |= 0x60 << 8;
5321 kb_translation_table
[DIK_NUMPAD9
] = '9';
5322 kb_translation_table
[DIK_NUMPAD9
] |= 0x61 << 8;
5324 kb_translation_table
[DIK_NUMPADCOMMA
] = ',';
5325 kb_translation_table
[DIK_NUMPADCOMMA
] |= 0x85 << 8;
5327 kb_translation_table
[DIK_NUMPADENTER
] = '\n';
5328 kb_translation_table
[DIK_NUMPADENTER
] |= 0x58 << 8;
5330 kb_translation_table
[DIK_NUMPADEQUALS
] = '=';
5331 kb_translation_table
[DIK_NUMPADEQUALS
] |= 0x67 << 8;
5333 kb_translation_table
[DIK_PAUSE
] = 0;
5334 kb_translation_table
[DIK_PAUSE
] |= 0x48 << 8;
5336 kb_translation_table
[DIK_PERIOD
] = '.';
5337 kb_translation_table
[DIK_PERIOD
] |= 0x37 << 8;
5339 kb_translation_table
[DIK_POWER
] = 0;
5340 kb_translation_table
[DIK_POWER
] |= 0x66 << 8;
5342 kb_translation_table
[DIK_PRIOR
] = 0;
5343 kb_translation_table
[DIK_PRIOR
] |= 0x4b << 8;
5345 kb_translation_table
[DIK_RBRACKET
] = ']';
5346 kb_translation_table
[DIK_RBRACKET
] |= 0x30 << 8;
5348 kb_translation_table
[DIK_RCONTROL
] = 0;
5349 kb_translation_table
[DIK_RCONTROL
] |= 0xe4 << 8;
5351 kb_translation_table
[DIK_RETURN
] = '\n';
5352 kb_translation_table
[DIK_RETURN
] |= 0x28 << 8;
5354 kb_translation_table
[DIK_RIGHT
] = 0;
5355 kb_translation_table
[DIK_RIGHT
] |= 0x4f << 8;
5357 kb_translation_table
[DIK_RMENU
] = 0;
5358 kb_translation_table
[DIK_RMENU
] |= 0xe6 << 8;
5360 kb_translation_table
[DIK_RSHIFT
] = 0;
5361 kb_translation_table
[DIK_RSHIFT
] |= 0xe5 << 8;
5363 kb_translation_table
[DIK_RWIN
] = 0;
5364 kb_translation_table
[DIK_RWIN
] |= 0xe7 << 8;
5366 kb_translation_table
[DIK_SCROLL
] = 0;
5367 kb_translation_table
[DIK_SCROLL
] |= 0x47 << 8;
5369 kb_translation_table
[DIK_SEMICOLON
] = ';';
5370 kb_translation_table
[DIK_SEMICOLON
] |= 0x33 << 8;
5372 kb_translation_table
[DIK_SLASH
] = '/';
5373 kb_translation_table
[DIK_SLASH
] |= 0x38 << 8;
5375 kb_translation_table
[DIK_SPACE
] = ' ';
5376 kb_translation_table
[DIK_SPACE
] |= 0x2c << 8;
5378 kb_translation_table
[DIK_STOP
] = 0;
5379 kb_translation_table
[DIK_STOP
] |= 0x78 << 8;
5381 kb_translation_table
[DIK_SUBTRACT
] = '-';
5382 kb_translation_table
[DIK_SUBTRACT
] |= 0x56 << 8;
5384 kb_translation_table
[DIK_SYSRQ
] = 0;
5385 kb_translation_table
[DIK_SYSRQ
] |= 0x46 << 8;
5387 kb_translation_table
[DIK_TAB
] = '\t';
5388 kb_translation_table
[DIK_TAB
] |= 0x2b << 8;
5390 kb_translation_table
[DIK_UP
] = 0;
5391 kb_translation_table
[DIK_UP
] |= 0x52 << 8;
5393 // kb_translation_table[DIK_VOLUMEDOWN] = 0;
5394 // kb_translation_table[DIK_VOLUMEDOWN] |= 0x81;
5396 // kb_translation_table[DIK_VOLUMEUP] = 0;
5397 // kb_translation_table[DIK_VOLUMEUP] |= 0x80;
5400 static void Keyboard_dikey_to_ascii_and_usb( unsigned char dikey
,
5404 unsigned short tr
= kb_translation_table
[dikey
];
5407 usb
= ( tr
>> 8 ) & 0xff;
5410 static BOOL CALLBACK
DIEnumKeyboardProc( LPCDIDEVICEINSTANCE lpddi
,
5413 GUID guid
= lpddi
->guidInstance
;
5414 win32_keyboard
* keyboard
= new win32_keyboard
;
5416 EM_log( CK_LOG_INFO
, "found %s", lpddi
->tszProductName
);
5418 strncpy( keyboard
->name
, lpddi
->tszProductName
, MAX_PATH
);
5420 if( lpdi
->CreateDevice( guid
,
5421 ( LPDIRECTINPUTDEVICE
* ) &keyboard
->lpdiKeyboard
,
5425 EM_log( CK_LOG_WARNING
, "error: unable to initialize device %s",
5426 lpddi
->tszProductName
);
5427 return DIENUM_CONTINUE
;
5430 keyboards
->push_back( keyboard
);
5432 return DIENUM_CONTINUE
;
5435 void Keyboard_init()
5437 if( keyboards
!= NULL
)
5440 EM_log( CK_LOG_INFO
, "initializing keyboard" );
5443 HINSTANCE hInstance
= GetModuleHandle( NULL
);
5447 if( DirectInputCreate( hInstance
, DIRECTINPUT_VERSION
,
5448 &lpdi
, NULL
) != DI_OK
)
5451 EM_log( CK_LOG_SEVERE
, "error: unable to initialize DirectInput, initialization failed" );
5457 keyboards
= new vector
< win32_keyboard
* >;
5458 if( lpdi
->EnumDevices( DIDEVTYPE_KEYBOARD
, DIEnumKeyboardProc
,
5459 NULL
, DIEDFL_ATTACHEDONLY
) != DI_OK
)
5465 EM_log( CK_LOG_SEVERE
, "error: unable to enumerate devices, initialization failed" );
5470 Keyboard_init_translation_table();
5475 void Keyboard_poll()
5480 win32_keyboard
* keyboard
;
5482 vector
< win32_keyboard
* >::size_type i
, len
= keyboards
->size();
5483 for( i
= 0; i
< len
; i
++ )
5485 keyboard
= keyboards
->at( i
);
5486 if( keyboard
->refcount
)
5488 // TODO: convert this to buffered input, or maybe notifications
5489 char state
[DINPUT_KEYBUFFER_SIZE
];
5491 keyboard
->lpdiKeyboard
->Poll();
5493 if( keyboard
->lpdiKeyboard
->GetDeviceState( DINPUT_KEYBUFFER_SIZE
, state
)
5496 EM_log( CK_LOG_WARNING
, "keyboard: GetDeviceState failed for %s",
5501 for( int j
= 0; j
< DINPUT_KEYBUFFER_SIZE
; j
++ )
5503 if( ( state
[j
] & 0x80 ) ^ ( keyboard
->last_state
[j
] & 0x80 ) )
5507 msg
.device_type
= CK_HID_DEV_KEYBOARD
;
5508 msg
.type
= ( state
[j
] & 0x80 ) ? CK_HID_BUTTON_DOWN
:
5511 msg
.idata
[0] = ( state
[j
] & 0x80 ) ? 1 : 0;
5512 Keyboard_dikey_to_ascii_and_usb( j
, msg
.idata
[2], msg
.idata
[1] );
5513 HidInManager::push_message( msg
);
5517 memcpy( keyboard
->last_state
, state
, DINPUT_KEYBUFFER_SIZE
);
5520 else if( keyboard
->needs_close
)
5522 keyboard
->needs_close
= FALSE
;
5523 keyboard
->lpdiKeyboard
->Unacquire();
5524 keyboard
->lpdiKeyboard
->SetEventNotification( NULL
);
5529 void Keyboard_quit()
5533 win32_keyboard
* keyboard
;
5534 vector
< win32_keyboard
* >::size_type i
, len
= keyboards
->size();
5535 for( i
= 0; i
< len
; i
++ )
5537 keyboard
= keyboards
->at( i
);
5539 if( keyboard
->refcount
> 0 || keyboard
->needs_close
)
5541 keyboard
->needs_close
= FALSE
;
5542 keyboard
->refcount
= 0;
5543 keyboard
->lpdiKeyboard
->Unacquire();
5544 keyboard
->lpdiKeyboard
->SetEventNotification( NULL
);
5547 keyboard
->lpdiKeyboard
->Release();
5562 int Keyboard_count()
5566 return keyboards
->size();
5569 int Keyboard_open( int k
)
5571 if( !keyboards
|| k
< 0 || k
>= keyboards
->size() )
5574 win32_keyboard
* keyboard
= keyboards
->at( k
);
5576 if( keyboard
->refcount
== 0 )
5578 if( keyboard
->lpdiKeyboard
->SetDataFormat( &c_dfDIKeyboard
) != DI_OK
)
5583 if( keyboard
->lpdiKeyboard
->SetEventNotification( g_device_event
) != DI_OK
)
5585 // fallback to sleep+poll mode
5586 g_wait_function
= Hid_wait_usleep
;
5587 SetEvent( g_device_event
);
5590 if( keyboard
->lpdiKeyboard
->Acquire() != DI_OK
)
5592 keyboard
->lpdiKeyboard
->SetEventNotification( NULL
);
5597 keyboard
->refcount
++;
5602 int Keyboard_close( int k
)
5604 if( !keyboards
|| k
< 0 || k
>= keyboards
->size() )
5607 win32_keyboard
* keyboard
= keyboards
->at( k
);
5609 keyboard
->refcount
--;
5611 if( keyboard
->refcount
< 1 )
5612 keyboard
->needs_close
= TRUE
;
5617 const char * Keyboard_name( int kb
)
5619 if( !keyboards
|| kb
< 0 || kb
>= keyboards
->size() )
5622 return keyboards
->at( kb
)->name
;
5625 /*****************************************************************************
5626 Windows mouse support
5627 *****************************************************************************/
5628 #pragma mark Windows mouse support
5635 needs_close
= FALSE
;
5638 memset( &last_state
, 0, sizeof( last_state
) );
5641 LPDIRECTINPUTDEVICE2 lpdiMouse
;
5642 DIMOUSESTATE last_state
;
5644 char name
[MAX_PATH
];
5647 t_CKBOOL needs_close
;
5650 static vector
< win32_mouse
* > * mice
;
5652 static BOOL CALLBACK
DIEnumMouseProc( LPCDIDEVICEINSTANCE lpddi
,
5655 GUID guid
= lpddi
->guidInstance
;
5656 win32_mouse
* mouse
= new win32_mouse
;
5658 EM_log( CK_LOG_INFO
, "found %s", lpddi
->tszProductName
);
5660 strncpy( mouse
->name
, lpddi
->tszProductName
, MAX_PATH
);
5662 if( lpdi
->CreateDevice( guid
, ( LPDIRECTINPUTDEVICE
* ) &mouse
->lpdiMouse
,
5666 return DIENUM_CONTINUE
;
5669 mice
->push_back( mouse
);
5671 return DIENUM_CONTINUE
;
5679 EM_log( CK_LOG_INFO
, "initializing mouse" );
5682 HINSTANCE hInstance
= GetModuleHandle( NULL
);
5686 if( DirectInputCreate( hInstance
, DIRECTINPUT_VERSION
,
5687 &lpdi
, NULL
) != DI_OK
)
5695 mice
= new vector
< win32_mouse
* >;
5696 if( lpdi
->EnumDevices( DIDEVTYPE_MOUSE
, DIEnumMouseProc
,
5697 NULL
, DIEDFL_ATTACHEDONLY
) != DI_OK
)
5715 win32_mouse
* mouse
;
5717 vector
< win32_mouse
* >::size_type i
, len
= mice
->size();
5718 for( i
= 0; i
< len
; i
++ )
5720 mouse
= mice
->at( i
);
5721 if( mouse
->refcount
)
5723 // TODO: convert this to buffered input, or maybe notifications
5726 mouse
->lpdiMouse
->Poll();
5728 if( mouse
->lpdiMouse
->GetDeviceState( sizeof( DIMOUSESTATE
), &state
)
5731 EM_log( CK_LOG_WARNING
, "mouse: GetDeviceState failed for %s", mouse
->name
);
5735 if( state
.lX
!= 0 || state
.lY
!= 0 )
5739 msg
.device_type
= CK_HID_DEV_MOUSE
;
5740 msg
.type
= CK_HID_MOUSE_MOTION
;
5742 msg
.idata
[0] = state
.lX
;
5743 msg
.idata
[1] = state
.lY
;
5744 HidInManager::push_message( msg
);
5751 msg
.device_type
= CK_HID_DEV_MOUSE
;
5752 msg
.type
= CK_HID_MOUSE_WHEEL
;
5755 msg
.idata
[1] = state
.lZ
;
5756 HidInManager::push_message( msg
);
5759 for( int j
= 0; j
< 4; j
++ )
5761 if( ( state
.rgbButtons
[j
] & 0x80 ) ^
5762 ( mouse
->last_state
.rgbButtons
[j
] & 0x80 ) )
5766 msg
.device_type
= CK_HID_DEV_MOUSE
;
5767 msg
.type
= ( state
.rgbButtons
[j
] & 0x80 ) ? CK_HID_BUTTON_DOWN
:
5770 msg
.idata
[0] = ( state
.rgbButtons
[j
] & 0x80 ) ? 1 : 0;
5771 HidInManager::push_message( msg
);
5775 mouse
->last_state
= state
;
5778 else if( mouse
->needs_close
)
5780 mouse
->needs_close
= FALSE
;
5781 mouse
->lpdiMouse
->Unacquire();
5782 mouse
->lpdiMouse
->SetEventNotification( NULL
);
5791 win32_mouse
* mouse
;
5792 vector
< win32_mouse
* >::size_type i
, len
= mice
->size();
5793 for( i
= 0; i
< len
; i
++ )
5795 mouse
= mice
->at( i
);
5797 if( mouse
->refcount
> 0 || mouse
->needs_close
)
5799 mouse
->needs_close
= FALSE
;
5800 mouse
->refcount
= 0;
5801 mouse
->lpdiMouse
->Unacquire();
5802 mouse
->lpdiMouse
->SetEventNotification( NULL
);
5805 mouse
->lpdiMouse
->Release();
5824 return mice
->size();
5827 int Mouse_open( int m
)
5829 if( !mice
|| m
< 0 || m
>= mice
->size() )
5832 win32_mouse
* mouse
= mice
->at( m
);
5834 if( mouse
->refcount
== 0 )
5836 if( mouse
->lpdiMouse
->SetDataFormat( &c_dfDIMouse
) != DI_OK
)
5841 if( mouse
->lpdiMouse
->SetEventNotification( g_device_event
) != DI_OK
)
5843 // fallback to sleep+poll mode
5844 g_wait_function
= Hid_wait_usleep
;
5845 SetEvent( g_device_event
);
5848 if( mouse
->lpdiMouse
->Acquire() != DI_OK
)
5850 mouse
->lpdiMouse
->SetEventNotification( g_device_event
);
5860 int Mouse_close( int m
)
5862 if( !mice
|| m
< 0 || m
>= mice
->size() )
5865 win32_mouse
* mouse
= mice
->at( m
);
5869 if( mouse
->refcount
< 1 )
5870 mouse
->needs_close
= TRUE
; // let the polling thread take care of it
5875 const char * Mouse_name( int m
)
5877 if( !mice
|| m
< 0 || m
>= mice
->size() )
5880 return mice
->at( m
)->name
;
5883 #elif defined( __PLATFORM_WIN32__ ) || defined( __WINDOWS_PTHREAD__ ) && defined( USE_RAWINPUT )
5885 void Joystick_init()
5890 void Joystick_poll()
5895 void Joystick_quit()
5900 int Joystick_count()
5905 int Joystick_open( int js
)
5910 int Joystick_close( int js
)
5935 int Mouse_open( int js
)
5940 int Mouse_close( int js
)
5945 void Keyboard_init()
5950 void Keyboard_poll()
5955 void Keyboard_quit()
5960 int Keyboard_count()
5965 int Keyboard_open( int js
)
5970 int Keyboard_close( int js
)
5977 #elif defined( __LINUX_ALSA__ ) || defined( __LINUX_OSS__ ) || defined( __LINUX_JACK__ )
5978 /*****************************************************************************
5979 Linux general HID support
5980 *****************************************************************************/
5981 #pragma mark Linux general HID support
5983 #include <sys/types.h>
5984 #include <sys/stat.h>
5987 #include <linux/unistd.h>
5990 #include <sys/poll.h>
5991 #include <sys/ioctl.h>
5993 #include <linux/joystick.h>
5994 #include <linux/input.h>
5996 #define CK_HID_DIR ("/dev/input")
5997 #define CK_HID_MOUSEFILE ("mouse%d")
5998 #define CK_HID_JOYSTICKFILE ("js%d")
5999 #define CK_HID_EVDEVFILE ("event%d")
6000 #define CK_HID_STRBUFSIZE (1024)
6001 #define CK_HID_NAMESIZE (128)
6013 needs_open
= needs_close
= FALSE
;
6014 strncpy( name
, "(name unknown)", CK_HID_NAMESIZE
);
6017 virtual void callback() = 0;
6019 int fd
; // file descriptor
6020 t_CKINT num
; // index in the respective device vector {joysticks, mice, keyboards}
6026 t_CKBOOL needs_open
;
6027 t_CKBOOL needs_close
;
6029 char filename
[CK_HID_STRBUFSIZE
];
6030 char name
[CK_HID_NAMESIZE
];
6033 class linux_joystick
: public linux_device
6036 linux_joystick() : linux_device()
6041 virtual void callback()
6047 while( ( len
= read( fd
, &event
, sizeof( event
) ) ) > 0 )
6049 if( len
< sizeof( event
) )
6051 EM_log( CK_LOG_WARNING
, "joystick: read event from %s smaller than expected, ignoring", name
);
6055 if( event
.type
== JS_EVENT_INIT
)
6058 msg
.device_type
= CK_HID_DEV_JOYSTICK
;
6059 msg
.device_num
= num
;
6060 msg
.eid
= event
.number
;
6062 switch( event
.type
)
6064 case JS_EVENT_BUTTON
:
6065 msg
.type
= event
.value
? CK_HID_BUTTON_DOWN
:
6067 msg
.idata
[0] = event
.value
;
6070 msg
.type
= CK_HID_JOYSTICK_AXIS
;
6071 msg
.fdata
[0] = ((t_CKFLOAT
)event
.value
) / ((t_CKFLOAT
) SHRT_MAX
);
6074 EM_log( CK_LOG_WARNING
, "joystick: unknown event type from %s, ignoring", name
);
6078 HidInManager::push_message( msg
);
6082 int js_num
; // /dev/input/js# <-- the #
6085 #define __LITTLE_ENDIAN__
6086 struct ps2_mouse_event
6088 #ifdef __BIG_ENDIAN__
6090 unsigned y_reverse_motion
:1;
6091 unsigned x_reverse_motion
:1;
6098 #elif defined( __LITTLE_ENDIAN__ )
6103 unsigned x_reverse_motion
:1;
6104 unsigned y_reverse_motion
:1;
6109 #error unknown endian mode (both __LITTLE_ENDIAN__ and __BIG_ENDIAN__ undefined)
6111 } __attribute__ ((__packed__
));
6113 class linux_mouse
: public linux_device
6116 linux_mouse() : linux_device()
6119 memset( &last_event
, 0, sizeof( last_event
) );
6122 virtual void callback()
6124 //ps2_mouse_event event;
6129 while( ( len
= read( fd
, &event
, sizeof( event
) ) ) > 0 )
6131 if( len
< sizeof( event
) )
6133 EM_log( CK_LOG_WARNING
, "mouse: read event from mouse %i smaller than expected (%i), ignoring", num
, len
);
6137 switch( event
.type
)
6140 if( event
.code
& BTN_MOUSE
)
6143 msg
.device_type
= CK_HID_DEV_MOUSE
;
6144 msg
.device_num
= num
;
6145 msg
.eid
= event
.code
- BTN_MOUSE
;
6146 msg
.type
= event
.value
? CK_HID_BUTTON_DOWN
: CK_HID_BUTTON_UP
;
6147 msg
.idata
[0] = event
.value
;
6148 HidInManager::push_message( msg
);
6155 msg
.device_type
= CK_HID_DEV_MOUSE
;
6156 msg
.device_num
= num
;
6158 switch( event
.code
)
6161 msg
.type
= CK_HID_MOUSE_MOTION
;
6162 msg
.idata
[0] = event
.value
;
6167 msg
.type
= CK_HID_MOUSE_MOTION
;
6169 msg
.idata
[1] = event
.value
;
6173 msg
.type
= CK_HID_MOUSE_WHEEL
;
6174 msg
.idata
[0] = event
.value
;
6180 msg
.type
= CK_HID_MOUSE_WHEEL
;
6182 msg
.idata
[1] = event
.value
;
6186 HidInManager::push_message( msg
);
6193 if( event.dx || event.dy )
6195 msg.device_type = CK_HID_DEV_MOUSE;
6196 msg.device_num = num;
6198 msg.type = CK_HID_MOUSE_MOTION;
6199 msg.idata[0] = event.dx;
6200 msg.idata[1] = event.dy;
6201 HidInManager::push_message( msg );
6204 if( event.button1 ^ last_event.button1 )
6206 msg.device_type = CK_HID_DEV_MOUSE;
6207 msg.device_num = num;
6209 msg.type = event.button1 ? CK_HID_BUTTON_DOWN : CK_HID_BUTTON_UP;
6210 msg.idata[0] = event.button1;
6211 HidInManager::push_message( msg );
6214 if( event.button2 ^ last_event.button2 )
6216 msg.device_type = CK_HID_DEV_MOUSE;
6217 msg.device_num = num;
6219 msg.type = event.button2 ? CK_HID_BUTTON_DOWN : CK_HID_BUTTON_UP;
6220 msg.idata[0] = event.button2;
6221 HidInManager::push_message( msg );
6224 if( event.button3 ^ last_event.button3 )
6226 msg.device_type = CK_HID_DEV_MOUSE;
6227 msg.device_num = num;
6229 msg.type = event.button3 ? CK_HID_BUTTON_DOWN : CK_HID_BUTTON_UP;
6230 msg.idata[0] = event.button3;
6231 HidInManager::push_message( msg );
6234 memcpy( &last_event
, &event
, sizeof( last_event
) );
6238 int m_num
; // /dev/input/mouse# <-- the #
6239 //ps2_mouse_event last_event;
6240 input_event last_event
;
6243 static unsigned short kb_translation_table
[KEY_UNKNOWN
];
6245 static void Keyboard_init_translation_table()
6247 memset( kb_translation_table
, 0, sizeof( kb_translation_table
) );
6249 kb_translation_table
[KEY_ESC
] = '\e';
6250 kb_translation_table
[KEY_ESC
] |= 0x29 << 8;
6252 kb_translation_table
[KEY_1
] = '1';
6253 kb_translation_table
[KEY_1
] |= 0x1e << 8;
6255 kb_translation_table
[KEY_2
] = '2';
6256 kb_translation_table
[KEY_2
] |= 0x1f << 8;
6258 kb_translation_table
[KEY_3
] = '3';
6259 kb_translation_table
[KEY_3
] |= 0x20 << 8;
6261 kb_translation_table
[KEY_4
] = '4';
6262 kb_translation_table
[KEY_4
] |= 0x21 << 8;
6264 kb_translation_table
[KEY_5
] = '5';
6265 kb_translation_table
[KEY_5
] |= 0x22 << 8;
6267 kb_translation_table
[KEY_6
] = '6';
6268 kb_translation_table
[KEY_6
] |= 0x23 << 8;
6270 kb_translation_table
[KEY_7
] = '7';
6271 kb_translation_table
[KEY_7
] |= 0x24 << 8;
6273 kb_translation_table
[KEY_8
] = '8';
6274 kb_translation_table
[KEY_8
] |= 0x25 << 8;
6276 kb_translation_table
[KEY_9
] = '9';
6277 kb_translation_table
[KEY_9
] |= 0x26 << 8;
6279 kb_translation_table
[KEY_0
] = '0';
6280 kb_translation_table
[KEY_0
] |= 0x27 << 8;
6282 kb_translation_table
[KEY_MINUS
] = '-';
6283 kb_translation_table
[KEY_MINUS
] |= 0x2d << 8;
6285 kb_translation_table
[KEY_EQUAL
] = '=';
6286 kb_translation_table
[KEY_EQUAL
] |= 0x2e << 8;
6288 kb_translation_table
[KEY_BACKSPACE
] = '\b';
6289 kb_translation_table
[KEY_BACKSPACE
] |= 0x2a << 8;
6291 kb_translation_table
[KEY_TAB
] = '\t';
6292 kb_translation_table
[KEY_TAB
] |= 0x2b << 8;
6294 kb_translation_table
[KEY_Q
] = 'Q';
6295 kb_translation_table
[KEY_Q
] |= 0x14 << 8;
6297 kb_translation_table
[KEY_W
] = 'W';
6298 kb_translation_table
[KEY_W
] |= 0x1a << 8;
6300 kb_translation_table
[KEY_E
] = 'E';
6301 kb_translation_table
[KEY_E
] |= 0x08 << 8;
6303 kb_translation_table
[KEY_R
] = 'R';
6304 kb_translation_table
[KEY_R
] |= 0x15 << 8;
6306 kb_translation_table
[KEY_T
] = 'T';
6307 kb_translation_table
[KEY_T
] |= 0x17 << 8;
6309 kb_translation_table
[KEY_Y
] = 'Y';
6310 kb_translation_table
[KEY_Y
] |= 0x1c << 8;
6312 kb_translation_table
[KEY_U
] = 'U';
6313 kb_translation_table
[KEY_U
] |= 0x18 << 8;
6315 kb_translation_table
[KEY_I
] = 'I';
6316 kb_translation_table
[KEY_I
] |= 0x0c << 8;
6318 kb_translation_table
[KEY_O
] = 'O';
6319 kb_translation_table
[KEY_O
] |= 0x12 << 8;
6321 kb_translation_table
[KEY_P
] = 'P';
6322 kb_translation_table
[KEY_P
] |= 0x13 << 8;
6324 kb_translation_table
[KEY_LEFTBRACE
] = '[';
6325 kb_translation_table
[KEY_LEFTBRACE
] |= 0x2f << 8;
6327 kb_translation_table
[KEY_RIGHTBRACE
] = ']';
6328 kb_translation_table
[KEY_RIGHTBRACE
] |= 0x30 << 8;
6330 kb_translation_table
[KEY_ENTER
] = '\n';
6331 kb_translation_table
[KEY_ENTER
] |= 0x28 << 8;
6333 kb_translation_table
[KEY_LEFTCTRL
] = 0;
6334 kb_translation_table
[KEY_LEFTCTRL
] |= 0xe0 << 8;
6336 kb_translation_table
[KEY_A
] = 'A';
6337 kb_translation_table
[KEY_A
] |= 0x04 << 8;
6339 kb_translation_table
[KEY_S
] = 'S';
6340 kb_translation_table
[KEY_S
] |= 0x16 << 8;
6342 kb_translation_table
[KEY_D
] = 'D';
6343 kb_translation_table
[KEY_D
] |= 0x07 << 8;
6345 kb_translation_table
[KEY_F
] = 'F';
6346 kb_translation_table
[KEY_F
] |= 0x09 << 8;
6348 kb_translation_table
[KEY_G
] = 'G';
6349 kb_translation_table
[KEY_G
] |= 0x0a << 8;
6351 kb_translation_table
[KEY_H
] = 'H';
6352 kb_translation_table
[KEY_H
] |= 0x0b << 8;
6354 kb_translation_table
[KEY_J
] = 'J';
6355 kb_translation_table
[KEY_J
] |= 0x0d << 8;
6357 kb_translation_table
[KEY_K
] = 'K';
6358 kb_translation_table
[KEY_K
] |= 0x0e << 8;
6360 kb_translation_table
[KEY_L
] = 'L';
6361 kb_translation_table
[KEY_L
] |= 0x0f << 8;
6363 kb_translation_table
[KEY_SEMICOLON
] = ';';
6364 kb_translation_table
[KEY_SEMICOLON
] |= 0x33 << 8;
6366 kb_translation_table
[KEY_APOSTROPHE
] = '\'';
6367 kb_translation_table
[KEY_APOSTROPHE
] |= 0x34 << 8;
6369 kb_translation_table
[KEY_GRAVE
] = '`';
6370 kb_translation_table
[KEY_GRAVE
] |= 0x35 << 8;
6372 kb_translation_table
[KEY_LEFTSHIFT
] = 0;
6373 kb_translation_table
[KEY_LEFTSHIFT
] |= 0xe1 << 8;
6375 kb_translation_table
[KEY_BACKSLASH
] = '\\';
6376 kb_translation_table
[KEY_BACKSLASH
] |= 0x31 << 8;
6378 kb_translation_table
[KEY_Z
] = 'Z';
6379 kb_translation_table
[KEY_Z
] |= 0x1d << 8;
6381 kb_translation_table
[KEY_X
] = 'X';
6382 kb_translation_table
[KEY_X
] |= 0x1b << 8;
6384 kb_translation_table
[KEY_C
] = 'C';
6385 kb_translation_table
[KEY_C
] |= 0x06 << 8;
6387 kb_translation_table
[KEY_V
] = 'V';
6388 kb_translation_table
[KEY_V
] |= 0x19 << 8;
6390 kb_translation_table
[KEY_B
] = 'B';
6391 kb_translation_table
[KEY_B
] |= 0x05 << 8;
6393 kb_translation_table
[KEY_N
] = 'N';
6394 kb_translation_table
[KEY_N
] |= 0x11 << 8;
6396 kb_translation_table
[KEY_M
] = 'M';
6397 kb_translation_table
[KEY_M
] |= 0x10 << 8;
6399 kb_translation_table
[KEY_COMMA
] = ',';
6400 kb_translation_table
[KEY_COMMA
] |= 0x36 << 8;
6402 kb_translation_table
[KEY_DOT
] = '.';
6403 kb_translation_table
[KEY_DOT
] |= 0x37 << 8;
6405 kb_translation_table
[KEY_SLASH
] = '/';
6406 kb_translation_table
[KEY_SLASH
] |= 0x38 << 8;
6408 kb_translation_table
[KEY_RIGHTSHIFT
] = 0;
6409 kb_translation_table
[KEY_RIGHTSHIFT
] |= 0xe5 << 8;
6411 kb_translation_table
[KEY_KPASTERISK
] = '*';
6412 kb_translation_table
[KEY_KPASTERISK
] |= 0x55 << 8;
6414 kb_translation_table
[KEY_LEFTALT
] = 0;
6415 kb_translation_table
[KEY_LEFTALT
] |= 0xe2 << 8;
6417 kb_translation_table
[KEY_SPACE
] = ' ';
6418 kb_translation_table
[KEY_SPACE
] |= 0x2c << 8;
6420 kb_translation_table
[KEY_CAPSLOCK
] = 0;
6421 kb_translation_table
[KEY_CAPSLOCK
] |= 0x39 << 8;
6423 kb_translation_table
[KEY_F1
] = 0;
6424 kb_translation_table
[KEY_F1
] |= 0x3a << 8;
6426 kb_translation_table
[KEY_F2
] = 0;
6427 kb_translation_table
[KEY_F2
] |= 0x3b << 8;
6429 kb_translation_table
[KEY_F3
] = 0;
6430 kb_translation_table
[KEY_F3
] |= 0x3c << 8;
6432 kb_translation_table
[KEY_F4
] = 0;
6433 kb_translation_table
[KEY_F4
] |= 0x3d << 8;
6435 kb_translation_table
[KEY_F5
] = 0;
6436 kb_translation_table
[KEY_F5
] |= 0x3e << 8;
6438 kb_translation_table
[KEY_F6
] = 0;
6439 kb_translation_table
[KEY_F6
] |= 0x3f << 8;
6441 kb_translation_table
[KEY_F7
] = 0;
6442 kb_translation_table
[KEY_F7
] |= 0x40 << 8;
6444 kb_translation_table
[KEY_F8
] = 0;
6445 kb_translation_table
[KEY_F8
] |= 0x41 << 8;
6447 kb_translation_table
[KEY_F9
] = 0;
6448 kb_translation_table
[KEY_F9
] |= 0x42 << 8;
6450 kb_translation_table
[KEY_F10
] = 0;
6451 kb_translation_table
[KEY_F10
] |= 0x43 << 8;
6453 kb_translation_table
[KEY_NUMLOCK
] = 0;
6454 kb_translation_table
[KEY_NUMLOCK
] |= 0x53 << 8;
6456 kb_translation_table
[KEY_SCROLLLOCK
] = 0;
6457 kb_translation_table
[KEY_SCROLLLOCK
] |= 0x47 << 8;
6459 kb_translation_table
[KEY_KP7
] = '7';
6460 kb_translation_table
[KEY_KP7
] |= 0x5f << 8;
6462 kb_translation_table
[KEY_KP8
] = '8';
6463 kb_translation_table
[KEY_KP8
] |= 0x60 << 8;
6465 kb_translation_table
[KEY_KP9
] = '9';
6466 kb_translation_table
[KEY_KP9
] |= 0x61 << 8;
6468 kb_translation_table
[KEY_KPMINUS
] = '-';
6469 kb_translation_table
[KEY_KPMINUS
] |= 0x56 << 8;
6471 kb_translation_table
[KEY_KP4
] = '4';
6472 kb_translation_table
[KEY_KP4
] |= 0x5c << 8;
6474 kb_translation_table
[KEY_KP5
] = '5';
6475 kb_translation_table
[KEY_KP5
] |= 0x5d << 8;
6477 kb_translation_table
[KEY_KP6
] = '6';
6478 kb_translation_table
[KEY_KP6
] |= 0x5e << 8;
6480 kb_translation_table
[KEY_KPPLUS
] = '+';
6481 kb_translation_table
[KEY_KPPLUS
] |= 0x57 << 8;
6483 kb_translation_table
[KEY_KP1
] = '1';
6484 kb_translation_table
[KEY_KP1
] |= 0x59 << 8;
6486 kb_translation_table
[KEY_KP2
] = '2';
6487 kb_translation_table
[KEY_KP2
] |= 0x51 << 8;
6489 kb_translation_table
[KEY_KP3
] = '3';
6490 kb_translation_table
[KEY_KP3
] |= 0x52 << 8;
6492 kb_translation_table
[KEY_KP0
] = '0';
6493 kb_translation_table
[KEY_KP0
] |= 0x62 << 8;
6495 kb_translation_table
[KEY_KPDOT
] = '.';
6496 kb_translation_table
[KEY_KPDOT
] |= 0x63 << 8;
6498 kb_translation_table
[KEY_F11
] = 0;
6499 kb_translation_table
[KEY_F11
] |= 0x44 << 8;
6501 kb_translation_table
[KEY_F12
] = 0;
6502 kb_translation_table
[KEY_F12
] |= 0x45 << 8;
6504 // kb_translation_table[KEY_KPJPCOMMA] = ',';
6505 // kb_translation_table[KEY_KPJPCOMMA] |= 0x85 << 8;
6507 kb_translation_table
[KEY_KPENTER
] = '\n';
6508 kb_translation_table
[KEY_KPENTER
] |= 0x58 << 8;
6510 kb_translation_table
[KEY_RIGHTCTRL
] = 0;
6511 kb_translation_table
[KEY_RIGHTCTRL
] |= 0xe4 << 8;
6513 kb_translation_table
[KEY_KPSLASH
] = '/';
6514 kb_translation_table
[KEY_KPSLASH
] |= 0x54 << 8;
6516 kb_translation_table
[KEY_SYSRQ
] = 0;
6517 kb_translation_table
[KEY_SYSRQ
] |= 0x46 << 8;
6519 kb_translation_table
[KEY_RIGHTALT
] = 0;
6520 kb_translation_table
[KEY_RIGHTALT
] |= 0xe6 << 8;
6522 kb_translation_table
[KEY_HOME
] = 0;
6523 kb_translation_table
[KEY_HOME
] |= 0x4a << 8;
6525 kb_translation_table
[KEY_UP
] = 0;
6526 kb_translation_table
[KEY_UP
] |= 0x52 << 8;
6528 kb_translation_table
[KEY_PAGEUP
] = 0;
6529 kb_translation_table
[KEY_PAGEUP
] |= 0x4b << 8;
6531 kb_translation_table
[KEY_LEFT
] = 0;
6532 kb_translation_table
[KEY_LEFT
] |= 0x50 << 8;
6534 kb_translation_table
[KEY_RIGHT
] = 0;
6535 kb_translation_table
[KEY_RIGHT
] |= 0x4f << 8;
6537 kb_translation_table
[KEY_END
] = 0;
6538 kb_translation_table
[KEY_END
] |= 0x4d << 8;
6540 kb_translation_table
[KEY_DOWN
] = 0;
6541 kb_translation_table
[KEY_DOWN
] |= 0x51 << 8;
6543 kb_translation_table
[KEY_PAGEDOWN
] = 0;
6544 kb_translation_table
[KEY_PAGEDOWN
] |= 0x4e << 8;
6546 kb_translation_table
[KEY_INSERT
] = 0;
6547 kb_translation_table
[KEY_INSERT
] |= 0x49 << 8;
6549 kb_translation_table
[KEY_DELETE
] = 0x7f;
6550 kb_translation_table
[KEY_DELETE
] |= 0x4c << 8;
6552 kb_translation_table
[KEY_MUTE
] = 0;
6553 kb_translation_table
[KEY_MUTE
] |= 0x7f << 8;
6555 kb_translation_table
[KEY_VOLUMEDOWN
] = 0;
6556 kb_translation_table
[KEY_VOLUMEDOWN
] |= 0x81 << 8;
6558 kb_translation_table
[KEY_VOLUMEUP
] = 0;
6559 kb_translation_table
[KEY_VOLUMEUP
] |= 0x80 << 8;
6561 kb_translation_table
[KEY_POWER
] = 0;
6562 kb_translation_table
[KEY_POWER
] |= 0x66 << 8;
6564 kb_translation_table
[KEY_KPEQUAL
] = '=';
6565 kb_translation_table
[KEY_KPEQUAL
] |= 0x67 << 8;
6567 kb_translation_table
[KEY_PAUSE
] = 0;
6568 kb_translation_table
[KEY_PAUSE
] |= 0x48 << 8;
6570 kb_translation_table
[KEY_KPCOMMA
] = ',';
6571 kb_translation_table
[KEY_KPCOMMA
] |= 0x85 << 8;
6573 kb_translation_table
[KEY_LEFTMETA
] = 0;
6574 kb_translation_table
[KEY_LEFTMETA
] |= 0xe3 << 8;
6576 kb_translation_table
[KEY_RIGHTMETA
] = 0;
6577 kb_translation_table
[KEY_RIGHTMETA
] |= 0xe7 << 8;
6579 kb_translation_table
[KEY_STOP
] = 0;
6580 kb_translation_table
[KEY_STOP
] |= 0x78 << 8;
6582 kb_translation_table
[KEY_AGAIN
] = 0;
6583 kb_translation_table
[KEY_AGAIN
] |= 0x79 << 8;
6585 kb_translation_table
[KEY_UNDO
] = 0;
6586 kb_translation_table
[KEY_UNDO
] |= 0x7a << 8;
6588 kb_translation_table
[KEY_COPY
] = 0;
6589 kb_translation_table
[KEY_COPY
] |= 0x7c << 8;
6591 kb_translation_table
[KEY_PASTE
] = 0;
6592 kb_translation_table
[KEY_PASTE
] |= 0x7d << 8;
6594 kb_translation_table
[KEY_FIND
] = 0;
6595 kb_translation_table
[KEY_FIND
] |= 0x7e << 8;
6597 kb_translation_table
[KEY_CUT
] = 0;
6598 kb_translation_table
[KEY_CUT
] |= 0x7b << 8;
6600 kb_translation_table
[KEY_HELP
] = 0;
6601 kb_translation_table
[KEY_HELP
] |= 0x75 << 8;
6603 kb_translation_table
[KEY_MENU
] = 0;
6604 kb_translation_table
[KEY_MENU
] |= 0x76 << 8;
6606 kb_translation_table
[KEY_F13
] = 0;
6607 kb_translation_table
[KEY_F13
] |= 0x68 << 8;
6609 kb_translation_table
[KEY_F14
] = 0;
6610 kb_translation_table
[KEY_F14
] |= 0x69 << 8;
6612 kb_translation_table
[KEY_F15
] = 0;
6613 kb_translation_table
[KEY_F15
] |= 0x6a << 8;
6615 kb_translation_table
[KEY_F16
] = 0;
6616 kb_translation_table
[KEY_F16
] |= 0x6b << 8;
6618 kb_translation_table
[KEY_F17
] = 0;
6619 kb_translation_table
[KEY_F17
] |= 0x6c << 8;
6621 kb_translation_table
[KEY_F18
] = 0;
6622 kb_translation_table
[KEY_F18
] |= 0x6d << 8;
6624 kb_translation_table
[KEY_F19
] = 0;
6625 kb_translation_table
[KEY_F19
] |= 0x6e << 8;
6627 kb_translation_table
[KEY_F20
] = 0;
6628 kb_translation_table
[KEY_F20
] |= 0x6f << 8;
6630 kb_translation_table
[KEY_F21
] = 0;
6631 kb_translation_table
[KEY_F21
] |= 0x70 << 8;
6633 kb_translation_table
[KEY_F22
] = 0;
6634 kb_translation_table
[KEY_F22
] |= 0x71 << 8;
6636 kb_translation_table
[KEY_F23
] = 0;
6637 kb_translation_table
[KEY_F23
] |= 0x72 << 8;
6639 kb_translation_table
[KEY_F24
] = 0;
6640 kb_translation_table
[KEY_F24
] |= 0x73 << 8;
6643 static void Keyboard_translate_key( __u16 evdev_key
, long & ascii
, long & usb
)
6645 unsigned short tr
= kb_translation_table
[evdev_key
];
6648 usb
= ( tr
>> 8 ) & 0xff;
6651 class linux_keyboard
: public linux_device
6654 linux_keyboard() : linux_device()
6658 virtual void callback()
6664 while( ( len
= read( fd
, &event
, sizeof( event
) ) ) > 0 )
6666 if( len
< sizeof( event
) )
6668 EM_log( CK_LOG_WARNING
, "keyboard: read event from keyboard %i smaller than expected (%i), ignoring", num
, len
);
6672 if( event
.type
!= EV_KEY
)
6675 if( event
.value
== 2 )
6679 msg
.device_type
= CK_HID_DEV_KEYBOARD
;
6680 msg
.device_num
= num
;
6681 msg
.type
= event
.value
? CK_HID_BUTTON_DOWN
: CK_HID_BUTTON_UP
;
6682 msg
.eid
= event
.code
;
6683 msg
.idata
[0] = event
.value
;
6684 Keyboard_translate_key( event
.code
, msg
.idata
[2], msg
.idata
[1] );
6686 HidInManager::push_message( msg
);
6691 static vector
< linux_joystick
* > * joysticks
= NULL
;
6692 static vector
< linux_mouse
* > * mice
= NULL
;
6693 static vector
< linux_keyboard
* > * keyboards
= NULL
;
6695 static map
< int, linux_device
* > * device_map
= NULL
;
6697 static pollfd
* pollfds
= NULL
;
6698 #define DEFAULT_POLLFDS_SIZE (1)
6699 static size_t pollfds_size
= 0;
6700 static size_t pollfds_end
= 0;
6701 static int hid_channel_r
= -1; // HID communications channel, read fd
6702 static int hid_channel_w
= -1; // HID communications channel, write fd
6704 struct hid_channel_msg
6707 #define HID_CHANNEL_OPEN 1
6708 #define HID_CHANNEL_CLOSE 0
6709 #define HID_CHANNEL_QUIT -1
6710 linux_device
* device
;
6713 static t_CKBOOL g_hid_init
= FALSE
;
6720 pollfds
= new pollfd
[DEFAULT_POLLFDS_SIZE
];
6721 pollfds_size
= DEFAULT_POLLFDS_SIZE
;
6725 if( pipe( filedes
) )
6727 EM_log( CK_LOG_SEVERE
, "hid: unable to create pipe, initialization failed" );
6731 hid_channel_r
= filedes
[0];
6732 hid_channel_w
= filedes
[1];
6734 int fd_flags
= fcntl( hid_channel_r
, F_GETFL
);
6735 fcntl( hid_channel_r
, F_SETFL
, fd_flags
| O_NONBLOCK
);
6737 /* right now, the hid_channel is just used as a dummy file descriptor
6738 passed to poll, such that poll will work/block even when there are
6739 no open devices. In the future hid_channel could also be used to
6740 communicate between the VM thread and the HID thread */
6741 pollfds
[0].fd
= hid_channel_r
;
6742 pollfds
[0].events
= POLLIN
;
6743 pollfds
[0].revents
= 0;
6746 device_map
= new map
< int, linux_device
* >;
6748 Keyboard_init_translation_table();
6758 hid_channel_msg hcm
;
6759 while( poll( pollfds
, pollfds_end
, -1 ) > 0 )
6761 for( int i
= 1; i
< pollfds_end
; i
++ )
6763 if( pollfds
[i
].revents
& POLLIN
)
6765 ( *device_map
)[pollfds
[i
].fd
]->callback();
6766 pollfds
[i
].revents
= 0;
6770 if( pollfds
[0].revents
& POLLIN
)
6772 while( read( hid_channel_r
, &hcm
, sizeof( hcm
) ) > 0 )
6774 if( hcm
.action
== HID_CHANNEL_OPEN
)
6776 if( pollfds_end
>= pollfds_size
)
6778 pollfds_size
= pollfds_end
* 2;
6779 pollfd
* t_pollfds
= new pollfd
[pollfds_size
];
6780 memcpy( t_pollfds
, pollfds
, pollfds_end
* sizeof( pollfd
) );
6782 pollfds
= t_pollfds
;
6785 pollfds
[pollfds_end
].fd
= hcm
.device
->fd
;
6786 pollfds
[pollfds_end
].events
= POLLIN
;
6787 pollfds
[pollfds_end
].revents
= 0;
6788 hcm
.device
->pollfds_i
= pollfds_end
;
6789 ( *device_map
)[hcm
.device
->fd
] = hcm
.device
;
6793 else if( hcm
.action
== HID_CHANNEL_CLOSE
)
6795 // erase the closing entry by copying the last entry into it
6796 // this is okay even when joystick->pollfds_i == pollfds_end
6797 // because we decrement pollfds_end
6798 ( *device_map
)[pollfds
[pollfds_end
- 1].fd
]->pollfds_i
= hcm
.device
->pollfds_i
;
6799 pollfds
[hcm
.device
->pollfds_i
] = pollfds
[pollfds_end
- 1];
6801 close( hcm
.device
->fd
);
6802 device_map
->erase( hcm
.device
->fd
);
6805 else if( hcm
.action
== HID_CHANNEL_QUIT
)
6807 close( hid_channel_r
);
6823 hid_channel_msg hcm
= { HID_CHANNEL_QUIT
, NULL
};
6824 write( hid_channel_w
, &hcm
, sizeof( hcm
) );
6825 close( hid_channel_w
);
6833 int TiltSensor_read( t_CKINT
* x
, t_CKINT
* y
, t_CKINT
* z
)
6838 // designate new poll rate
6839 t_CKINT
TiltSensor_setPollRate( t_CKINT usec
)
6842 assert( usec
>= 0 );
6844 fprintf( stderr
, "TiltSensor - setPollRate is not (yet) supported on this platform...\n" );
6848 // query current poll rate
6849 t_CKINT
TiltSensor_getPollRate( )
6852 fprintf( stderr
, "TiltSensor - getPollRate is not (yet) supported on this platform...\n" );
6857 /*****************************************************************************
6858 Linux joystick support
6859 *****************************************************************************/
6860 #pragma mark Linux joystick support
6862 void Joystick_init()
6864 if( joysticks
!= NULL
)
6867 EM_log( CK_LOG_INFO
, "initializing joysticks" );
6870 joysticks
= new vector
< linux_joystick
* >;
6873 struct dirent
* dir_entity
;
6874 struct stat stat_buf
;
6876 uid_t uid
= geteuid();
6877 gid_t gid
= getegid();
6878 char buf
[CK_HID_STRBUFSIZE
];
6879 linux_joystick
* js
;
6881 dir_handle
= opendir( CK_HID_DIR
);
6882 if( dir_handle
== NULL
)
6884 if( errno
== EACCES
)
6885 EM_log( CK_LOG_WARNING
, "hid: error opening %s, unable to initialize joystick", CK_HID_DIR
);
6890 while( dir_entity
= readdir( dir_handle
) )
6892 if( sscanf( dir_entity
->d_name
, CK_HID_JOYSTICKFILE
, &js_num
) )
6894 snprintf( buf
, CK_HID_STRBUFSIZE
, "%s/%s", CK_HID_DIR
,
6895 dir_entity
->d_name
);
6896 if( ( fd
= open( buf
, O_RDONLY
| O_NONBLOCK
) ) >= 0 ||
6897 errno
== EACCES
) /* wait to report access errors until the
6898 device is actually opened */
6900 js
= new linux_joystick
;
6901 js
->js_num
= js_num
;
6902 js
->num
= joysticks
->size();
6905 ioctl( fd
, JSIOCGNAME( CK_HID_NAMESIZE
), js
->name
);
6906 close( fd
); // no need to keep the file open
6908 strncpy( js
->filename
, buf
, CK_HID_STRBUFSIZE
);
6909 joysticks
->push_back( js
);
6910 EM_log( CK_LOG_INFO
, "joystick: found device %s", js
->name
);
6915 closedir( dir_handle
);
6919 void Joystick_poll()
6924 void Joystick_quit()
6926 if( joysticks
== NULL
)
6929 vector
< linux_joystick
* >::size_type i
, len
= joysticks
->size();
6931 for( i
= 0; i
< len
; i
++ )
6932 delete joysticks
->at( i
);
6938 int Joystick_count()
6940 if( joysticks
== NULL
)
6942 return joysticks
->size();
6945 int Joystick_open( int js
)
6947 if( joysticks
== NULL
|| js
< 0 || js
>= joysticks
->size() )
6950 linux_joystick
* joystick
= joysticks
->at( js
);
6952 if( joystick
->refcount
== 0 )
6954 if( ( joystick
->fd
= open( joystick
->filename
, O_RDONLY
| O_NONBLOCK
) ) < 0 )
6956 EM_log( CK_LOG_SEVERE
, "joystick: unable to open %s: %s", joystick
->filename
, strerror( errno
) );
6960 hid_channel_msg hcm
= { HID_CHANNEL_OPEN
, joystick
};
6961 write( hid_channel_w
, &hcm
, sizeof( hcm
) );
6964 joystick
->refcount
++;
6969 int Joystick_close( int js
)
6971 if( joysticks
== NULL
|| js
< 0 || js
>= joysticks
->size() )
6974 linux_joystick
* joystick
= joysticks
->at( js
);
6976 joystick
->refcount
--;
6978 if( joystick
->refcount
== 0 )
6980 hid_channel_msg hcm
= { HID_CHANNEL_CLOSE
, joystick
};
6981 write( hid_channel_w
, &hcm
, sizeof( hcm
) );
6988 const char * Joystick_name( int js
)
6990 if( joysticks
== NULL
|| js
< 0 || js
>= joysticks
->size() )
6993 return joysticks
->at( js
)->name
;
6996 #define test_bit( array, bit ) (array[bit/8] & (1<<(bit%8)))
6998 void Mouse_configure( const char * filename
)
7000 struct stat statbuf
;
7001 int fd
, devmajor
, devminor
, is_mouse
= 0;
7002 linux_mouse
* mouse
;
7003 unsigned char relcaps
[(REL_MAX
/ 8) + 1];
7004 unsigned char abscaps
[(ABS_MAX
/ 8) + 1];
7005 unsigned char keycaps
[(KEY_MAX
/ 8) + 1];
7007 if( stat( filename
, &statbuf
) == -1 )
7010 if( S_ISCHR( statbuf
.st_mode
) == 0 )
7011 return; /* not a character device... */
7013 devmajor
= ( statbuf
.st_rdev
& 0xFF00 ) >> 8;
7014 devminor
= ( statbuf
.st_rdev
& 0x00FF );
7015 if ( ( devmajor
!= 13 ) || ( devminor
< 64 ) || ( devminor
> 96 ) )
7016 return; /* not an evdev. */
7018 if( ( fd
= open( filename
, O_RDONLY
| O_NONBLOCK
) ) < 0 )
7021 memset( relcaps
, 0, sizeof( relcaps
) );
7022 memset( abscaps
, 0, sizeof( abscaps
) );
7023 memset( keycaps
, 0, sizeof( keycaps
) );
7026 if( ioctl( fd
, EVIOCGBIT( EV_KEY
, sizeof( keycaps
) ), keycaps
) == -1 )
7030 if( ioctl( fd
, EVIOCGBIT( EV_REL
, sizeof( relcaps
) ), relcaps
) != -1 )
7032 if( test_bit( relcaps
, REL_X
) && test_bit( relcaps
, REL_Y
) &&
7033 test_bit( keycaps
, BTN_MOUSE
) )
7038 if( test_bit( relcaps
, REL_DIAL
) )
7042 if( ioctl( fd
, EVIOCGBIT( EV_ABS
, sizeof( abscaps
) ), abscaps
) != -1 )
7044 if( test_bit( abscaps
, ABS_X
) && test_bit( abscaps
, ABS_Y
) &&
7045 ( test_bit( keycaps
, BTN_MOUSE
) || test_bit( keycaps
, BTN_TOUCH
) ) )
7052 mouse
= new linux_mouse
;
7053 mouse
->num
= mice
->size();
7054 ioctl( fd
, EVIOCGNAME( CK_HID_NAMESIZE
), mouse
->name
);
7056 close( fd
); // no need to keep the file open
7057 strncpy( mouse
->filename
, filename
, CK_HID_STRBUFSIZE
);
7058 mice
->push_back( mouse
);
7059 EM_log( CK_LOG_INFO
, "mouse: found device %s", mouse
->name
);
7067 EM_log( CK_LOG_INFO
, "initializing mice" );
7070 mice
= new vector
< linux_mouse
* >;
7073 struct dirent
* dir_entity
;
7074 struct stat stat_buf
;
7076 char buf
[CK_HID_STRBUFSIZE
];
7077 linux_mouse
* mouse
;
7079 dir_handle
= opendir( CK_HID_DIR
);
7080 if( dir_handle
== NULL
)
7082 EM_log( CK_LOG_WARNING
, "hid: error opening %s, unable to initialize mice", CK_HID_DIR
);
7087 while( dir_entity
= readdir( dir_handle
) )
7089 if( sscanf( dir_entity
->d_name
, CK_HID_EVDEVFILE
, &m_num
) )
7091 snprintf( buf
, CK_HID_STRBUFSIZE
, "%s/%s", CK_HID_DIR
,
7092 dir_entity
->d_name
);
7093 Mouse_configure( buf
);
7094 /* if( ( fd = open( buf, O_RDONLY | O_NONBLOCK ) ) >= 0 ||
7095 errno == EACCES ) *//* wait to report access errors until the
7096 device is actually opened *//*
7098 mouse = new linux_mouse;
7099 mouse->m_num = m_num;
7100 mouse->num = mice->size();
7101 //ioctl( fd, JSIOCGNAME( CK_HID_NAMESIZE ), js->name );
7103 close( fd ); // no need to keep the file open
7104 strncpy( mouse->filename, buf, CK_HID_STRBUFSIZE );
7105 mice->push_back( mouse );
7106 //EM_log( CK_LOG_INFO, "mouse: found device %s", mouse->name );
7111 closedir( dir_handle
);
7126 vector
< linux_mouse
* >::size_type i
, len
= mice
->size();
7128 for( i
= 0; i
< len
; i
++ )
7129 delete mice
->at( i
);
7139 return mice
->size();
7142 int Mouse_open( int m
)
7144 if( mice
== NULL
|| m
< 0 || m
>= mice
->size() )
7147 linux_mouse
* mouse
= mice
->at( m
);
7149 if( mouse
->refcount
== 0 )
7151 if( ( mouse
->fd
= open( mouse
->filename
, O_RDONLY
| O_NONBLOCK
) ) < 0 )
7153 EM_log( CK_LOG_SEVERE
, "mouse: unable to open %s: %s", mouse
->filename
, strerror( errno
) );
7157 mouse
->needs_open
= TRUE
;
7158 hid_channel_msg hcm
= { HID_CHANNEL_OPEN
, mouse
};
7159 write( hid_channel_w
, &hcm
, sizeof( hcm
) );
7167 int Mouse_close( int m
)
7169 if( mice
== NULL
|| m
< 0 || m
>= mice
->size() )
7172 linux_mouse
* mouse
= mice
->at( m
);
7176 if( mouse
->refcount
== 0 )
7178 mouse
->needs_close
= TRUE
;
7179 hid_channel_msg hcm
= { HID_CHANNEL_CLOSE
, mouse
};
7180 write( hid_channel_w
, &hcm
, sizeof( hcm
) );
7186 const char * Mouse_name( int m
)
7188 if( mice
== NULL
|| m
< 0 || m
>= mice
->size() )
7190 return mice
->at( m
)->name
;
7193 void Keyboard_configure( const char * filename
)
7195 struct stat statbuf
;
7196 int fd
, devmajor
, devminor
;
7197 linux_keyboard
* keyboard
;
7198 unsigned char relcaps
[(REL_MAX
/ 8) + 1];
7199 unsigned char abscaps
[(ABS_MAX
/ 8) + 1];
7200 unsigned char keycaps
[(KEY_MAX
/ 8) + 1];
7202 if( stat( filename
, &statbuf
) == -1 )
7205 if( S_ISCHR( statbuf
.st_mode
) == 0 )
7206 return; /* not a character device... */
7208 devmajor
= ( statbuf
.st_rdev
& 0xFF00 ) >> 8;
7209 devminor
= ( statbuf
.st_rdev
& 0x00FF );
7210 if ( ( devmajor
!= 13 ) || ( devminor
< 64 ) || ( devminor
> 96 ) )
7211 return; /* not an evdev. */
7213 if( ( fd
= open( filename
, O_RDONLY
| O_NONBLOCK
) ) < 0 )
7216 memset( relcaps
, 0, sizeof( relcaps
) );
7217 memset( abscaps
, 0, sizeof( abscaps
) );
7218 memset( keycaps
, 0, sizeof( keycaps
) );
7221 if( ioctl( fd
, EVIOCGBIT( EV_KEY
, sizeof( keycaps
) ), keycaps
) == -1 )
7224 if( ioctl( fd
, EVIOCGBIT( EV_REL
, sizeof( relcaps
) ), relcaps
) != -1 )
7226 for( int i
= 0; i
< sizeof( relcaps
); i
++ )
7231 if( ioctl( fd
, EVIOCGBIT( EV_ABS
, sizeof( abscaps
) ), abscaps
) != -1 )
7233 for( int i
= 0; i
< sizeof( abscaps
); i
++ )
7238 for( int i
= 0; i
< sizeof( keycaps
); i
++ )
7240 for( int j
= 0; j
< 8; j
++ )
7242 if( keycaps
[i
] & ( 1 << j
) )
7247 keyboard
= new linux_keyboard
;
7248 keyboard
->num
= keyboards
->size();
7249 ioctl( fd
, EVIOCGNAME( CK_HID_NAMESIZE
), keyboard
->name
);
7251 close( fd
); // no need to keep the file open
7252 strncpy( keyboard
->filename
, filename
, CK_HID_STRBUFSIZE
);
7253 keyboards
->push_back( keyboard
);
7254 EM_log( CK_LOG_INFO
, "keyboard: found device %s", keyboard
->name
);
7257 void Keyboard_init()
7259 if( keyboards
!= NULL
)
7262 EM_log( CK_LOG_INFO
, "initializing keyboards" );
7265 keyboards
= new vector
< linux_keyboard
* >;
7268 struct dirent
* dir_entity
;
7272 char buf
[CK_HID_STRBUFSIZE
];
7274 dir_handle
= opendir( CK_HID_DIR
);
7275 if( dir_handle
== NULL
)
7277 if( errno
== EACCES
)
7278 EM_log( CK_LOG_WARNING
, "hid: error opening %s, unable to initialize keyboards", CK_HID_DIR
);
7283 while( dir_entity
= readdir( dir_handle
) )
7285 if( sscanf( dir_entity
->d_name
, CK_HID_EVDEVFILE
, &m_num
) )
7287 snprintf( buf
, CK_HID_STRBUFSIZE
, "%s/%s", CK_HID_DIR
,
7288 dir_entity
->d_name
);
7289 Keyboard_configure( buf
);
7293 closedir( dir_handle
);
7298 void Keyboard_poll()
7303 void Keyboard_quit()
7308 int Keyboard_count()
7310 if( keyboards
== NULL
)
7312 return keyboards
->size();
7315 int Keyboard_open( int k
)
7317 if( keyboards
== NULL
|| k
< 0 || k
>= keyboards
->size() )
7320 linux_keyboard
* keyboard
= keyboards
->at( k
);
7322 if( keyboard
->refcount
== 0 )
7324 if( ( keyboard
->fd
= open( keyboard
->filename
, O_RDONLY
| O_NONBLOCK
) ) < 0 )
7326 EM_log( CK_LOG_SEVERE
, "keyboard: unable to open %s: %s", keyboard
->filename
, strerror( errno
) );
7330 hid_channel_msg hcm
= { HID_CHANNEL_OPEN
, keyboard
};
7331 write( hid_channel_w
, &hcm
, sizeof( hcm
) );
7334 keyboard
->refcount
++;
7339 int Keyboard_close( int k
)
7341 if( keyboards
== NULL
|| k
< 0 || k
>= keyboards
->size() )
7344 linux_keyboard
* keyboard
= keyboards
->at( k
);
7346 keyboard
->refcount
--;
7348 if( keyboard
->refcount
== 0 )
7350 hid_channel_msg hcm
= { HID_CHANNEL_CLOSE
, keyboard
};
7351 write( hid_channel_w
, &hcm
, sizeof( hcm
) );
7357 const char * Keyboard_name( int k
)
7359 if( keyboards
== NULL
|| k
< 0 || k
>= keyboards
->size() )
7362 return keyboards
->at( k
)->name
;
7368 #pragma mark Hid graveyard
7369 /***** empty functions for stuff that isn't yet cross platform *****/
7370 #ifndef __PLATFORM_MACOSX__
7371 /*** empty functions for Mac-only stuff ***/
7373 int Joystick_count_elements( int js
, int type
) { return -1; }
7375 int Mouse_count_elements( int js
, int type
) { return -1; }
7376 int Mouse_start_cursor_track(){ return -1; }
7377 int Mouse_stop_cursor_track(){ return -1; }
7379 int Keyboard_count_elements( int js
, int type
) { return -1; }
7380 int Keyboard_send( int k
, const HidMsg
* msg
){ return -1; }
7382 int WiiRemote_send( int k
, const HidMsg
* msg
){ return -1; }
7384 void WiiRemote_init(){}
7385 void WiiRemote_poll(){}
7386 void WiiRemote_quit(){}
7387 void WiiRemote_probe(){}
7388 int WiiRemote_count(){ return 0; }
7389 int WiiRemote_open( int wr
){ return -1; }
7390 int WiiRemote_open( const char * name
){ return -1; }
7391 int WiiRemote_close( int wr
){ return -1; }
7392 int WiiRemote_send( const HidMsg
* msg
){ return -1; }
7393 const char * WiiRemote_name( int wr
){ return NULL
; }
7395 void TiltSensor_init(){}
7396 void TiltSensor_quit(){}
7397 void TiltSensor_probe(){}
7398 int TiltSensor_count(){ return 0; }
7399 int TiltSensor_open( int ts
){ return -1; }
7400 int TiltSensor_close( int ts
){ return -1; }
7401 int TiltSensor_read( int ts
, int type
, int num
, HidMsg
* msg
){ return -1; }
7402 const char * TiltSensor_name( int ts
){ return NULL
; }
7408 #ifdef __CHIP_MODE__
7410 // #include "util_iphone.h"
7412 extern int get_tilt_sensor_x();
7413 extern int get_tilt_sensor_y();
7414 extern int get_tilt_sensor_z();
7416 extern void start_hid_multi_touch();
7417 extern void stop_hid_multi_touch();
7426 void Mouse_probe(){}
7433 int Mouse_count_elements( int js
, int type
)
7438 int Mouse_open( int m
)
7442 start_hid_multi_touch();
7449 int Mouse_open( const char * name
)
7454 int Mouse_close( int m
)
7458 stop_hid_multi_touch();
7465 int Mouse_send( int m
, const HidMsg
* msg
)
7470 const char * Mouse_name( int m
)
7473 return "iPhone Multitouch";
7478 int Mouse_buttons( int m
)
7486 int Mouse_start_cursor_track()
7491 int Mouse_stop_cursor_track()
7496 void TiltSensor_init(){}
7497 void TiltSensor_quit(){}
7498 void TiltSensor_probe(){}
7500 int TiltSensor_count()
7505 int TiltSensor_open( int ts
)
7512 int TiltSensor_close( int ts
)
7519 int TiltSensor_read( int ts
, int type
, int num
, HidMsg
* msg
)
7521 if( type
!= CK_HID_ACCELEROMETER
)
7524 msg
->idata
[0] = get_tilt_sensor_x();
7525 msg
->idata
[1] = get_tilt_sensor_y();
7526 msg
->idata
[2] = get_tilt_sensor_z();
7531 const char * TiltSensor_name( int ts
)
7534 return "iPhone Accelerometer";
7539 // ge: SMS multi-thread poll rate
7540 t_CKINT
TiltSensor_setPollRate( t_CKINT usec
)
7545 t_CKINT
TiltSensor_getPollRate( )
7550 void Joystick_init(){}
7552 void Joystick_poll(){}
7554 void Joystick_quit(){}
7556 void Joystick_probe(){}
7558 int Joystick_count()
7563 int Joystick_count_elements( int js
, int type
)
7568 int Joystick_open( int js
)
7573 int Joystick_open_async( int js
)
7578 int Joystick_open( const char * name
)
7583 int Joystick_close( int js
)
7588 int Joystick_send( int js
, const HidMsg
* msg
)
7594 const char * Joystick_name( int js
)
7599 int Joystick_axes( int js
)
7604 int Joystick_buttons( int js
)
7609 int Joystick_hats( int js
)
7614 void Keyboard_init(){}
7615 void Keyboard_poll(){}
7616 void Keyboard_quit(){}
7617 void Keyboard_probe(){}
7619 int Keyboard_count()
7624 int Keyboard_count_elements( int js
, int type
)
7629 int Keyboard_open( int kb
)
7634 int Keyboard_open( const char * name
)
7639 int Keyboard_close( int kb
)
7644 int Keyboard_send( int kb
, const HidMsg
* msg
)
7649 const char * Keyboard_name( int kb
)
7654 void WiiRemote_init(){}
7655 void WiiRemote_poll(){}
7656 void WiiRemote_quit(){}
7657 void WiiRemote_probe(){}
7659 int WiiRemote_count()
7664 int WiiRemote_open( int wr
)
7669 int WiiRemote_open( const char * name
)
7674 int WiiRemote_close( int wr
)
7679 int WiiRemote_send( int wr
, const HidMsg
* msg
)
7684 const char * WiiRemote_name( int wr
)
7690 #endif // __CHIP_MODE__