diff options
-rw-r--r-- | plugins/OSX/src/native/jinputjnilib.c | 716 |
1 files changed, 716 insertions, 0 deletions
diff --git a/plugins/OSX/src/native/jinputjnilib.c b/plugins/OSX/src/native/jinputjnilib.c new file mode 100644 index 0000000..0d73db3 --- /dev/null +++ b/plugins/OSX/src/native/jinputjnilib.c @@ -0,0 +1,716 @@ +/* + * %W% %E% + * + * Copyright 2002 Sun Microsystems, Inc. All rights reserved. + * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +/***************************************************************************** +* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* - Redistribution of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* - Redistribution in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materails provided with the distribution. +* +* Neither the name Sun Microsystems, Inc. or the names of the contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* This software is provided "AS IS," without a warranty of any kind. +* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING +* ANY IMPLIED WARRANT OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR +* NON-INFRINGEMEN, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND +* ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS +* A RESULT OF USING, MODIFYING OR DESTRIBUTING THIS SOFTWARE OR ITS +* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST +* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, +* INCIDENTAL OR PUNITIVE DAMAGES. HOWEVER CAUSED AND REGARDLESS OF THE THEORY +* OF LIABILITY, ARISING OUT OF THE USE OF OUR INABILITY TO USE THIS SOFTWARE, +* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +* +* You acknowledge that this software is not designed or intended for us in +* the design, construction, operation or maintenance of any nuclear facility +* +*****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <sys/errno.h> +#include <sysexits.h> +#include <mach/mach.h> +#include <mach/mach_error.h> +#include <IOKit/IOKitLib.h> +#include <IOKit/IOCFPlugIn.h> +#include <IOKit/hid/IOHIDLib.h> +#include <IOKit/hid/IOHIDKeys.h> +#include <CoreFoundation/CoreFoundation.h> +#include <Carbon/Carbon.h> +#include "net_java_games_input_OSXEnvironmentPlugin.h" + +Boolean init( JNIEnv * env ); +void createMasterPort(); +void disposeMasterPort(); + + +void createHIDDevice(io_object_t hidDevice, IOHIDDeviceInterface ***hidDeviceInterface); +IOReturn openDevice(IOHIDDeviceInterface ***hidDeviceInterface); +IOReturn closeDevice(IOHIDDeviceInterface ***hidDeviceInterface); + + +Boolean showDictionaryElement (CFDictionaryRef dictionary, CFStringRef key); +void showProperty(const void * key, const void * value); +void displayCFProperty(CFStringRef object, CFTypeRef value); +void CFObjectShow( CFTypeRef value ); +void CFObjectSend( CFTypeRef value ); + +jclass CLASS_JNIWrapper = NULL; +jmethodID MID_AddDevice = NULL; +jmethodID MID_AddControllerElement = NULL; +mach_port_t masterPort = NULL; +io_iterator_t hidObjectIterator; +int gElementIndex; + +long elementCookie; +long collectionType; +long min; +long max; +long scaledMin; +long scaledMax; +long size; +jboolean isRelative; +jboolean isWrapping; +jboolean isNonLinear; + + +JNIEnv * lpEnv; +jlong lpDevice; + + + + +Boolean showDictionaryElement (CFDictionaryRef dictionary, CFStringRef key) +{ + CFTypeRef value = CFDictionaryGetValue (dictionary, key); + if (value) + { + const char * c = CFStringGetCStringPtr (key, CFStringGetSystemEncoding ()); + if (c) + { + printf ("%s", c); + } + else + { + CFIndex bufferSize = CFStringGetLength (key) + 1; + char * buffer = (char *)malloc (bufferSize); + if (buffer) + { + if (CFStringGetCString (key, buffer, bufferSize, CFStringGetSystemEncoding ())) + printf ("%s", buffer); + free(buffer); + } + } + + printf("="); + + CFObjectShow( value ); + + printf("\n"); + } + return (value != NULL); +} + +static void showCFArray (const void * value, void * parameter) +{ + if (CFGetTypeID (value) != CFDictionaryGetTypeID ()) + { + return; + } + + CFObjectShow(value); +} + +void CFObjectShow( CFTypeRef value ) +{ + CFTypeID type = CFGetTypeID(value); + if (type == CFArrayGetTypeID()) + { + + printf("Array Type\n"); + CFRange range = {0, CFArrayGetCount (value)}; + CFIndex savedIndex = gElementIndex; + + //Show an element array containing one or more element dictionaries + gElementIndex = 0; //Reset index to zero + CFArrayApplyFunction (value, range, showCFArray, 0); + + gElementIndex = savedIndex; + } + else if (type == CFBooleanGetTypeID()) + { + printf(CFBooleanGetValue(value) ? "true" : "false"); + } + else if (type == CFDictionaryGetTypeID()) + { + printf("Map\n"); + + + showDictionaryElement (value, CFSTR(kIOHIDElementCookieKey)); + showDictionaryElement (value, CFSTR(kIOHIDElementCollectionTypeKey)); + + showDictionaryElement (value, CFSTR(kIOHIDElementMinKey)); + showDictionaryElement (value, CFSTR(kIOHIDElementMaxKey)); + showDictionaryElement (value, CFSTR(kIOHIDElementScaledMinKey)); + showDictionaryElement (value, CFSTR(kIOHIDElementScaledMaxKey)); + + showDictionaryElement (value, CFSTR(kIOHIDElementSizeKey)); + showDictionaryElement (value, CFSTR(kIOHIDElementIsRelativeKey)); + showDictionaryElement (value, CFSTR(kIOHIDElementIsWrappingKey)); + showDictionaryElement (value, CFSTR(kIOHIDElementIsNonLinearKey)); +#ifdef kIOHIDElementHasPreferredStateKey + showDictionaryElement (value, CFSTR(kIOHIDElementHasPreferredStateKey)); +#else + showDictionaryElement (value, CFSTR(kIOHIDElementHasPreferedStateKey)); +#endif + showDictionaryElement (value, CFSTR(kIOHIDElementHasNullStateKey)); + showDictionaryElement (value, CFSTR(kIOHIDElementVendorSpecificKey)); + showDictionaryElement (value, CFSTR(kIOHIDElementUnitKey)); + showDictionaryElement (value, CFSTR(kIOHIDElementUnitExponentKey)); + showDictionaryElement (value, CFSTR(kIOHIDElementNameKey)); + showDictionaryElement (value, CFSTR(kIOHIDElementKey)); + + printf("\n\n\n"); + } + else if (type == CFNumberGetTypeID()) + { + long number; + if (CFNumberGetValue (value, kCFNumberLongType, &number)) + { + printf("0x%lx (%ld)", number, number); + } + } + else if (type == CFStringGetTypeID()) + { + const char * c = CFStringGetCStringPtr (value, CFStringGetSystemEncoding ()); + if (c) + { + printf ("%s", c); + } + else + { + CFIndex bufferSize = CFStringGetLength (value) + 1; + char * buffer = (char *)malloc (bufferSize); + if (buffer) + { + if (CFStringGetCString (value, buffer, bufferSize, CFStringGetSystemEncoding ())) + { + printf ("%s", buffer); + } + + free(buffer); + } + } + } +} + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// + +Boolean init(JNIEnv* env) +{ + CLASS_JNIWrapper = (*env)->FindClass(env,"net/java/games/input/OSXEnvironmentPlugin"); + if ( CLASS_JNIWrapper == NULL ) + { + printf("Class OSXEnvironmentPlugin not found... \n"); + return FALSE; + } + + MID_AddDevice = (*env)->GetMethodID(env, CLASS_JNIWrapper, "addController", "(JLjava/lang/String;I)V"); + if (MID_AddDevice == NULL) + { + printf("Method addController not found... \n"); + return FALSE; + } + + MID_AddControllerElement = (*env)->GetMethodID(env, CLASS_JNIWrapper, "addControllerElement", "(JJILjava/lang/String;IIIIIZZZZZ)V"); + if (MID_AddDeviceElement == NULL) + { + printf("Method addControllerElement not found... \n"); + return FALSE; + } + + return TRUE; +} + +void createMasterPort() +{ + IOReturn ioReturnValue = kIOReturnSuccess; + + //Get a Mach port to initiate communication with I/O Kit. + // + ioReturnValue = IOMasterPort(bootstrap_port, &masterPort); +} + +void disposeMasterPort() +{ + //Free master port if we created one. + // + if (masterPort) + { + mach_port_deallocate(mach_task_self(), masterPort); + } +} + +void createHIDDevice( io_object_t hidDevice, IOHIDDeviceInterface ***hidDeviceInterface ) +{ + io_name_t className; + IOCFPlugInInterface **plugInInterface = NULL; + HRESULT plugInResult = S_OK; + SInt32 score = 0; + IOReturn ioReturnValue = kIOReturnSuccess; + + ioReturnValue = IOObjectGetClass(hidDevice, className); + if ( ioReturnValue != kIOReturnSuccess ) + { + printf("Failed to getIOObject class name."); + } + + printf("Found device type %s\n", className); + + ioReturnValue = IOCreatePlugInInterfaceForService(hidDevice, + kIOHIDDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, + &plugInInterface, + &score); + + if (ioReturnValue == kIOReturnSuccess) + { + //Call a method of the intermediate plug-in to create the device + //interface + plugInResult = (*plugInInterface)->QueryInterface(plugInInterface, + CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), + (LPVOID) hidDeviceInterface); + if ( plugInResult != S_OK ) + { + printf("Couldn't create HID class device interface"); + } + + (*plugInInterface)->Release(plugInInterface); + } +} + +IOReturn openDevice(IOHIDDeviceInterface ***hidDeviceInterface) +{ + IOReturn ioReturnValue = kIOReturnSuccess; + + //todo, change this to be controlled from the java layer at each device + // + ioReturnValue = (**hidDeviceInterface)->open(*hidDeviceInterface, 0 ); + if ( ioReturnValue != kIOReturnSuccess ) + { + printf("Unable to open device - return [%d]\n", ioReturnValue ); + } + else + { + printf("Successfully opened device \n"); + } + + return ioReturnValue; +} + +IOReturn closeDevice(IOHIDDeviceInterface ***hidDeviceInterface) +{ + IOReturn ioReturnValue = kIOReturnSuccess; + + ioReturnValue = (**hidDeviceInterface)->close(*hidDeviceInterface); + if ( ioReturnValue != kIOReturnSuccess ) + { + printf("Unable to close device - return [%d]\n", ioReturnValue ); + } + else + { + printf("Successfully closed device \n"); + } + + // release the device interface + // + (**hidDeviceInterface)->Release(*hidDeviceInterface); + + return ioReturnValue; +} + +void addControllerElements( CFMutableDictionaryRef dictionary, CFStringRef key ) +{ + printf("Adding controller elements\n"); + + CFTypeRef value = CFDictionaryGetValue (dictionary, key); + if (value) + { + CFTypeID type = CFGetTypeID(value); + + CFRange range = {0, CFArrayGetCount (value)}; + CFIndex savedIndex = gElementIndex; + + //Show an element array containing one or more element dictionaries + gElementIndex = 0; //Reset index to zero + CFArrayApplyFunction (value, range, sendCFArray, 0); + + gElementIndex = savedIndex; + } +} + +static void sendCFArray(const void * value, void * parameter) +{ + if (CFGetTypeID (value) != CFDictionaryGetTypeID ()) + { + return; + } + + CFObjectSend(value); +} + +void CFObjectSend( CFTypeRef value ) +{ + CFTypeID type = CFGetTypeID(value); + if (type == CFArrayGetTypeID()) + { + + printf("Array Type\n"); + CFRange range = {0, CFArrayGetCount (value)}; + CFIndex savedIndex = gElementIndex; + + //Show an element array containing one or more element dictionaries + gElementIndex = 0; //Reset index to zero + CFArrayApplyFunction (value, range, sendCFArray, 0); + + gElementIndex = savedIndex; + } + else if (type == CFDictionaryGetTypeID()) + { + printf("Sending Map\n"); + + + CFTypeRef val = CFDictionaryGetValue( value, CFSTR(kIOHIDElementCookieKey) ); + if ( val ) + { + CFNumberGetValue ( val , kCFNumberLongType, &elementCookie); + printf("ElementCookie - 0x%lx (%ld) \n", elementCookie, elementCookie); + } + + val = CFDictionaryGetValue( value, CFSTR(kIOHIDElementCollectionTypeKey) ); + if ( val ) + { + CFNumberGetValue ( val, kCFNumberLongType, &collectionType); + printf("collection Type - 0x%lx (%ld) \n", collectionType, collectionType); + } + + val = CFDictionaryGetValue( value, CFSTR(kIOHIDElementMinKey) ); + if ( val ) + { + CFNumberGetValue ( val, kCFNumberLongType, &min); + printf("min - 0x%lx (%ld) \n", min, min); + } + + val = CFDictionaryGetValue( value, CFSTR(kIOHIDElementMaxKey) ); + if ( val ) + { + CFNumberGetValue ( val, kCFNumberLongType, &max); + printf("max - 0x%lx (%ld) \n", max, max); + } + + val = CFDictionaryGetValue( value, CFSTR(kIOHIDElementScaledMinKey) ); + if ( val ) + { + CFNumberGetValue ( val, kCFNumberLongType, &scaledMin); + printf("scaledMin - 0x%lx (%ld) \n", scaledMin, scaledMin); + } + + val = CFDictionaryGetValue( value, CFSTR(kIOHIDElementScaledMaxKey) ); + if ( val ) + { + CFNumberGetValue ( val, kCFNumberLongType, &scaledMax); + printf("scaledMax - 0x%lx (%ld) \n", scaledMax, scaledMax); + } + + val = CFDictionaryGetValue( value, CFSTR(kIOHIDElementSizeKey) ); + if ( val ) + { + CFNumberGetValue ( val, kCFNumberLongType, &size); + printf("Size - 0x%lx (%ld) \n", size, size); + } + + + printf("End of element definition \n"); + +/* + + jboolean isRelative; + isRelative = (CFBooleanGetValue(value) ? JNI_TRUE : JNI_FALSE); + + + jboolean isWrapping; + isWrapping = (CFBooleanGetValue(value) ? JNI_TRUE : JNI_FALSE); + + jboolean isNonLinear; + isNonLinear = (CFBooleanGetValue(value) ? JNI_TRUE : JNI_FALSE); +*/ +#ifdef kIOHIDElementHasPreferredStateKey + //showDictionaryElement (value, CFSTR(kIOHIDElementHasPreferredStateKey)); +#else + //showDictionaryElement (value, CFSTR(kIOHIDElementHasPreferedStateKey)); +#endif + //showDictionaryElement (value, CFSTR(kIOHIDElementHasNullStateKey)); + //showDictionaryElement (value, CFSTR(kIOHIDElementVendorSpecificKey)); + + //showDictionaryElement (value, CFSTR(kIOHIDElementKey)); + + //showDictionaryElement (value, CFSTR(kIOHIDElementKey)); + + CFTypeRef object = CFDictionaryGetValue (value, CFSTR(kIOHIDElementKey)); + if (object) + { + CFObjectSend( object ); + } + + printf("\n\n\n"); + } +} + +/* + * Class: net_java_games_input_OSXEnvironmentPlugin + * Method: hidCreate + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_net_java_games_input_OSXEnvironmentPlugin_hidCreate + (JNIEnv * env, jobject obj) +{ + if ( init( env ) ) + { + createMasterPort(); + } +} +/* + * Class: net_java_games_input_OSXEnvironmentPlugin + * Method: hidDispose + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_net_java_games_input_OSXEnvironmentPlugin_hidDispose + (JNIEnv * env, jobject obj) +{ + disposeMasterPort(); +} + + +/* + * Class: net_java_games_input_OSXEnvironmentPlugin + * Method: enumDevices + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_net_java_games_input_OSXEnvironmentPlugin_enumDevices + (JNIEnv * env, jobject obj) +{ + CFMutableDictionaryRef hidMatchDictionary = NULL; + IOReturn ioReturnValue = kIOReturnSuccess; + Boolean noMatchingDevices = false; + + // Set up a matching dictionary to search the I/O Registry by class + // name for all HID class devices + // + hidMatchDictionary = IOServiceMatching(kIOHIDDeviceKey); + + // Now search I/O Registry for matching devices. + // + ioReturnValue = IOServiceGetMatchingServices(masterPort, hidMatchDictionary, &hidObjectIterator); + + noMatchingDevices = ((ioReturnValue != kIOReturnSuccess) | (hidObjectIterator == NULL)); + + // If search is unsuccessful, print message and hang. + // + if (noMatchingDevices) + { + printf("No matching HID class devices found."); + } + + // IOServiceGetMatchingServices consumes a reference to the + // dictionary, so we don't need to release the dictionary ref. + // + hidMatchDictionary = NULL; + + io_object_t hidDevice = NULL; + IOHIDDeviceInterface **hidDeviceInterface = NULL; + CFMutableDictionaryRef properties = 0; + char path[512]; + kern_return_t result; + + + while ((hidDevice = IOIteratorNext(hidObjectIterator))) + { + result = IORegistryEntryGetPath(hidDevice, kIOServicePlane, path); + + if ( result == KERN_SUCCESS ) + { + result = IORegistryEntryCreateCFProperties(hidDevice, + &properties, + kCFAllocatorDefault, + kNilOptions); + } + + if ((result == KERN_SUCCESS) && properties) + { + //showDictionaryElement(properties, CFSTR(kIOHIDTransportKey)); + //showDictionaryElement(properties, CFSTR(kIOHIDVendorKey)); + //printf("ProductID: "); showDictionaryElement(properties, CFSTR(kIOHIDProductIDKey)); + //printf("VersionNumber: "); showDictionaryElement(properties, CFSTR(kIOHIDVersionNumberKey)); + //printf("Manufacturer: "); showDictionaryElement(properties, CFSTR(kIOHIDManufacturerKey)); + //printf("ProductKey: "); showDictionaryElement(properties, CFSTR(kIOHIDProductKey)); + //printf("SerialNumber: "); showDictionaryElement(properties, CFSTR(kIOHIDSerialNumberKey)); + //showDictionaryElement(properties, CFSTR(kIOHIDLocationIDKey)); + //printf("PrimaryUsage: "); showDictionaryElement(properties, CFSTR(kIOHIDPrimaryUsageKey)); + //showDictionaryElement(properties, CFSTR(kIOHIDPrimaryUsagePageKey)); + //showDictionaryElement(properties, CFSTR(kIOHIDElementKey)); + + + + // get the product name + // + CFTypeRef productName = CFDictionaryGetValue (properties, CFSTR(kIOHIDProductKey)); + + // get the usage for this product + // + long usage; + CFNumberGetValue ( CFDictionaryGetValue( properties, CFSTR(kIOHIDPrimaryUsageKey) ), kCFNumberLongType, &usage); + + + createHIDDevice( hidDevice, &hidDeviceInterface ); + + IOObjectRelease( hidDevice ); + + if ( hidDeviceInterface != NULL ) + { + (*env)->CallVoidMethod(env, obj, MID_AddDevice, + (jlong)(long)hidDeviceInterface, + (*env)->NewStringUTF( env, CFStringGetCStringPtr( productName, CFStringGetSystemEncoding()) ), + (jint)usage ); + lpEnv = env; + lpDevice = (jlong)(long)hidDeviceInterface; + + addControllerElements( properties, CFSTR(kIOHIDElementKey) ); + + + } + + //Release the properties dictionary + CFRelease(properties); + } + + } + + IOObjectRelease(hidObjectIterator); +} + +/* + * Class: net_java_games_input_OSXEnvironmentPlugin + * Method: openDevice + * Signature: (JI)J + */ +JNIEXPORT jlong JNICALL Java_net_java_games_input_OSXEnvironmentPlugin_openDevice + (JNIEnv * env, jobject obj, jlong lpDevice, jint queueDepth) +{ + IOHIDDeviceInterface **hidDeviceInterface = NULL; + hidDeviceInterface = (IOHIDDeviceInterface **) (long)lpDevice; + openDevice( &hidDeviceInterface ); + + + IOHIDQueueInterface **queue = NULL; + queue = (*hidDeviceInterface)->allocQueue(hidDeviceInterface); + + if (queue) + { + // create a queue and specify how deep they want the input queue to be + // + (*queue)->create( queue, 0, (int)queueDepth ); + printf("InputQueue created %lx with depth %d \n", queue, (int)queueDepth ); + + // todo - add the buttons/keys we want to receive from the queue + + + // start the input queue + // + (*queue)->start( queue ); + } + else + { + printf("Unable to create queue for device! \n"); + } + + return (jlong)(long)queue; + +} + +/* + * Class: net_java_games_input_OSXEnvironmentPlugin + * Method: closeDevice + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_net_java_games_input_OSXEnvironmentPlugin_closeDevice + (JNIEnv * env, jobject obj, jlong lpDevice, jlong lpQueue) +{ + IOHIDDeviceInterface **hidDeviceInterface = NULL; + hidDeviceInterface = (IOHIDDeviceInterface **) (long)lpDevice; + + IOHIDQueueInterface **queue = NULL; + queue = (IOHIDQueueInterface **)(long)lpQueue; + + // stop the queue + // + (*queue)->stop(queue); + + // dispose of the queue + // + (*queue)->dispose(queue); + + // release the queue + // + (*queue)->Release(queue); + + // close the input device + // + closeDevice( &hidDeviceInterface ); +} + +/* + * Class: net_java_games_input_OSXEnvironmentPlugin + * Method: pollDevice + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_net_java_games_input_OSXEnvironmentPlugin_pollDevice + (JNIEnv * env, jobject obj, jlong lpQueue) +{ + IOHIDEventStruct event; + + IOHIDQueueInterface **queue = NULL; + queue = (IOHIDQueueInterface **)(long)lpQueue; + + AbsoluteTime zeroTime = {0,0}; + + HRESULT result = (*queue)->getNextEvent(queue, &event, zeroTime, 0); + if ( result ) + { + printf("Queue getNextEvent result: %lx\n", result ); + } + else + { + printf("Queue event[%lx] %ld\n", (unsigned long) event.elementCookie, event.value ); + } + + +} + + + |