Initial release of native library

This commit is contained in:
gregorypierce 2003-08-05 18:33:07 +00:00
parent c2688c3ae8
commit 24d639f5be

View file

@ -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 );
}
}