smsvn -> ssc-hg glue: rearrange directory structure

This commit is contained in:
Devin J. Pohly
2013-06-10 15:38:43 -04:00
parent 51576d5942
commit 80057f53cd
3362 changed files with 0 additions and 0 deletions
+124
View File
@@ -0,0 +1,124 @@
#include "global.h"
#include "Crash.h"
#include "ProductInfo.h"
#include "arch/ArchHooks/ArchHooks.h"
#include <CoreServices/CoreServices.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sysctl.h>
RString CrashHandler::GetLogsDirectory()
{
FSRef fs;
char dir[PATH_MAX];
if( FSFindFolder(kUserDomain, kDomainLibraryFolderType, kDontCreateFolder, &fs) ||
FSRefMakePath(&fs, (UInt8 *)dir, PATH_MAX) )
{
return "/tmp";
}
return RString( dir ) + "/Logs/" PRODUCT_ID;
}
// XXX Can we use LocalizedString here instead?
#define LSTRING(b,x) CFBundleCopyLocalizedString( (b), CFSTR(x), NULL, CFSTR("Localizable") )
void CrashHandler::InformUserOfCrash( const RString& sPath )
{
CFBundleRef bundle = CFBundleGetMainBundle();
CFStringRef sAlternate = LSTRING( bundle, "Quit " PRODUCT_FAMILY );
/* XXX Translate these and remove the redefine of LSTRING. Another way to do this
* would be to pass bundle's URL to CFUserNotificationDisplayAlert's localizationURL
* parameter and let it do it. This wouldn't work for sBody though. */
#undef LSTRING
#define LSTRING(b,x) CFSTR(x)
CFStringRef sDefault = LSTRING( bundle, "File Bug Report" );
CFStringRef sOther = LSTRING( bundle, "Open crashinfo.txt" );
CFStringRef sTitle = LSTRING( bundle, PRODUCT_FAMILY " has crashed" );
CFStringRef sFormat = LSTRING( bundle, PRODUCT_FAMILY " has crashed. "
"Debugging information has been output to\n\n%s\n\n"
"Please file a bug report at\n\n%s" );
CFStringRef sBody = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, sFormat,
sPath.c_str(), REPORT_BUG_URL );
CFOptionFlags response = kCFUserNotificationCancelResponse;
CFTimeInterval timeout = 0.0; // Should we ever time out?
CFUserNotificationDisplayAlert( timeout, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL,
sTitle, sBody, sDefault, sAlternate, sOther, &response );
switch( response )
{
case kCFUserNotificationDefaultResponse:
HOOKS->GoToURL( REPORT_BUG_URL );
// Fall through.
case kCFUserNotificationOtherResponse:
// Open the file with the default application (probably TextEdit).
HOOKS->GoToURL( "file://" + sPath );
break;
}
CFRelease( sBody );
CFRelease( sFormat );
CFRelease( sTitle );
CFRelease( sOther );
CFRelease( sDefault );
CFRelease( sAlternate );
}
/* IMPORTANT: Because the definition of the kinfo_proc structure (in <sys/sysctl.h>)
* is conditionalized by __APPLE_API_UNSTABLE, you should restrict use of the [below]
* code to the debug build of your program.
* http://developer.apple.com/qa/qa2004/qa1361.html */
bool CrashHandler::IsDebuggerPresent()
{
#ifdef DEBUG
int ret;
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
struct kinfo_proc info;
size_t size;
// Initialize the flags so that, if sysctl fails for some bizarre
// reason, we get a predictable result.
info.kp_proc.p_flag = 0;
// Call sysctl.
size = sizeof( info );
ret = sysctl( mib, sizeof(mib)/sizeof(*mib), &info, &size, NULL, 0 );
// We're being debugged if the P_TRACED flag is set.
return ret == 0 && (info.kp_proc.p_flag & P_TRACED) != 0;
#else
return false;
#endif
}
void CrashHandler::DebugBreak()
{
DebugStr( "\pDebugBreak()" );
}
/*
* (c) 2003-2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+37
View File
@@ -0,0 +1,37 @@
#ifndef DARWIN_CRASH_H
#define DARWIN_CRASH_H
namespace CrashHandler
{
RString GetLogsDirectory();
void InformUserOfCrash( const RString& sPath );
bool IsDebuggerPresent();
void DebugBreak();
}
#endif /* DARWIN_CRASH_H */
/*
* (c) 2003-2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
@@ -0,0 +1,90 @@
#include <mach/mach_types.h>
#include <mach/thread_act.h>
#include <mach/mach_init.h>
#include <mach/mach_error.h>
#include "Backtrace.h"
bool SuspendThread( uint64_t threadHandle )
{
return !thread_suspend( thread_act_t(threadHandle) );
}
bool ResumeThread( uint64_t threadHandle )
{
return !thread_resume( thread_act_t(threadHandle) );
}
uint64_t GetCurrentThreadId()
{
return mach_thread_self();
}
bool GetThreadBacktraceContext( uint64_t iID, BacktraceContext *ctx )
{
/* Can't GetThreadBacktraceContext the current thread. */
ASSERT( iID != GetCurrentThreadId() );
SuspendThread( iID );
thread_act_t thread = thread_act_t( iID );
#if defined(__ppc__)
ppc_thread_state state;
mach_msg_type_number_t count = PPC_THREAD_STATE_COUNT;
if( thread_get_state(thread, PPC_THREAD_STATE, thread_state_t(&state), &count) )
return false;
ctx->FramePtr = (const Frame *)state.r1;
ctx->PC = (void *)state.srr0;
return true;
#elif defined(__i386__)
i386_thread_state state;
mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
if( thread_get_state(thread, i386_THREAD_STATE, thread_state_t(&state), &count) )
return false;
ctx->ip = (void *)state.eip;
ctx->bp = (void *)state.ebp;
ctx->sp = (void *)state.esp;
return true;
#else
return false;
#endif
}
RString SetThreadPrecedence( float prec )
{
// Real values are between 0 and 63.
DEBUG_ASSERT( 0.0f <= prec && prec <= 1.0f );
thread_precedence_policy po = { integer_t( lrintf(prec * 63) ) };
kern_return_t ret = thread_policy_set( mach_thread_self(), THREAD_PRECEDENCE_POLICY,
(thread_policy_t)&po, THREAD_PRECEDENCE_POLICY_COUNT );
if( ret != KERN_SUCCESS )
return mach_error_string( ret );
return RString();
}
/*
* (c) 2004-2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
@@ -0,0 +1,35 @@
#ifndef DARWIN_THREAD_HELPERS_H
#define DARWIN_THREAD_HELPERS_H
bool SuspendThread( uint64_t threadHandle );
bool ResumeThread( uint64_t threadHandle );
uint64_t GetCurrentThreadId();
// Valid values are from 0.0f to 1.0f. 0.5f is default.
RString SetThreadPrecedence( float prec );
#endif
/*
* (c) 2004-2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+279
View File
@@ -0,0 +1,279 @@
#include "global.h"
#include "HIDDevice.h"
#include "RageUtil.h"
HIDDevice::HIDDevice() : m_Interface( NULL ), m_Queue( NULL ), m_bRunning( false )
{
}
HIDDevice::~HIDDevice()
{
if( m_Queue )
{
CFRunLoopSourceRef runLoopSource;
if( m_bRunning )
{
CALL( m_Queue, stop );
runLoopSource = CALL( m_Queue, getAsyncEventSource );
CFRunLoopSourceInvalidate( runLoopSource );
CFRelease( runLoopSource );
}
CALL( m_Queue, dispose );
CALL( m_Queue, Release );
}
if( m_Interface )
{
CALL( m_Interface, close );
CALL( m_Interface, Release );
}
}
bool HIDDevice::Open( io_object_t device )
{
IOReturn ret;
CFMutableDictionaryRef properties;
kern_return_t result;
CFTypeRef object;
result = IORegistryEntryCreateCFProperties( device, &properties, kCFAllocatorDefault, kNilOptions );
if( result != KERN_SUCCESS || !properties )
{
LOG->Warn( "Couldn't get properties." );
return false;
}
object = CFDictionaryGetValue( properties, CFSTR(kIOHIDProductKey) );
CFTypeRef vidRef = CFDictionaryGetValue( properties, CFSTR(kIOHIDVendorIDKey) );
CFTypeRef pidRef = CFDictionaryGetValue( properties, CFSTR(kIOHIDProductIDKey) );
int vid, pid;
if( !IntValue(vidRef, vid) )
vid = 0;
if( !IntValue(pidRef, pid) )
pid = 0;
if( !InitDevice(vid, pid) )
{
LOG->Warn( "Couldn't initialize device." );
CFRelease( properties );
return false;
}
if( object && CFGetTypeID(object) == CFStringGetTypeID() )
{
const char *str = CFStringGetCStringPtr( CFStringRef(object), CFStringGetSystemEncoding() );
m_sDescription = str? str:"";
}
if( m_sDescription == "" )
m_sDescription = ssprintf( "%04x:%04x", vid, pid );
LOG->Trace( "\t\tDevice description: %s", m_sDescription.c_str() );
object = CFDictionaryGetValue( properties, CFSTR(kIOHIDElementKey) );
if ( !object || CFGetTypeID(object) != CFArrayGetTypeID() )
{
LOG->Warn( "Couldn't get HID elements." );
CFRelease( properties );
return false;
}
CFArrayRef logicalDevices = CFArrayRef( object );
CFRange r = { 0, CFArrayGetCount(logicalDevices) };
CFArrayApplyFunction( logicalDevices, r, HIDDevice::AddLogicalDevice, this );
CFRelease( properties );
// Create the interface
IOCFPlugInInterface **plugInInterface;
HRESULT hresult;
SInt32 score;
ret = IOCreatePlugInInterfaceForService( device, kIOHIDDeviceUserClientTypeID,
kIOCFPlugInInterfaceID, &plugInInterface, &score );
if( ret != kIOReturnSuccess )
{
PrintIOErr( ret, "Failed to create plugin interface." );
return false;
}
// Call a method of the plugin to create the device interface
CFUUIDBytes bytes = CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID );
hresult = CALL( plugInInterface, QueryInterface, bytes, (void **)&m_Interface );
CALL( plugInInterface, Release );
if( hresult != S_OK )
{
LOG->Warn( "Couldn't get device interface from plugin interface." );
m_Interface = NULL;
return false;
}
// open the interface
if( (ret = CALL(m_Interface, open, 0)) != kIOReturnSuccess )
{
PrintIOErr( ret, "Failed to open the interface." );
CALL( m_Interface, Release );
m_Interface = NULL;
return false;
}
// alloc/create queue
m_Queue = CALL( m_Interface, allocQueue );
if( !m_Queue )
{
LOG->Warn( "Couldn't allocate a queue." );
return false;
}
if( (ret = CALL(m_Queue, create, 0, 32)) != kIOReturnSuccess )
{
PrintIOErr( ret, "Failed to create the queue." );
CALL( m_Queue, Release );
m_Queue = NULL;
CALL( m_Interface, Release );
m_Interface = NULL;
return false;
}
Open();
LOG->Trace( "\t\tDevice open" );
return true;
}
void HIDDevice::StartQueue( CFRunLoopRef loopRef, IOHIDCallbackFunction callback, void *target, int refCon )
{
CFRunLoopSourceRef runLoopSource;
// This creates a run loop source. It is released in the dtor.
IOReturn ret = CALL( m_Queue, createAsyncEventSource, &runLoopSource );
if( ret != kIOReturnSuccess )
{
PrintIOErr( ret, "Failed to create async event source." );
return;
}
if( !CFRunLoopContainsSource(loopRef, runLoopSource, kCFRunLoopDefaultMode) )
CFRunLoopAddSource( loopRef, runLoopSource, kCFRunLoopDefaultMode );
ret = CALL( m_Queue, setEventCallout, callback, target, (void *)refCon );
if( ret != kIOReturnSuccess )
{
PrintIOErr( ret, "Failed to set the call back." );
return;
}
// start the queue
ret = CALL( m_Queue, start );
if( ret != kIOReturnSuccess )
{
CFRunLoopSourceInvalidate( runLoopSource );
CFRelease( runLoopSource );
PrintIOErr( ret, "Failed to start the queue." );
return;
}
m_bRunning = true;
}
void HIDDevice::AddLogicalDevice( const void *value, void *context )
{
if( CFGetTypeID(CFTypeRef(value)) != CFDictionaryGetTypeID() )
return;
CFDictionaryRef properties = CFDictionaryRef( value );
HIDDevice *This = (HIDDevice *)context;
CFTypeRef object;
int usage, usagePage;
// Get usage page
object = CFDictionaryGetValue( properties, CFSTR(kIOHIDElementUsagePageKey) );
if( !IntValue(object, usagePage) )
return;
// Get usage
object = CFDictionaryGetValue( properties, CFSTR(kIOHIDElementUsageKey) );
if( !IntValue(object, usage) )
return;
object = CFDictionaryGetValue( properties, CFSTR(kIOHIDElementKey) );
if( !object || CFGetTypeID(object) != CFArrayGetTypeID() )
return;
if( !This->AddLogicalDevice(usagePage, usage) )
return;
CFArrayRef elements = CFArrayRef( object );
CFRange r = { 0, CFArrayGetCount(elements) };
CFArrayApplyFunction( elements, r, HIDDevice::AddElement, This );
}
void HIDDevice::AddElement( const void *value, void *context )
{
if( CFGetTypeID(CFTypeRef(value)) != CFDictionaryGetTypeID() )
return;
CFDictionaryRef properties = CFDictionaryRef( value );
HIDDevice *This = (HIDDevice *)context;
CFTypeRef object;
int usage, usagePage;
long cookie;
// Recursively add elements
object = CFDictionaryGetValue( properties, CFSTR(kIOHIDElementKey) );
if( object && CFGetTypeID(object) == CFArrayGetTypeID() )
{
CFArrayRef elements = CFArrayRef( object );
CFRange r = { 0, CFArrayGetCount(elements) };
CFArrayApplyFunction( elements, r, AddElement, context );
}
// Get usage page
object = CFDictionaryGetValue( properties, CFSTR(kIOHIDElementUsagePageKey) );
if( !IntValue(object, usagePage) )
return;
// Get usage
object = CFDictionaryGetValue( properties, CFSTR(kIOHIDElementUsageKey) );
if( !IntValue(object, usage) )
return;
// Get cookie
object = CFDictionaryGetValue( properties, CFSTR(kIOHIDElementCookieKey) );
if( !LongValue(object, cookie) )
return;
This->AddElement( usagePage, usage, IOHIDElementCookie(cookie), properties );
}
/*
* (c) 2005-2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+169
View File
@@ -0,0 +1,169 @@
#ifndef HIDDEVICE_H
#define HIDDEVICE_H
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/hid/IOHIDUsageTables.h>
#include <IOKit/usb/USB.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <vector>
#include <utility>
#include <ext/hash_map>
#include "RageLog.h"
#include "RageInputDevice.h"
/* A few helper functions. */
// The result needs to be released.
inline CFNumberRef CFInt( int n )
{
return CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &n );
}
inline void PrintIOErr( IOReturn err, const char *s )
{
LOG->Warn( "%s - %s(%x,%d)", s, mach_error_string(err), err, err & 0xFFFFFF );
}
inline Boolean IntValue( CFTypeRef o, int &n )
{
if( !o || CFGetTypeID(o) != CFNumberGetTypeID() )
return false;
return CFNumberGetValue( CFNumberRef(o), kCFNumberIntType, &n );
}
inline Boolean LongValue( CFTypeRef o, long &n )
{
if( !o || CFGetTypeID(o) != CFNumberGetTypeID() )
return false;
return CFNumberGetValue( CFNumberRef(o), kCFNumberLongType, &n );
}
namespace __gnu_cxx
{
template<>
struct hash<IOHIDElementCookie> : private hash<uintptr_t>
{
size_t operator()( const IOHIDElementCookie& cookie ) const
{
return hash<unsigned long>::operator()( uintptr_t(cookie) );
}
};
}
/*
* This is just awful, these aren't objects, treating them as such leads
* to: (*object)->function(object [, argument]...)
* Instead, do: CALL(object, function [, argument]...)
*/
#define CALL(o,f,...) (*(o))->f((o), ## __VA_ARGS__)
class HIDDevice
{
private:
IOHIDDeviceInterface **m_Interface;
IOHIDQueueInterface **m_Queue;
bool m_bRunning;
RString m_sDescription;
static void AddLogicalDevice( const void *value, void *context );
static void AddElement( const void *value, void *context );
protected:
/*
* Each physical device has zero or more logical devices. If this device allows
* a logical device of type (usagePage, usage), then allocate storage as necessary
* and return true, otherwise, return false.
*/
virtual bool AddLogicalDevice( int usagePage, int usage ) = 0;
/*
* If the most recently added logical device cares about the state of an element of type
* (usagePage, usage), store the cookie.
*/
virtual void AddElement( int usagePage, int usage, IOHIDElementCookie cookie, const CFDictionaryRef properties ) = 0;
/*
* Add any elements to the queue by calling AddElementToQueue() with the stored cookies.
*/
virtual void Open() = 0;
/*
* Optional. Subclasses can initialize the device, if required.
*/
virtual bool InitDevice( int vid, int pid ) { return true; }
// This adds the element with the given cookie to the queue to be notified of state changes.
inline void AddElementToQueue( IOHIDElementCookie cookie )
{
IOReturn ret = CALL( m_Queue, addElement, cookie, 0 );
if( ret != KERN_SUCCESS )
LOG->Warn( "Failed to add HID element with cookie %p to queue: %u", cookie, ret );
}
// Perform a synchronous set report on the HID interface.
inline IOReturn SetReport( IOHIDReportType type, UInt32 reportID, void *buffer, UInt32 size, UInt32 timeoutMS )
{
return CALL( m_Interface, setReport, type, reportID, buffer, size, timeoutMS, NULL, NULL, NULL );
}
public:
HIDDevice();
virtual ~HIDDevice();
bool Open( io_object_t device );
void StartQueue( CFRunLoopRef loopRef, IOHIDCallbackFunction callback, void *target, int refCon );
inline const RString& GetDescription() const { return m_sDescription; }
/*
* Add button presses (or releases) to vPresses for the given cookie. More than one DeviceInput
* can be added at a time. For example, Two axes presses may be generated by a single element.
* The value of the element is passed to determine if this is a push or a release. The time
* is provided as an optimization.
*/
virtual void GetButtonPresses( vector<DeviceInput>& vPresses, IOHIDElementCookie cookie, int value, const RageTimer& now ) const = 0;
/*
* Returns the number of IDs assigned starting from startID. This is not meaningful for devices like
* keyboards that all share the same InputDevice id. If a particular device has multiple logical
* devices, then it must ensure that AssignIDs does not assign an ID outside of its range. Return
* -1 to indicate that the device does not share the same InputDevice and none could be assigned.
*/
virtual int AssignIDs( InputDevice startID ) { return 0; }
/*
* Add a device and a description for each logical device.
*/
virtual void GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevices ) const = 0;
};
#endif
/*
* (c) 2005-2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+297
View File
@@ -0,0 +1,297 @@
#include "global.h"
#include "JoystickDevice.h"
#include "RageLog.h"
#include "Foreach.h"
using __gnu_cxx::hash_map;
Joystick::Joystick() : id( InputDevice_Invalid ),
x_axis( 0 ), x_min( 0 ), x_max( 0 ),
y_axis( 0 ), y_min( 0 ), y_max( 0 ),
z_axis( 0 ), z_min( 0 ), z_max( 0 ),
x_rot( 0 ), rx_min( 0 ), rx_max( 0 ),
y_rot( 0 ), ry_min( 0 ), ry_max( 0 ),
z_rot( 0 ), rz_min( 0 ), rz_max( 0 ),
hat( 0 ), hat_min( 0 ), hat_max( 0 )
{
}
bool JoystickDevice::AddLogicalDevice( int usagePage, int usage )
{
if( usagePage != kHIDPage_GenericDesktop )
return false;
switch( usage )
{
case kHIDUsage_GD_Joystick:
case kHIDUsage_GD_GamePad:
break;
default:
return false;
}
m_vSticks.push_back( Joystick() );
return true;
}
void JoystickDevice::AddElement( int usagePage, int usage, IOHIDElementCookie cookie, const CFDictionaryRef properties )
{
if( usagePage >= kHIDPage_VendorDefinedStart )
return;
ASSERT( m_vSticks.size() );
Joystick& js = m_vSticks.back();
switch( usagePage )
{
case kHIDPage_GenericDesktop:
{
int iMin = 0;
int iMax = 0;
IntValue( CFDictionaryGetValue(properties, CFSTR(kIOHIDElementMinKey)), iMin );
IntValue( CFDictionaryGetValue(properties, CFSTR(kIOHIDElementMaxKey)), iMax );
switch( usage )
{
case kHIDUsage_GD_X:
js.x_axis = cookie;
js.x_min = iMin;
js.x_max = iMax;
break;
case kHIDUsage_GD_Y:
js.y_axis = cookie;
js.y_min = iMin;
js.y_max = iMax;
break;
case kHIDUsage_GD_Z:
js.z_axis = cookie;
js.z_min = iMin;
js.z_max = iMax;
break;
case kHIDUsage_GD_Rx:
js.x_rot = cookie;
js.rx_min = iMin;
js.rx_max = iMax;
break;
case kHIDUsage_GD_Ry:
js.y_rot = cookie;
js.ry_min = iMin;
js.ry_max = iMax;
break;
case kHIDUsage_GD_Rz:
js.z_rot = cookie;
js.rz_min = iMin;
js.rz_max = iMax;
break;
case kHIDUsage_GD_DPadUp:
js.mapping[cookie] = JOY_UP;
break;
case kHIDUsage_GD_DPadDown:
js.mapping[cookie] = JOY_DOWN;
break;
case kHIDUsage_GD_DPadRight:
js.mapping[cookie] = JOY_RIGHT;
break;
case kHIDUsage_GD_DPadLeft:
js.mapping[cookie] = JOY_LEFT;
break;
case kHIDUsage_GD_Hatswitch:
{
if( iMax - iMin != 7 && iMax - iMin != 3 )
break;
js.hat = cookie;
js.hat_min = iMin;
js.hat_max = iMax;
break;
}
default:
//LOG->Warn( "Unknown usagePage usage pair: (kHIDPage_GenericDesktop, %d).", usage );
break;
}
break;
}
case kHIDPage_Button:
{
const DeviceButton buttonID = enum_add2( JOY_BUTTON_1, usage - kHIDUsage_Button_1 );
if( buttonID <= JOY_BUTTON_32 )
js.mapping[cookie] = buttonID;
else
LOG->Warn( "Button id too large: %d.", int(buttonID) );
break;
}
default:
//LOG->Warn( "Unknown usagePage usage pair: (%d, %d).", usagePage, usage );
break;
} // end switch (usagePage)
}
void JoystickDevice::Open()
{
// Add elements to the queue for each Joystick
FOREACH_CONST( Joystick, m_vSticks, i )
{
const Joystick& js = *i;
#define ADD(x) if( js.x ) AddElementToQueue( js.x )
ADD( x_axis ); ADD( y_axis ); ADD( z_axis );
ADD( x_rot ); ADD( y_rot ); ADD( z_rot );
ADD( hat );
#undef ADD
for( hash_map<IOHIDElementCookie,DeviceButton>::const_iterator j = js.mapping.begin(); j != js.mapping.end(); ++j )
AddElementToQueue( j->first );
}
}
bool JoystickDevice::InitDevice( int vid, int pid )
{
if( vid != 0x0507 || pid != 0x0011 )
return true;
// It's a Para controller so try to power it on.
uint8_t powerOn = 1;
IOReturn ret = SetReport( kIOHIDReportTypeFeature, 0, &powerOn, 1, 10 );
if( ret )
LOG->Warn( "Failed to power on the Para controller: %#08x", ret );
return ret == kIOReturnSuccess;
}
void JoystickDevice::GetButtonPresses( vector<DeviceInput>& vPresses, IOHIDElementCookie cookie, int value, const RageTimer& now ) const
{
FOREACH_CONST( Joystick, m_vSticks, i )
{
const Joystick& js = *i;
if( js.x_axis == cookie )
{
float level = SCALE( value, js.x_min, js.x_max, -1.0f, 1.0f );
vPresses.push_back( DeviceInput(js.id, JOY_LEFT, max(-level, 0.0f), now) );
vPresses.push_back( DeviceInput(js.id, JOY_RIGHT, max(level, 0.0f), now) );
break;
}
else if( js.y_axis == cookie )
{
float level = SCALE( value, js.y_min, js.y_max, -1.0f, 1.0f );
vPresses.push_back( DeviceInput(js.id, JOY_UP, max(-level, 0.0f), now) );
vPresses.push_back( DeviceInput(js.id, JOY_DOWN, max(level, 0.0f), now) );
break;
}
else if( js.z_axis == cookie )
{
float level = SCALE( value, js.z_min, js.z_max, -1.0f, 1.0f );
vPresses.push_back( DeviceInput(js.id, JOY_Z_UP, max(-level, 0.0f), now) );
vPresses.push_back( DeviceInput(js.id, JOY_Z_DOWN, max(level, 0.0f), now) );
break;
}
else if( js.x_rot == cookie )
{
float level = SCALE( value, js.rx_min, js.rx_max, -1.0f, 1.0f );
vPresses.push_back( DeviceInput(js.id, JOY_ROT_LEFT, max(-level, 0.0f), now) );
vPresses.push_back( DeviceInput(js.id, JOY_ROT_RIGHT, max(level, 0.0f), now) );
break;
}
else if( js.y_rot == cookie )
{
float level = SCALE( value, js.ry_min, js.ry_max, -1.0f, 1.0f );
vPresses.push_back( DeviceInput(js.id, JOY_ROT_UP, max(-level, 0.0f), now) );
vPresses.push_back( DeviceInput(js.id, JOY_ROT_DOWN, max(level, 0.0f), now) );
break;
}
else if( js.z_rot == cookie )
{
float level = SCALE( value, js.rz_min, js.rz_max, -1.0f, 1.0f );
vPresses.push_back( DeviceInput(js.id, JOY_ROT_Z_UP, max(-level, 0.0f), now) );
vPresses.push_back( DeviceInput(js.id, JOY_ROT_Z_DOWN, max(level, 0.0f), now) );
break;
}
else if( js.hat == cookie )
{
float levelUp = 0.f, levelRight = 0.f, levelDown = 0.f, levelLeft = 0.f;
value -= js.hat_min; // Probably just subtracting 0.
if( js.hat_max - js.hat_min == 3 )
value *= 2;
switch( value )
{
case 0: levelUp = 1.f; break; // U
case 1: levelUp = 1.f; levelRight = 1.f; break; // UR
case 2: levelRight = 1.f; break; // R
case 3: levelDown = 1.f; levelRight = 1.f; break; // DR
case 4: levelDown = 1.f; break; // D
case 5: levelDown = 1.f; levelLeft = 1.f; break; // DL
case 6: levelLeft = 1.f; break; // L
case 7: levelUp = 1.f; levelLeft = 1.f; break; // UL
}
vPresses.push_back( DeviceInput(js.id, JOY_HAT_UP, levelUp, now) );
vPresses.push_back( DeviceInput(js.id, JOY_HAT_RIGHT, levelRight, now) );
vPresses.push_back( DeviceInput(js.id, JOY_HAT_DOWN, levelDown, now) );
vPresses.push_back( DeviceInput(js.id, JOY_HAT_LEFT, levelLeft, now) );
break;
}
else
{
// hash_map<T,U>::operator[] is not const
hash_map<IOHIDElementCookie, DeviceButton>::const_iterator iter;
iter = js.mapping.find( cookie );
if( iter != js.mapping.end() )
{
vPresses.push_back( DeviceInput(js.id, iter->second, value, now) );
break;
}
}
}
}
int JoystickDevice::AssignIDs( InputDevice startID )
{
if( !IsJoystick(startID) )
return -1;
FOREACH( Joystick, m_vSticks, i )
{
if( !IsJoystick(startID) )
{
m_vSticks.erase( i, m_vSticks.end() );
break;
}
i->id = startID;
enum_add( startID, 1 );
}
return m_vSticks.size();
}
void JoystickDevice::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevices ) const
{
FOREACH_CONST( Joystick, m_vSticks, i )
vDevices.push_back( InputDeviceInfo(i->id,GetDescription()) );
}
/*
* (c) 2005-2007 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+66
View File
@@ -0,0 +1,66 @@
#ifndef JOYSTICK_DEVICE_H
#define JOYSTICK_DEVICE_H
#include "HIDDevice.h"
struct Joystick
{
InputDevice id;
// map cookie to button
__gnu_cxx::hash_map<IOHIDElementCookie, DeviceButton> mapping;
IOHIDElementCookie x_axis, y_axis, z_axis, x_rot, y_rot, z_rot, hat;
int x_min, x_max;
int y_min, y_max;
int z_min, z_max;
int rx_min, rx_max;
int ry_min, ry_max;
int rz_min, rz_max;
int hat_min, hat_max;
Joystick();
};
class JoystickDevice : public HIDDevice
{
private:
vector<Joystick> m_vSticks;
protected:
bool AddLogicalDevice( int usagePage, int usage );
void AddElement( int usagePage, int usage, IOHIDElementCookie cookie, const CFDictionaryRef properties );
void Open();
bool InitDevice( int vid, int pid );
public:
void GetButtonPresses( vector<DeviceInput>& vPresses, IOHIDElementCookie cookie, int value, const RageTimer& now ) const;
int AssignIDs( InputDevice startID );
void GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevices ) const;
};
#endif
/*
* (c) 2005-2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+514
View File
@@ -0,0 +1,514 @@
#include "global.h"
#include "KeyboardDevice.h"
using namespace __gnu_cxx;
bool KeyboardDevice::AddLogicalDevice( int usagePage, int usage )
{
return usagePage == kHIDPage_GenericDesktop && usage == kHIDUsage_GD_Keyboard;
}
static bool UsbKeyToDeviceButton( UInt8 iUsbKey, DeviceButton &buttonOut )
{
UInt8 usage = iUsbKey;
if( usage < kHIDUsage_KeyboardA )
return false;
if( usage <= kHIDUsage_KeyboardZ )
{
buttonOut = enum_add2( KEY_Ca, usage - kHIDUsage_KeyboardA );
return true;
}
// KEY_C0 = KEY_C1 - 1, kHIDUsage_Keyboard0 = kHIDUsage_Keyboard9 + 1
if( usage <= kHIDUsage_Keyboard9 )
{
buttonOut = enum_add2( KEY_C1, usage - kHIDUsage_Keyboard1 );
return true;
}
if( usage >= kHIDUsage_KeyboardF1 && usage <= kHIDUsage_KeyboardF12 )
{
buttonOut = enum_add2( KEY_F1, usage - kHIDUsage_KeyboardF1 );
return true;
}
if( usage >= kHIDUsage_KeyboardF13 && usage <= kHIDUsage_KeyboardF16 )
{
buttonOut = enum_add2( KEY_F13, usage - kHIDUsage_KeyboardF13 );
return true;
}
// keypad 0 is again backward
if( usage >= kHIDUsage_Keypad1 && usage <= kHIDUsage_Keypad9 )
{
buttonOut = enum_add2( KEY_KP_C1, usage - kHIDUsage_Keypad1 );
return true;
}
#define OTHER(n) (enum_add2(KEY_OTHER_0, (n)))
// [0, 8]
if( usage >= kHIDUsage_KeyboardF17 && usage <= kHIDUsage_KeyboardExecute )
{
buttonOut = OTHER( 0 + usage - kHIDUsage_KeyboardF17 );
return true;
}
// [9, 19]
if( usage >= kHIDUsage_KeyboardSelect && usage <= kHIDUsage_KeyboardVolumeDown )
{
buttonOut = OTHER( 9 + usage - kHIDUsage_KeyboardSelect );
return true;
}
// [20, 41]
if( usage >= kHIDUsage_KeypadEqualSignAS400 && usage <= kHIDUsage_KeyboardCancel )
{
buttonOut = OTHER( 20 + usage - kHIDUsage_KeypadEqualSignAS400 );
return true;
}
// [42, 47]
// XXX kHIDUsage_KeyboardClearOrAgain
if( usage >= kHIDUsage_KeyboardSeparator && usage <= kHIDUsage_KeyboardExSel )
{
buttonOut = OTHER( 32 + usage - kHIDUsage_KeyboardSeparator );
return true;
}
#define X(x,y) case x: buttonOut = y; return true
// Time for the special cases
switch( usage )
{
X( kHIDUsage_Keyboard0, KEY_C0 );
X( kHIDUsage_Keypad0, KEY_KP_C0 );
X( kHIDUsage_KeyboardReturnOrEnter, KEY_ENTER );
X( kHIDUsage_KeyboardEscape, KEY_ESC );
X( kHIDUsage_KeyboardDeleteOrBackspace, KEY_BACK );
X( kHIDUsage_KeyboardTab, KEY_TAB );
X( kHIDUsage_KeyboardSpacebar, KEY_SPACE );
X( kHIDUsage_KeyboardHyphen, KEY_HYPHEN );
X( kHIDUsage_KeyboardEqualSign, KEY_EQUAL );
X( kHIDUsage_KeyboardOpenBracket, KEY_LBRACKET );
X( kHIDUsage_KeyboardCloseBracket, KEY_RBRACKET );
X( kHIDUsage_KeyboardBackslash, KEY_BACKSLASH );
X( kHIDUsage_KeyboardNonUSPound, KEY_HASH );
X( kHIDUsage_KeyboardSemicolon, KEY_SEMICOLON );
X( kHIDUsage_KeyboardQuote, KEY_SQUOTE );
X( kHIDUsage_KeyboardGraveAccentAndTilde, KEY_ACCENT );
X( kHIDUsage_KeyboardComma, KEY_COMMA );
X( kHIDUsage_KeyboardPeriod, KEY_PERIOD );
X( kHIDUsage_KeyboardSlash, KEY_SLASH );
X( kHIDUsage_KeyboardCapsLock, KEY_CAPSLOCK );
X( kHIDUsage_KeyboardPrintScreen, KEY_PRTSC );
X( kHIDUsage_KeyboardScrollLock, KEY_SCRLLOCK );
X( kHIDUsage_KeyboardPause, KEY_PAUSE );
X( kHIDUsage_KeyboardInsert, KEY_INSERT );
X( kHIDUsage_KeyboardHome, KEY_HOME );
X( kHIDUsage_KeyboardPageUp, KEY_PGUP );
X( kHIDUsage_KeyboardDeleteForward, KEY_DEL );
X( kHIDUsage_KeyboardEnd, KEY_END );
X( kHIDUsage_KeyboardPageDown, KEY_PGDN );
X( kHIDUsage_KeyboardRightArrow, KEY_RIGHT );
X( kHIDUsage_KeyboardLeftArrow, KEY_LEFT );
X( kHIDUsage_KeyboardDownArrow, KEY_DOWN );
X( kHIDUsage_KeyboardUpArrow, KEY_UP );
X( kHIDUsage_KeypadNumLock, KEY_NUMLOCK );
X( kHIDUsage_KeypadSlash, KEY_KP_SLASH );
X( kHIDUsage_KeypadEqualSign, KEY_KP_EQUAL );
X( kHIDUsage_KeypadAsterisk, KEY_KP_ASTERISK );
X( kHIDUsage_KeypadHyphen, KEY_KP_HYPHEN );
X( kHIDUsage_KeypadPlus, KEY_KP_PLUS );
X( kHIDUsage_KeypadEnter, KEY_KP_ENTER );
X( kHIDUsage_KeypadPeriod, KEY_KP_PERIOD );
X( kHIDUsage_KeyboardNonUSBackslash, OTHER(48) );
X( kHIDUsage_KeyboardApplication, OTHER(49) );
X( kHIDUsage_KeyboardClear, KEY_NUMLOCK ); // XXX
X( kHIDUsage_KeyboardHelp, KEY_INSERT );
X( kHIDUsage_KeyboardMenu, KEY_MENU );
// XXX kHIDUsage_KeyboardLockingCapsLock
// XXX kHIDUsage_KeyboardLockingNumLock
// XXX kHIDUsage_KeyboardLockingScrollLock
X( kHIDUsage_KeypadComma, KEY_KP_PERIOD ); // XXX
X( kHIDUsage_KeyboardReturn, KEY_ENTER );
X( kHIDUsage_KeyboardPrior, OTHER(50) );
X( kHIDUsage_KeyboardLeftControl, KEY_LCTRL );
X( kHIDUsage_KeyboardLeftShift, KEY_LSHIFT );
X( kHIDUsage_KeyboardLeftAlt, KEY_LALT );
X( kHIDUsage_KeyboardLeftGUI, KEY_LMETA );
X( kHIDUsage_KeyboardRightControl, KEY_RCTRL );
X( kHIDUsage_KeyboardRightShift, KEY_RSHIFT );
X( kHIDUsage_KeyboardRightAlt, KEY_RALT );
X( kHIDUsage_KeyboardRightGUI, KEY_RMETA );
}
#undef X
#undef OTHER
return false;
}
void KeyboardDevice::AddElement( int usagePage, int usage, IOHIDElementCookie cookie, const CFDictionaryRef properties )
{
if( usagePage != kHIDPage_KeyboardOrKeypad )
return;
DeviceButton button;
if( UsbKeyToDeviceButton(usage,button) )
m_Mapping[cookie] = button;
}
void KeyboardDevice::Open()
{
for( hash_map<IOHIDElementCookie,DeviceButton>::const_iterator i = m_Mapping.begin(); i != m_Mapping.end(); ++i )
{
//LOG->Trace( "Adding %s to queue, cookie %p", DeviceButtonToString(i->second).c_str(), i->first );
AddElementToQueue( i->first );
}
}
void KeyboardDevice::GetButtonPresses( vector<DeviceInput>& vPresses, IOHIDElementCookie cookie, int value, const RageTimer& now ) const
{
hash_map<IOHIDElementCookie, DeviceButton>::const_iterator iter = m_Mapping.find( cookie );
if( iter != m_Mapping.end() )
{
//LOG->Trace( "Pushed %s", DeviceButtonToString(iter->second).c_str() );
vPresses.push_back( DeviceInput(DEVICE_KEYBOARD, iter->second, value, now) );
}
}
void KeyboardDevice::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevices ) const
{
if( vDevices.size() && vDevices[0].id == DEVICE_KEYBOARD )
return;
vDevices.insert( vDevices.begin(), InputDeviceInfo(DEVICE_KEYBOARD, "Keyboard") );
}
// http://lists.apple.com/archives/carbon-dev/2005/Feb/msg00071.html
// index represents USB keyboard usage value, content is Mac virtual keycode
static UInt8 g_iUsbKeyToMacVirtualKey[256] =
{
0xFF, /* 00 no event */
0xFF, /* 01 ErrorRollOver */
0xFF, /* 02 POSTFail */
0xFF, /* 03 ErrorUndefined */
0x00, /* 04 A */
0x0B, /* 05 B */
0x08, /* 06 C */
0x02, /* 07 D */
0x0E, /* 08 E */
0x03, /* 09 F */
0x05, /* 0A G */
0x04, /* 0B H */
0x22, /* 0C I */
0x26, /* 0D J */
0x28, /* 0E K */
0x25, /* 0F L */
0x2E, /* 10 M */
0x2D, /* 11 N */
0x1F, /* 12 O */
0x23, /* 13 P */
0x0C, /* 14 Q */
0x0F, /* 15 R */
0x01, /* 16 S */
0x11, /* 17 T */
0x20, /* 18 U */
0x09, /* 19 V */
0x0D, /* 1A W */
0x07, /* 1B X */
0x10, /* 1C Y */
0x06, /* 1D Z */
0x12, /* 1E 1/! */
0x13, /* 1F 2/@ */
0x14, /* 20 3 # */
0x15, /* 21 4 $ */
0x17, /* 22 5 % */
0x16, /* 23 6 ^ */
0x1A, /* 24 7 & */
0x1C, /* 25 8 * */
0x19, /* 26 9 ( */
0x1D, /* 27 0 ) */
0x24, /* 28 Return (Enter) */
0x35, /* 29 ESC */
0x33, /* 2A Delete (Backspace) */
0x30, /* 2B Tab */
0x31, /* 2C Spacebar */
0x1B, /* 2D - _ */
0x18, /* 2E = + */
0x21, /* 2F [ { */
0x1E, /* 30 ] } */
0x2A, /* 31 \ | */
0xFF, /* 32 Non-US # and ~ (what?!!!) */
0x29, /* 33 ; : */
0x27, /* 34 ' " */
0x32, /* 35 ` ~ */
0x2B, /* 36 , < */
0x2F, /* 37 . > */
0x2C, /* 38 / ? */
0x39, /* 39 Caps Lock */
0x7A, /* 3A F1 */
0x78, /* 3B F2 */
0x63, /* 3C F3 */
0x76, /* 3D F4 */
0x60, /* 3E F5 */
0x61, /* 3F F6 */
0x62, /* 40 F7 */
0x64, /* 41 F8 */
0x65, /* 42 F9 */
0x6D, /* 43 F10 */
0x67, /* 44 F11 */
0x6F, /* 45 F12 */
0x69, /* 46 F13/PrintScreen */
0x6B, /* 47 F14/ScrollLock */
0x71, /* 48 F15/Pause */
0x72, /* 49 Insert */
0x73, /* 4A Home */
0x74, /* 4B PageUp */
0x75, /* 4C Delete Forward */
0x77, /* 4D End */
0x79, /* 4E PageDown */
0x7C, /* 4F RightArrow */
0x7B, /* 50 LeftArrow */
0x7D, /* 51 DownArrow */
0x7E, /* 52 UpArrow */
0x47, /* 53 NumLock/Clear */
0x4B, /* 54 Keypad / */
0x43, /* 55 Keypad * */
0x4E, /* 56 Keypad - */
0x45, /* 57 Keypad + */
0x4C, /* 58 Keypad Enter */
0x53, /* 59 Keypad 1 */
0x54, /* 5A Keypad 2 */
0x55, /* 5B Keypad 3 */
0x56, /* 5C Keypad 4 */
0x57, /* 5D Keypad 5 */
0x58, /* 5E Keypad 6 */
0x59, /* 5F Keypad 7 */
0x5B, /* 60 Keypad 8 */
0x5C, /* 61 Keypad 9 */
0x52, /* 62 Keypad 0 */
0x41, /* 63 Keypad . */
0xFF, /* 64 Non-US \ and | (what ??!!) */
0x6E, /* 65 ApplicationKey (not on a mac!)*/
0x7F, /* 66 PowerKey */
0x51, /* 67 Keypad = */
0x69, /* 68 F13 */
0x6B, /* 69 F14 */
0x71, /* 6A F15 */
0xFF, /* 6B F16 */
0xFF, /* 6C F17 */
0xFF, /* 6D F18 */
0xFF, /* 6E F19 */
0xFF, /* 6F F20 */
0x5B, /* 70 F21 */
0x5C, /* 71 F22 */
0x52, /* 72 F23 */
0x41, /* 73 F24 */
0xFF, /* 74 Execute */
0xFF, /* 75 Help */
0x7F, /* 76 Menu */
0x4C, /* 77 Select */
0x69, /* 78 Stop */
0x6B, /* 79 Again */
0x71, /* 7A Undo */
0xFF, /* 7B Cut */
0xFF, /* 7C Copy */
0xFF, /* 7D Paste */
0xFF, /* 7E Find */
0xFF, /* 7F Mute */
0xFF, /* 80 no event */
0xFF, /* 81 no event */
0xFF, /* 82 no event */
0xFF, /* 83 no event */
0xFF, /* 84 no event */
0xFF, /* 85 no event */
0xFF, /* 86 no event */
0xFF, /* 87 no event */
0xFF, /* 88 no event */
0xFF, /* 89 no event */
0xFF, /* 8A no event */
0xFF, /* 8B no event */
0xFF, /* 8C no event */
0xFF, /* 8D no event */
0xFF, /* 8E no event */
0xFF, /* 8F no event */
0xFF, /* 90 no event */
0xFF, /* 91 no event */
0xFF, /* 92 no event */
0xFF, /* 93 no event */
0xFF, /* 94 no event */
0xFF, /* 95 no event */
0xFF, /* 96 no event */
0xFF, /* 97 no event */
0xFF, /* 98 no event */
0xFF, /* 99 no event */
0xFF, /* 9A no event */
0xFF, /* 9B no event */
0xFF, /* 9C no event */
0xFF, /* 9D no event */
0xFF, /* 9E no event */
0xFF, /* 9F no event */
0xFF, /* A0 no event */
0xFF, /* A1 no event */
0xFF, /* A2 no event */
0xFF, /* A3 no event */
0xFF, /* A4 no event */
0xFF, /* A5 no event */
0xFF, /* A6 no event */
0xFF, /* A7 no event */
0xFF, /* A8 no event */
0xFF, /* A9 no event */
0xFF, /* AA no event */
0xFF, /* AB no event */
0xFF, /* AC no event */
0xFF, /* AD no event */
0xFF, /* AE no event */
0xFF, /* AF no event */
0xFF, /* B0 no event */
0xFF, /* B1 no event */
0xFF, /* B2 no event */
0xFF, /* B3 no event */
0xFF, /* B4 no event */
0xFF, /* B5 no event */
0xFF, /* B6 no event */
0xFF, /* B7 no event */
0xFF, /* B8 no event */
0xFF, /* B9 no event */
0xFF, /* BA no event */
0xFF, /* BB no event */
0xFF, /* BC no event */
0xFF, /* BD no event */
0xFF, /* BE no event */
0xFF, /* BF no event */
0xFF, /* C0 no event */
0xFF, /* C1 no event */
0xFF, /* C2 no event */
0xFF, /* C3 no event */
0xFF, /* C4 no event */
0xFF, /* C5 no event */
0xFF, /* C6 no event */
0xFF, /* C7 no event */
0xFF, /* C8 no event */
0xFF, /* C9 no event */
0xFF, /* CA no event */
0xFF, /* CB no event */
0xFF, /* CC no event */
0xFF, /* CD no event */
0xFF, /* CE no event */
0xFF, /* CF no event */
0xFF, /* D0 no event */
0xFF, /* D1 no event */
0xFF, /* D2 no event */
0xFF, /* D3 no event */
0xFF, /* D4 no event */
0xFF, /* D5 no event */
0xFF, /* D6 no event */
0xFF, /* D7 no event */
0xFF, /* D8 no event */
0xFF, /* D9 no event */
0xFF, /* DA no event */
0xFF, /* DB no event */
0xFF, /* DC no event */
0xFF, /* DD no event */
0xFF, /* DE no event */
0xFF, /* DF no event */
0x3B, /* E0 left control key */
0x38, /* E1 left shift key key */
0x3A, /* E2 left alt/option key */
0x37, /* E3 left GUI (windows/cmd) key */
0x3B, /* E4 right control key */
0x38, /* E5 right shift key key */
0x3A, /* E6 right alt/option key */
0x37, /* E7 right GUI (windows/cmd) key */
0xFF, /* E8 no event */
0xFF, /* E9 no event */
0xFF, /* EA no event */
0xFF, /* EB no event */
0xFF, /* EC no event */
0xFF, /* ED no event */
0xFF, /* EE no event */
0xFF, /* EF no event */
0xFF, /* F0 no event */
0xFF, /* F1 no event */
0xFF, /* F2 no event */
0xFF, /* F3 no event */
0xFF, /* F4 no event */
0xFF, /* F5 no event */
0xFF, /* F6 no event */
0xFF, /* F7 no event */
0xFF, /* F8 no event */
0xFF, /* F9 no event */
0xFF, /* FA no event */
0xFF, /* FB no event */
0xFF, /* FC no event */
0xFF, /* FD no event */
0xFF, /* FE no event */
0xFF, /* FF no event */
};
static UInt8 g_iDeviceButtonToMacVirtualKey[KEY_OTHER_0];
bool KeyboardDevice::DeviceButtonToMacVirtualKey( DeviceButton button, UInt8 &iMacVKOut )
{
static bool bInited = false;
if( !bInited )
{
memset( g_iDeviceButtonToMacVirtualKey, 0xFF, sizeof(g_iDeviceButtonToMacVirtualKey) );
for( int iUsbKey = 0; iUsbKey < 256; ++iUsbKey )
{
DeviceButton button2;
if( UsbKeyToDeviceButton(iUsbKey, button2) && size_t(button2) < sizeof(g_iDeviceButtonToMacVirtualKey) )
g_iDeviceButtonToMacVirtualKey[button2] = g_iUsbKeyToMacVirtualKey[iUsbKey];
}
bInited = true;
}
iMacVKOut = g_iDeviceButtonToMacVirtualKey[button];
return iMacVKOut != 0xFF;
}
/*
* (c) 2005-2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+49
View File
@@ -0,0 +1,49 @@
#ifndef KEYBOARD_DEVICE_H
#define KEYBOARD_DEVICE_H
#include "HIDDevice.h"
class KeyboardDevice : public HIDDevice
{
private:
__gnu_cxx::hash_map<IOHIDElementCookie, DeviceButton> m_Mapping;
protected:
bool AddLogicalDevice( int usagePage, int usage );
void AddElement( int usagePage, int usage, IOHIDElementCookie cookie, const CFDictionaryRef properties );
void Open();
public:
void GetButtonPresses( vector<DeviceInput>& vPresses, IOHIDElementCookie cookie, int value, const RageTimer& now ) const;
void GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevices ) const;
static bool DeviceButtonToMacVirtualKey( DeviceButton button, UInt8 &iMacVKOut );
};
#endif
/*
* (c) 2005-2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+37
View File
@@ -0,0 +1,37 @@
char *GetPreferredLanguage()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
NSArray *languages = [def objectForKey:@"AppleLanguages"];
const char *lang = [[languages objectAtIndex:0] UTF8String];
char *ret = (char *)malloc( strlen(lang) + 1 );
strcpy( ret, lang );
[pool release];
return ret;
}
/*
* (c) 2005 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+89
View File
@@ -0,0 +1,89 @@
#include "global.h"
#include "PumpDevice.h"
void PumpDevice::Open()
{
AddElementToQueue( IOHIDElementCookie(2) );
AddElementToQueue( IOHIDElementCookie(3) );
AddElementToQueue( IOHIDElementCookie(4) );
AddElementToQueue( IOHIDElementCookie(6) );
AddElementToQueue( IOHIDElementCookie(7) );
AddElementToQueue( IOHIDElementCookie(8) );
}
void PumpDevice::GetButtonPresses( vector<DeviceInput>& vPresses, IOHIDElementCookie cookie, int value, const RageTimer& now ) const
{
DeviceButton db1 = DeviceButton_Invalid;
DeviceButton db2 = DeviceButton_Invalid;
bool pressed1 = !(value & 0x1);
bool pressed2 = !(value & 0x2);
switch( uintptr_t(cookie) )
{
case 2:
db2 = JOY_BUTTON_1; // bit 9
break;
case 3:
db1 = JOY_BUTTON_5; // bit 10
db2 = JOY_BUTTON_4; // bit 11
break;
case 4:
db1 = JOY_BUTTON_2; // bit 12
db2 = JOY_BUTTON_3; // bit 13
break;
case 6:
db1 = JOY_BUTTON_6; // bit 16
db2 = JOY_BUTTON_7; // bit 17
break;
case 7:
db1 = JOY_BUTTON_11; // bit 18
db2 = JOY_BUTTON_10; // bit 19
break;
case 8:
db1 = JOY_BUTTON_8; // bit 20
db2 = JOY_BUTTON_9; // bit 21
break;
}
if( db1 != DeviceButton_Invalid )
vPresses.push_back( DeviceInput(m_Id, db1, pressed1 ? 1.0f : 0.0f , now) );
if( db2 != DeviceButton_Invalid )
vPresses.push_back( DeviceInput(m_Id, db2, pressed2 ? 1.0f : 0.0f , now) );
}
int PumpDevice::AssignIDs( InputDevice startID )
{
if( !IsPump(startID) )
return -1;
m_Id = startID;
return 1;
}
void PumpDevice::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevices ) const
{
vDevices.push_back( InputDeviceInfo(m_Id, "Pump USB") );
}
/*
* (c) 2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+49
View File
@@ -0,0 +1,49 @@
#ifndef PUMP_DEVICE_H
#define PUMP_DEVICE_H
#include "HIDDevice.h"
class PumpDevice : public HIDDevice
{
private:
InputDevice m_Id;
protected:
bool AddLogicalDevice( int usagePage, int usage ) { return true; }
void AddElement( int usagePage, int usage, IOHIDElementCookie cookie,
const CFDictionaryRef properties ) { }
void Open();
bool InitDevice( int vid, int pid ) { return vid == 0x0d2f && pid == 0x0001; }
public:
void GetButtonPresses( vector<DeviceInput>& vPresses, IOHIDElementCookie cookie, int value, const RageTimer& now ) const;
int AssignIDs( InputDevice startID );
void GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevices ) const;
};
#endif
/*
* (c) 2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+227
View File
@@ -0,0 +1,227 @@
#include "global.h"
#include "RageUtil.h"
#include "RageThreads.h"
#import <Cocoa/Cocoa.h>
#include "ProductInfo.h"
#include "arch/ArchHooks/ArchHooks.h"
@interface NSApplication (PrivateShutUpWarning)
- (void) setAppleMenu:(NSMenu *)menu;
@end
/* Replacement NSApplication class.
* Replaces sendEvent so that key down events are only sent to the
* menu bar. We handle all other input by reading HID events from the
* keyboard directly. */
@interface SMApplication : NSApplication
- (void) fullscreen:(id)sender;
@end
@implementation SMApplication
- (void)fullscreen:(id)sender
{
ArchHooks::SetToggleWindowed();
}
- (void)sendEvent:(NSEvent *)event
{
if( [event type] == NSKeyDown )
[[self mainMenu] performKeyEquivalent:event];
else
[super sendEvent:event];
}
@end
// The main class of the application, the application's delegate.
@interface SMMain : NSObject
{
int m_iArgc;
char **m_pArgv;
BOOL m_bApplicationLaunched;
}
- (id) initWithArgc:(int)argc argv:(char **)argv;
- (void) startGame:(id)sender;
- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication *)sender;
- (BOOL) application:(NSApplication *)app openFile:(NSString *)file;
- (void) application:(NSApplication *)app openFiles:(NSArray *)files;
- (void) setForInstall:(NSArray *)files;
@end
@implementation SMMain
- (id) initWithArgc:(int)argc argv:(char **)argv
{
[super init];
if( argc == 2 && !strncmp(argv[1], "-psn_", 5) )
argc = 1;
m_iArgc = argc;
m_pArgv = new char*[argc];
for( int i = 0; i < argc; ++i )
m_pArgv[i] = argv[i];
m_bApplicationLaunched = NO;
return self;
}
- (void) startGame:(id)sender
{
// Hand off to main application code.
exit( SM_main(m_iArgc, m_pArgv) );
}
// Called when the internal event loop has just started running.
- (void) applicationDidFinishLaunching:(NSNotification *)note
{
m_bApplicationLaunched = YES;
[NSThread detachNewThreadSelector:@selector(startGame:) toTarget:self withObject:nil];
}
- (BOOL) application:(NSApplication *)app openFile:(NSString *)file
{
NSArray *files = [NSArray arrayWithObject:file];
if( m_bApplicationLaunched )
[NSTask launchedTaskWithLaunchPath:[NSString stringWithUTF8String:m_pArgv[0]] arguments:files];
else
[self setForInstall:files];
return YES;
}
- (void) application:(NSApplication *)app openFiles:(NSArray *)files
{
if( m_bApplicationLaunched )
[NSTask launchedTaskWithLaunchPath:[NSString stringWithUTF8String:m_pArgv[0]] arguments:files];
else
[self setForInstall:files];
[app replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
}
- (void) setForInstall:(NSArray *)files
{
char **temp = new char*[[files count] + m_iArgc];
for( int i = 0; i < m_iArgc; ++i )
temp[i] = m_pArgv[i];
for( unsigned i = 0; i < [files count]; ++i, ++m_iArgc )
{
const char *p = [[files objectAtIndex:i] fileSystemRepresentation];
temp[m_iArgc] = new char[strlen(p)+1];
strcpy( temp[m_iArgc], p );
}
delete[] m_pArgv;
m_pArgv = temp;
}
- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication *)sender
{
ArchHooks::SetUserQuit();
return NSTerminateCancel;
}
@end
static void HandleNSException( NSException *exception )
{
FAIL_M( ssprintf("%s raised: %s", [[exception name] UTF8String], [[exception reason] UTF8String]) );
}
static NSMenuItem *MenuItem( NSString *title, SEL action, NSString *code )
{
// Autorelease these because they'll be retained by the NSMenu.
return [[[NSMenuItem alloc] initWithTitle:title action:action keyEquivalent:code] autorelease];
}
static void SetupMenus( void )
{
// Get the localized strings from the file.
NSString *sWindow = NSLocalizedString( @"Window", @"Menu title" );
NSString *sHideOthers = NSLocalizedString( @"Hide Others", @"Menu item" );
NSString *sAbout = NSLocalizedString( @"About " PRODUCT_FAMILY, @"Menu item" );
NSString *sHide = NSLocalizedString( @"Hide " PRODUCT_FAMILY, @"Menu item" );
NSString *sShowAll = NSLocalizedString( @"Show All", @"Menu item" );
NSString *sQuit = NSLocalizedString( @"Quit " PRODUCT_FAMILY, @"Menu item" );
NSString *sMinimize = NSLocalizedString( @"Minimize", @"Menu item" );
NSString *sEnterFullScreen = NSLocalizedString( @"Enter Full Screen", @"Menu item" );
NSMenu *mainMenu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
NSMenu *appMenu = [[[NSMenu alloc] initWithTitle:@PRODUCT_FAMILY] autorelease];
NSMenu *windowMenu = [[[NSMenu alloc] initWithTitle:sWindow] autorelease];
NSMenuItem *hideOthers = MenuItem( sHideOthers, @selector(hideOtherApplications:), @"h" );
[hideOthers setKeyEquivalentModifierMask:NSAlternateKeyMask | NSCommandKeyMask ];
[appMenu addItem:MenuItem( sAbout, @selector(orderFrontStandardAboutPanel:), @"" )];
[appMenu addItem:[NSMenuItem separatorItem]];
[appMenu addItem:MenuItem( sHide, @selector(hide:), @"h" )];
[appMenu addItem:hideOthers];
[appMenu addItem:MenuItem( sShowAll, @selector(unhideAllApplications:), @"" )];
[appMenu addItem:[NSMenuItem separatorItem]];
[appMenu addItem:MenuItem( sQuit, @selector(terminate:), @"q" )];
[windowMenu addItem:MenuItem( sMinimize, @selector(performMiniaturize:), @"m" )];
[windowMenu addItem:[NSMenuItem separatorItem]];
// Add a Full Screen item.
NSMenuItem *item = MenuItem( sEnterFullScreen, @selector(fullscreen:), @"\n" );
[item setKeyEquivalentModifierMask:NSAlternateKeyMask]; // opt-enter
[windowMenu addItem:item];
[[mainMenu addItemWithTitle:[appMenu title] action:NULL keyEquivalent:@""] setSubmenu:appMenu];
[[mainMenu addItemWithTitle:[windowMenu title] action:NULL keyEquivalent:@""] setSubmenu:windowMenu];
[NSApp setMainMenu:mainMenu];
[NSApp setAppleMenu:appMenu]; // This isn't the apple menu, but it doesn't work without this.
[NSApp setWindowsMenu:windowMenu];
}
#undef main
int main( int argc, char **argv )
{
RageThreadRegister guiThread( "GUI thread" );
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
SMMain *sm;
// Ensure the application object is initialised, this sets NSApp.
[SMApplication sharedApplication];
// Set up NSException handler.
NSSetUncaughtExceptionHandler( HandleNSException );
// Set up the menubar.
SetupMenus();
// Create SMMain and make it the app delegate.
sm = [[SMMain alloc] initWithArgc:argc argv:argv];
[NSApp setDelegate:sm];
[pool release];
// Start the main event loop.
[NSApp run];
[sm release];
return 0;
}
/*
* (c) 2005-2009 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+10
View File
@@ -0,0 +1,10 @@
#define PBBUILD
// Only do this for c++ files.
#ifdef __cplusplus
# include "global.h"
#endif
#ifdef __OBJC__
# import <Cocoa/Cocoa.h>
#endif
+265
View File
@@ -0,0 +1,265 @@
#include "VectorHelper.h"
#include <sys/sysctl.h>
#if defined(USE_VEC)
#if defined(__VEC__)
#include <vecLib/vecLib.h>
bool Vector::CheckForVector()
{
int32_t result = 0;
size_t size = 4;
return !sysctlbyname( "hw.vectorunit", &result, &size, NULL, 0 ) && result;
}
/* for( unsigned pos = 0; pos < size; ++pos )
* dest[pos] += src[pos];
* Idea from: http://developer.apple.com/hardwaredrivers/ve/downloads/add.c */
void Vector::FastSoundWrite( float *dest, const float *src, unsigned size )
{
if( size > 4 )
{
int index = 0;
vUInt8 one = (vUInt8)(1);
vUInt8 srcMask = vec_add( vec_lvsl(15, src), one );
vUInt8 destMask = vec_add(vec_lvsl(15, dest), one );
vUInt8 storeMask = vec_lvsr( 0, dest );
vFloat load1Src = vec_ld( 0, src );
vFloat load1Dest = vec_ld( 0, dest );
vFloat store = (vFloat)(0.0f);
// If dest is misaligned, pull the first loop iteration out.
if( intptr_t(dest) & 0xF )
{
vFloat load2Src = vec_ld( 15, src );
vFloat load2Dest = vec_ld( 15, dest );
load1Src = vec_perm( load1Src, load2Src, srcMask );
load1Dest = vec_perm( load1Dest, load2Dest, destMask );
load1Dest = vec_add( load1Dest, load1Src );
store = vec_perm( load1Dest, load1Dest, storeMask );
while( (intptr_t(dest) + index) & 0xC )
{
vec_ste( store, index, dest );
index += 4;
}
load1Src = load2Src;
store = load1Dest;
load1Dest = load2Dest;
src += 4;
dest += 4;
size -= 4;
/* Incrementing the index is supposed to have the same effect
* as incrementing dest but since we read from dest as well
* we don't want to increment twice so decrement the index. */
// XXX: What in the world did I mean here?
index -= 16;
}
while( size >= 32 )
{
vFloat load2Src = vec_ld( 15, src );
vFloat load3Src = vec_ld( 31, src );
vFloat load4Src = vec_ld( 47, src );
vFloat load5Src = vec_ld( 63, src );
vFloat load6Src = vec_ld( 79, src );
vFloat load7Src = vec_ld( 95, src );
vFloat load8Src = vec_ld( 111, src );
vFloat load9Src = vec_ld( 127, src );
vFloat load2Dest = vec_ld( 15, dest );
vFloat load3Dest = vec_ld( 31, dest );
vFloat load4Dest = vec_ld( 47, dest );
vFloat load5Dest = vec_ld( 63, dest );
vFloat load6Dest = vec_ld( 79, dest );
vFloat load7Dest = vec_ld( 95, dest );
vFloat load8Dest = vec_ld( 111, dest );
vFloat load9Dest = vec_ld( 127, dest );
// Align the data.
load1Src = vec_perm( load1Src, load2Src, srcMask );
load2Src = vec_perm( load2Src, load3Src, srcMask );
load3Src = vec_perm( load3Src, load4Src, srcMask );
load4Src = vec_perm( load4Src, load5Src, srcMask );
load5Src = vec_perm( load5Src, load6Src, srcMask );
load6Src = vec_perm( load6Src, load7Src, srcMask );
load7Src = vec_perm( load7Src, load8Src, srcMask );
load8Src = vec_perm( load8Src, load9Src, srcMask );
// Not load5Src, it's untouched and used later.
load1Dest = vec_perm( load1Dest, load2Dest, destMask );
load2Dest = vec_perm( load2Dest, load3Dest, destMask );
load3Dest = vec_perm( load3Dest, load4Dest, destMask );
load4Dest = vec_perm( load4Dest, load5Dest, destMask );
load5Dest = vec_perm( load5Dest, load6Dest, destMask );
load6Dest = vec_perm( load6Dest, load7Dest, destMask );
load7Dest = vec_perm( load7Dest, load8Dest, destMask );
load8Dest = vec_perm( load8Dest, load9Dest, destMask );
// Not load9Dest.
load1Dest = vec_add( load1Dest, load1Src );
load2Dest = vec_add( load2Dest, load2Src );
load3Dest = vec_add( load3Dest, load3Src );
load4Dest = vec_add( load4Dest, load4Src );
load5Dest = vec_add( load5Dest, load5Src );
load6Dest = vec_add( load6Dest, load6Src );
load7Dest = vec_add( load7Dest, load7Src );
load8Dest = vec_add( load8Dest, load8Src );
// Unalign the results.
store = vec_perm( store, load1Dest, storeMask );
load1Dest = vec_perm( load1Dest, load2Dest, storeMask );
load2Dest = vec_perm( load2Dest, load3Dest, storeMask );
load3Dest = vec_perm( load3Dest, load4Dest, storeMask );
load4Dest = vec_perm( load4Dest, load5Dest, storeMask );
load5Dest = vec_perm( load5Dest, load6Dest, storeMask );
load6Dest = vec_perm( load6Dest, load7Dest, storeMask );
load7Dest = vec_perm( load7Dest, load8Dest, storeMask );
// store the results
vec_st( store, index + 0, dest );
vec_st( load1Dest, index + 16, dest );
vec_st( load2Dest, index + 32, dest );
vec_st( load3Dest, index + 48, dest );
vec_st( load4Dest, index + 64, dest );
vec_st( load5Dest, index + 80, dest );
vec_st( load6Dest, index + 96, dest );
vec_st( load7Dest, index + 112, dest );
load1Src = load9Src;
load1Dest = load9Dest;
store = load8Dest;
dest += 32;
src += 32;
size -= 32;
}
/* This completely baffles gcc's loop unrolling. If I make it > 3 instead,
* then gcc produces 4 identical copies of the loop without scheduling them
* in a sane manner (hence the manual unrolling above) but this loop will
* never be executed more than 3 times so that code will never be used.
* This produces code the way gcc _should_ do it by unrolling and scheduling
* and then producing the rolled version. */
while( size & ~0x3 )
{
vFloat load2Src = vec_ld( 15, src );
vFloat load2Dest = vec_ld( 15, dest );
load1Src = vec_perm( load1Src, load2Src, srcMask );
load1Dest = vec_perm( load1Dest, load2Dest, destMask );
load1Dest = vec_add( load1Dest, load1Src );
store = vec_perm( store, load1Dest, storeMask );
vec_st( store, index, dest );
load1Src = load2Src;
store = load1Dest;
load1Dest = load2Dest;
src += 4;
dest += 4;
size -= 4;
}
// Store the remainder of the vector, if it was misaligned.
if( index < 0 )
{
store = vec_perm( store, store, storeMask );
while( index < 0 )
{
vec_ste( store, index, dest );
index += 4;
}
}
}
/* If we account for both misaligned dest and src, there is really no way to
* do this in vector code so do the last at most 3 elements in scalar code. */
while( size-- )
*(dest++) += *(src++);
}
#elif defined(__SSE2__)
#include <xmmintrin.h>
// This is portable to other sysems since it uses Intel's intrinsics.
bool Vector::CheckForVector()
{
// MMX, SSE, and SSE2 must be present, we don't use SSE3 so no need to check for it.
return true;
}
void Vector::FastSoundWrite( float *dest, const float *src, unsigned size )
{
while( (intptr_t(dest) & 0xF) && size )
{
// Misaligned stores are slow.
*(dest++) += *(src++);
--size;
}
// Misaligned loads are slower so specialize to aligned loads when possible.
if( intptr_t(src) & 0xF )
{
while( size >= 8 )
{
__m128 data1 = _mm_loadu_ps( src + 0 );
__m128 data2 = _mm_loadu_ps( src + 4 );
data1 = _mm_add_ps( data1, *(__m128 *)(dest + 0) );
data2 = _mm_add_ps( data2, *(__m128 *)(dest + 4) );
_mm_store_ps( dest + 0, data1 );
_mm_store_ps( dest + 4, data2 );
src += 8;
dest += 8;
size -= 8;
}
}
else
{
while( size >= 8 )
{
__m128 data1 = _mm_load_ps( src + 0 );
__m128 data2 = _mm_load_ps( src + 4 );
data1 = _mm_add_ps( data1, *(__m128 *)(dest + 0) );
data2 = _mm_add_ps( data2, *(__m128 *)(dest + 4) );
_mm_store_ps( dest + 0, data1 );
_mm_store_ps( dest + 4, data2 );
src += 8;
dest += 8;
size -= 8;
}
}
while( size-- )
*(dest++) += *(src++);
}
#else
#error huh?
#endif
#endif
/*
* (c) 2006-2007 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+38
View File
@@ -0,0 +1,38 @@
#ifndef VECTOR_HELPER_H
#define VECTOR_HELPER_H
#if ( defined(__VEC__) || (defined(__SSE__) && defined(__SSE2__)) ) && defined(__GNUC__)
namespace Vector
{
bool CheckForVector();
void FastSoundWrite( float *dest, const float *src, unsigned size );
}
#define USE_VEC
#endif
#endif
/*
* (c) 2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+90
View File
@@ -0,0 +1,90 @@
#ifndef ARCH_SETUP_DARWIN_H
#define ARCH_SETUP_DARWIN_H
// Replace the main function.
extern "C" int SM_main( int argc, char *argv[] );
#define main(x,y) SM_main(x,y)
#define HAVE_VERSION_INFO
#define HAVE_CXA_DEMANGLE
#define HAVE_THEORA
#define HAVE_FFMPEG
#define HAVE_PTHREAD_COND_TIMEDWAIT
/* This must be defined to 1 because autoconf's AC_CHECK_DECLS macro decides to define
* this in all cases. If only they could be consistent... */
#define HAVE_DECL_SIGUSR1 1
/* We have <machine/endian.h> which gets pulled in when we use gcc 4.0's <cstdlib>
* but no <endian.h>. The definitions of LITTLE_ENDIAN, BIG_ENDIAN and end up conflicting
* even though they resolve to the same thing (bug in gcc?). */
#define HAVE_MACHINE_ENDIAN_H
#define HAVE_INTTYPES_H
#define __STDC_FORMAT_MACROS
#define CRASH_HANDLER
#define GL_GET_ERROR_IS_SLOW
// CGFlushDrawable() performs a glFlush() and the docs say not to call glFlush()
#define NO_GL_FLUSH
#if defined(__ppc__)
# define CPU_PPC
# define ENDIAN_BIG
# define BACKTRACE_LOOKUP_METHOD_DARWIN_DYLD
# define BACKTRACE_METHOD_POWERPC_DARWIN
#elif defined(__i386__)
# define CPU_X86
# define ENDIAN_LITTLE
# define BACKTRACE_METHOD_X86_DARWIN
# define BACKTRACE_LOOKUP_METHOD_DLADDR
#endif
#ifndef MACOSX
# define MACOSX
#endif
#ifndef __MACOSX__
# define __MACOSX__
#endif
#include <libkern/OSByteOrder.h>
#define ArchSwap32(n) OSSwapInt32((n))
#define ArchSwap24(n) (ArchSwap32((n)) >> 8)
#define ArchSwap16(n) OSSwapInt16((n))
#define HAVE_BYTE_SWAPS
// Define the work around if needed.
#include <bits/c++config.h>
#include <stdint.h>
#if _GLIBCXX_USE_C99
# define NEED_CSTDLIB_WORKAROUND
#else
inline int64_t llabs( int64_t x ) { return x < 0LL ? -x : x; }
#endif
#define attribute_deprecated // Shut ffmpeg up!
#endif
/*
* (c) 2003-2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/