00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "inputthread.h"
00020
00021 #include "inputthreadprivate.h"
00022 #include "inputbuffer.h"
00023
00024 #include <QtCore/QCoreApplication>
00025 #include <QtCore/QDebug>
00026 #include <IOKit/hid/IOHIDUsageTables.h>
00027
00028 using namespace GluonInput;
00029
00030 InputThread::InputThread( IOHIDDeviceRef pDevice, QObject* parent )
00031 : QThread( parent )
00032 , d( new InputThreadPrivate() )
00033 {
00034 d->device = pDevice;
00035 IOHIDDeviceOpen( d->device, kIOHIDOptionsTypeNone );
00036
00037 IOHIDDeviceScheduleWithRunLoop( d->device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode );
00038
00039 d->error = false;
00040 d->msgError.clear();
00041 d->deviceName = "Unknown";
00042
00043 readInformation();
00044 }
00045
00046 InputThread::~InputThread()
00047 {
00048 IOHIDDeviceUnscheduleFromRunLoop( d->device, CFRunLoopGetMain(), kCFRunLoopDefaultMode );
00049
00050 IOHIDDeviceClose( d->device, kIOHIDOptionsTypeNone );
00051 CFRelease( d->device );
00052 }
00053
00054 void InputThread::readInformation()
00055 {
00056 CFStringRef deviceNameRef = ( CFStringRef )IOHIDDeviceGetProperty( d->device, CFSTR( kIOHIDProductKey ) );
00057 if( CFGetTypeID( deviceNameRef ) == CFStringGetTypeID() )
00058 {
00059 d->deviceName = CFStringGetCStringPtr( deviceNameRef, kCFStringEncodingMacRoman );
00060 }
00061
00062 CFTypeRef type = IOHIDDeviceGetProperty( d->device, CFSTR( kIOHIDVendorIDKey ) );
00063 if( type )
00064 {
00065 CFNumberGetValue(( CFNumberRef ) type, kCFNumberSInt32Type, &d->vendor );
00066 CFRelease( type );
00067 }
00068 else
00069 {
00070 d->vendor = -1;
00071 }
00072
00073 type = IOHIDDeviceGetProperty( d->device, CFSTR( kIOHIDProductIDKey ) );
00074 if( type )
00075 {
00076 CFNumberGetValue(( CFNumberRef ) type, kCFNumberSInt32Type, &d->product );
00077 CFRelease( type );
00078 }
00079 else
00080 {
00081 d->product = -1;
00082 }
00083
00084 type = IOHIDDeviceGetProperty( d->device, CFSTR( kIOHIDTransportKey ) );
00085 if( type )
00086 {
00087 if( CFGetTypeID( type ) == CFNumberGetTypeID() )
00088 {
00089 CFNumberGetValue(( CFNumberRef ) type, kCFNumberSInt32Type, &d->bustype );
00090 CFRelease( type );
00091 }
00092 else if( CFGetTypeID( type ) == CFStringGetTypeID() )
00093 {
00094 d->bustype = -1;
00095 }
00096 else
00097 {
00098 d->bustype = -1;
00099 }
00100
00101 }
00102
00103 type = IOHIDDeviceGetProperty( d->device, CFSTR( kIOHIDVersionNumberKey ) );
00104 if( type )
00105 {
00106 CFNumberGetValue(( CFNumberRef ) type, kCFNumberSInt32Type, &d->version );
00107 CFRelease( type );
00108 }
00109 else
00110 {
00111 d->version = -1;
00112 }
00113
00114 d->buttonCapabilities.clear();
00115 d->absAxisCapabilities.clear();
00116 d->relAxisCapabilities.clear();
00117 d->absAxisInfos.clear();
00118
00119 CFArrayRef elements = IOHIDDeviceCopyMatchingElements( d->device, 0, kIOHIDOptionsTypeNone );
00120
00121 if( elements )
00122 {
00123 for( int i = 0; i < CFArrayGetCount( elements ); ++i )
00124 {
00125 IOHIDElementRef elementRef = ( IOHIDElementRef )CFArrayGetValueAtIndex( elements, ( CFIndex )i );
00126 if( CFGetTypeID( elementRef ) == IOHIDElementGetTypeID() )
00127 {
00128 int usagePage = IOHIDElementGetUsagePage( elementRef );
00129 int usage = IOHIDElementGetUsage( elementRef );
00130
00131 if( usagePage == kHIDPage_Button )
00132 {
00133 d->buttonCapabilities.append( usage );
00134 }
00135 else if( usagePage == kHIDPage_KeyboardOrKeypad )
00136 {
00137 if( usage > 3 && usage <= 231 && !d->buttonCapabilities.contains( usage ) )
00138 d->buttonCapabilities.append( usage );
00139 }
00140 else if( usagePage == kHIDPage_GenericDesktop )
00141 {
00142 if( usage <= 47 || usage == 60 )
00143 continue;
00144
00145 if( IOHIDElementIsRelative( elementRef ) )
00146 {
00147 d->relAxisCapabilities.append( usage );
00148 }
00149 else
00150 {
00151 d->absAxisCapabilities.append( usage );
00152 AbsVal val( 0, 0, 0, 0 );
00153 val.max = ( int )IOHIDElementGetLogicalMax( elementRef );
00154 val.min = ( int )IOHIDElementGetLogicalMin( elementRef );
00155 IOHIDValueRef valRef = NULL;
00156 IOHIDDeviceGetValue( d->device, elementRef, &valRef );
00157 val.value = IOHIDValueGetIntegerValue( valRef );
00158 d->absAxisInfos[usage] = val;
00159 if( usage == kHIDUsage_GD_X )
00160 {
00161 d->xAbsUsage = usage;
00162 }
00163 else if( usage == kHIDUsage_GD_Y )
00164 {
00165 d->yAbsUsage = usage;
00166 }
00167 else if( usage == kHIDUsage_GD_Z )
00168 {
00169 d->zAbsUsage = usage;
00170 }
00171 }
00172 }
00173 }
00174 }
00175 }
00176
00177 CFRelease( elements );
00178
00179 int deviceUsage = 0;
00180
00181 type = IOHIDDeviceGetProperty( d->device, CFSTR( kIOHIDPrimaryUsageKey ) );
00182
00183 if( type )
00184 {
00185 CFNumberGetValue(( CFNumberRef ) type, kCFNumberSInt32Type, &deviceUsage );
00186 CFRelease( type );
00187 }
00188 else
00189 {
00190 type = IOHIDDeviceGetProperty( d->device, CFSTR( kIOHIDDeviceUsageKey ) );
00191 CFNumberGetValue(( CFNumberRef ) type, kCFNumberSInt32Type, &deviceUsage );
00192 CFRelease( type );
00193 }
00194
00195 switch( deviceUsage )
00196 {
00197 case GluonInput::KeyboardDevice:
00198 d->deviceType = GluonInput::KeyboardDevice;
00199 break;
00200 case GluonInput::MouseDevice:
00201 d->deviceType = GluonInput::MouseDevice;
00202 break;
00203 case GluonInput::JoystickDevice:
00204 d->deviceType = GluonInput::JoystickDevice;
00205 break;
00206 case GluonInput::TouchDevice:
00207 d->deviceType = GluonInput::TouchDevice;
00208 break;
00209 default:
00210 d->deviceType = GluonInput::UnknownDevice;
00211 break;
00212 }
00213 }
00214
00215 void InputThread::deviceReport( void* inContext, IOReturn inResult, void* inSender, IOHIDValueRef inIOHIDValueRef )
00216 {
00217 IOHIDDeviceRef deviceRef = ( IOHIDDeviceRef ) inSender;
00218 InputThread* currentThread = ( InputThread* ) inContext;
00219 if( inResult == kIOReturnSuccess && CFGetTypeID( deviceRef ) == IOHIDDeviceGetTypeID() )
00220 {
00221 IOHIDElementRef elementRef = IOHIDValueGetElement( inIOHIDValueRef );
00222
00223 int usagePage = IOHIDElementGetUsagePage( elementRef );
00224 int usage = IOHIDElementGetUsage( elementRef );
00225 int value = IOHIDValueGetIntegerValue( inIOHIDValueRef );
00226
00227 if( usagePage == kHIDPage_GenericDesktop || usagePage == kHIDPage_KeyboardOrKeypad || usagePage == kHIDPage_Button )
00228 {
00229 if( usagePage == kHIDPage_GenericDesktop && usage == 60 )
00230 return;
00231 else if( usagePage == kHIDPage_KeyboardOrKeypad && ( usage <= 3 || usage > 231 ) )
00232 return;
00233
00234 switch( currentThread->deviceType() )
00235 {
00236 case GluonInput::MouseDevice:
00237 if( usagePage == kHIDPage_GenericDesktop )
00238 {
00239 if( value == 0 )
00240 return;
00241 emit currentThread->relAxisMoved( usage, value );
00242 }
00243 break;
00244 case GluonInput::JoystickDevice:
00245 if( usagePage == kHIDPage_GenericDesktop )
00246 {
00247 if( value == 0 )
00248 return;
00249
00250 currentThread->absAxisMoved( usage, value );
00251 }
00252 break;
00253 default:
00254 currentThread->buttonStateChanged( usage, value );
00255 break;
00256 }
00257 }
00258 }
00259 }
00260
00261 int InputThread::joystickXAxis()
00262 {
00263 return d->xAbsUsage;
00264 }
00265
00266 int InputThread::joystickYAxis()
00267 {
00268 return d->yAbsUsage;
00269 }
00270
00271 int InputThread::joystickZAxis()
00272 {
00273 return d->zAbsUsage;
00274 }
00275
00276 void InputThread::run()
00277 {
00278 IOHIDDeviceRegisterInputValueCallback( d->device, deviceReport, this );
00279 exec();
00280 }
00281
00282 void InputThread::stop()
00283 {
00284 IOHIDDeviceRegisterInputValueCallback( d->device, 0, this );
00285 quit();
00286 }
00287
00288 int InputThread::vendor() const
00289 {
00290 return d->vendor;
00291 }
00292
00293 int InputThread::product() const
00294 {
00295 return d->product;
00296 }
00297
00298 int InputThread::version() const
00299 {
00300 return d->version;
00301 }
00302
00303 int InputThread::bustype() const
00304 {
00305 return d->bustype;
00306 }
00307
00308 QList<int> InputThread::buttonCapabilities() const
00309 {
00310 return d->buttonCapabilities;
00311 }
00312
00313 QList<int> InputThread::absAxisCapabilities() const
00314 {
00315 return d->absAxisCapabilities;
00316 }
00317
00318 QList<int> InputThread::relAxisCapabilities() const
00319 {
00320 return d->relAxisCapabilities;
00321 }
00322
00323 AbsVal InputThread::axisInfo( int axisCode ) const
00324 {
00325 return d->absAxisInfos[axisCode];
00326 }
00327
00328 const QString InputThread::deviceName() const
00329 {
00330 return d->deviceName;
00331 }
00332
00333 GluonInput::DeviceFlag InputThread::deviceType() const
00334 {
00335 return d->deviceType;
00336 }
00337
00338 bool InputThread::isEnabled() const
00339 {
00340 return this->isRunning();
00341 }
00342
00343 bool InputThread::error()
00344 {
00345 return d->error;
00346 }
00347
00348 QString InputThread::msgError()
00349 {
00350 return d->msgError;
00351 }
00352
00353 #include "inputthread.moc"