Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
HID Support/HIDSupport.c
/* |
* HIDSupport.c |
* Carbon OpenGL |
* |
* Created by Geoff Stahl on Sat May 03 2003. |
* Copyright (c) 2003 Apple. All rights reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under Apple’s |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* |
*/ |
#include <IOKit/hid/IOHIDLib.h> |
#include <IOKit/hid/IOHIDUsageTables.h> |
#include "HIDSupport.h" |
#include "trackball.h" |
#include "main.h" |
EventLoopTimerRef gHIDTimer = NULL; // input timer |
static actionRec gActionArray [kNumActions]; // array of action records for mapping and values |
// --------------------------------- |
// internal routines |
static void GetInput (void); |
pascal void HIDTimer (EventLoopTimerRef inTimer, void* userData); |
EventLoopTimerUPP GetHIDTimerUPP (void); |
static void InitHIDInputArray (void); |
static Boolean GetInputElements (pRecDevice pDevice); |
static Boolean SetupHIDInputs (void); |
// --------------------------------- |
// polls for input for all actions based on current mapping |
static void GetInput (void) |
{ |
short a; |
for (a = 0; a < kNumActions; a++) { |
if (gActionArray [a].pDevice && gActionArray [a].pElement) { |
gActionArray [a].value = HIDGetElementValue (gActionArray [a].pDevice, gActionArray [a].pElement); |
// gActionArray [a].value = HIDCalibrateValue (gActionArray [a].value, gActionArray [a].pElement); |
gActionArray [a].value = HIDScaleValue (gActionArray [a].value, gActionArray [a].pElement); |
} |
else |
gActionArray [a].value = 0; |
} |
} |
// --------------------------------- |
// get input and update window for each timer beat |
pascal void HIDTimer (EventLoopTimerRef inTimer, void* userData) |
{ |
#pragma unused (inTimer) |
static AbsoluteTime time = {0, 0}; |
long deadZone = 15; |
pRecContext pContextInfo = NULL; |
float rotation[4] = {0.0f, 0.0f, 0.0f, 0.0f}; |
AbsoluteTime currTime = UpTime (); |
float deltaTime = (float) AbsoluteDeltaToDuration (currTime, time); |
time = currTime; // reset for next time interval |
if (0 > deltaTime) // if negative microseconds |
deltaTime /= -1000000.0; |
else // else milliseconds |
deltaTime /= 1000.0; |
if (deltaTime > 10.0) // skip pauses |
return; |
// get input values |
GetInput (); |
// apply to front window |
pContextInfo = GetCurrentContextInfo (FrontWindow ()); // call back to main to get the current context info record |
if (!pContextInfo) |
return; // not an application window so do not process |
// apply input |
if (gActionArray [kActionXAxis].pDevice && gActionArray [kActionXAxis].pElement && (abs (gActionArray [kActionXAxis].value) > deadZone)) { |
// pan |
GLfloat panX = abs (gActionArray [kActionXAxis].value) * gActionArray [kActionXAxis].value * deltaTime * 0.002f / (1500.0f / -pContextInfo->camera.viewPos.z); |
pContextInfo->camera.viewPos.x += panX; |
} |
if (gActionArray [kActionYAxis].pDevice && gActionArray [kActionYAxis].pElement && (abs (gActionArray [kActionYAxis].value) > deadZone)) { |
// pan |
GLfloat panY = abs (gActionArray [kActionYAxis].value) * gActionArray [kActionYAxis].value * deltaTime * 0.002f / (1500.0f / -pContextInfo->camera.viewPos.z); |
pContextInfo->camera.viewPos.y -= panY; |
} |
if (gActionArray [kActionZAxis].pDevice && gActionArray [kActionZAxis].pElement && (abs (gActionArray [kActionZAxis].value) > deadZone)) { |
// dolly |
GLfloat dolly = abs (gActionArray [kActionZAxis].value) * gActionArray [kActionZAxis].value * deltaTime * 0.002f * -pContextInfo->camera.viewPos.z / 500.0f; |
pContextInfo->camera.viewPos.z += dolly; |
if (pContextInfo->camera.viewPos.z == 0.0) // do not let z = 0.0 |
pContextInfo->camera.viewPos.z = 0.0001; |
} |
// handle rotations about each respective axis |
if (gActionArray [kActionXRot].pDevice && gActionArray [kActionXRot].pElement && (abs (gActionArray [kActionXRot].value) > deadZone)) { |
rotation[0] = abs (gActionArray [kActionXRot].value) * -gActionArray [kActionXRot].value * deltaTime * 0.0003f; |
rotation[1] = 1.0f; |
rotation[2] = 0.0f; |
rotation[3] = 0.0f; |
addToRotationTrackball (rotation, pContextInfo->worldRotation); |
} |
if (gActionArray [kActionYRot].pDevice && gActionArray [kActionYRot].pElement && (abs (gActionArray [kActionYRot].value) > deadZone)) { |
rotation[0] = abs (gActionArray [kActionYRot].value) * gActionArray [kActionYRot].value * deltaTime * 0.0003f; |
rotation[1] = 0.0f; |
rotation[2] = 1.0f; |
rotation[3] = 0.0f; |
addToRotationTrackball (rotation, pContextInfo->worldRotation); |
} |
if (gActionArray [kActionZRot].pDevice && gActionArray [kActionZRot].pElement && (abs (gActionArray [kActionZRot].value) > deadZone)) { |
rotation[0] = abs (gActionArray [kActionZRot].value) * -gActionArray [kActionZRot].value * deltaTime * 0.0003f; |
rotation[1] = 0.0f; |
rotation[2] = 0.0f; |
rotation[3] = 1.0f; |
addToRotationTrackball (rotation, pContextInfo->worldRotation); |
} |
// need to force draw here... |
{ |
Rect rectPort; |
WindowRef window = FrontWindow (); |
GetWindowPortBounds (window, &rectPort); |
InvalWindowRect (window, &rectPort); |
} |
} |
// --------------------------------- |
// make timer UPP |
EventLoopTimerUPP GetHIDTimerUPP (void) |
{ |
static EventLoopTimerUPP sTimerUPP = NULL; |
if (sTimerUPP == NULL) |
sTimerUPP = NewEventLoopTimerUPP (HIDTimer); |
return sTimerUPP; |
} |
// --------------------------------- |
static void InitHIDInputArray (void) |
{ |
long i; |
for (i = 0; i < kNumActions; i++) { |
gActionArray [i].pElement = NULL; |
gActionArray [i].pDevice = NULL; |
gActionArray [i].value = 0; |
} |
} |
// --------------------------------- |
static Boolean GetInputElements (pRecDevice pDevice) |
{ |
short i; |
pRecElement pElement = NULL; |
if (pDevice) { // if we have found a device set up elements |
// prefer correct elements, then try any |
// look for x axis |
pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); // get first element |
while (pElement) { // for each element |
if ((kHIDPage_GenericDesktop == pElement->usagePage) && (kHIDUsage_GD_X == pElement->usage)) { // if it is the x axis |
gActionArray [kActionXAxis].pDevice = pDevice; |
gActionArray [kActionXAxis].pElement = pElement; |
break; |
} |
pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); // get next element |
} |
// look for y axis |
pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); // get first element |
while (pElement) { // for each element |
if ((kHIDPage_GenericDesktop == pElement->usagePage) && (kHIDUsage_GD_Y == pElement->usage)) { // if it is the y axis |
gActionArray [kActionYAxis].pDevice = pDevice; |
gActionArray [kActionYAxis].pElement = pElement; |
break; |
} |
pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); // get next element |
} |
// look for z axis |
pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); // get first element |
while (pElement) { // for each element |
if ((kHIDPage_GenericDesktop == pElement->usagePage) && (kHIDUsage_GD_Z == pElement->usage)) { // if it is the y axis |
gActionArray [kActionZAxis].pDevice = pDevice; |
gActionArray [kActionZAxis].pElement = pElement; |
break; |
} |
pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); // get next element |
} |
// look for x rotation |
pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); // get first element |
while (pElement) { // for each element |
if ((kHIDPage_GenericDesktop == pElement->usagePage) && (kHIDUsage_GD_Rx == pElement->usage)) { // if it is the x axis |
gActionArray [kActionXRot].pDevice = pDevice; |
gActionArray [kActionXRot].pElement = pElement; |
break; |
} |
pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); // get next element |
} |
// look for y rotation |
pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); // get first element |
while (pElement) { // for each element |
if ((kHIDPage_GenericDesktop == pElement->usagePage) && (kHIDUsage_GD_Ry == pElement->usage)) { // if it is the y axis |
gActionArray [kActionYRot].pDevice = pDevice; |
gActionArray [kActionYRot].pElement = pElement; |
break; |
} |
pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); // get next element |
} |
// look for z rotation |
pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); // get first element |
while (pElement) { // for each element |
if ((kHIDPage_GenericDesktop == pElement->usagePage) && (kHIDUsage_GD_Rz == pElement->usage)) { // if it is the y axis |
gActionArray [kActionZRot].pDevice = pDevice; |
gActionArray [kActionZRot].pElement = pElement; |
break; |
} |
pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); // get next element |
} |
} |
// set device limits |
for (i = 0; i < kNumActions; i++) |
{ |
if (!gActionArray [i].pElement) { // check to ensure we have valid elements |
InitHIDInputArray (); |
return false; |
} |
if (gActionArray [i].pElement) { |
(gActionArray [i].pElement)->userMin = -1000; |
(gActionArray [i].pElement)->userMax = 1000; |
} |
} |
return true; |
} |
// --------------------------------- |
static Boolean SetupHIDInputs (void) |
{ |
UInt32 aUsage = 0; |
UInt32 aUsagePage = 0; |
pRecDevice pDevice = NULL; |
InitHIDInputArray (); |
HIDUpdateDeviceList(&aUsagePage, &aUsage, 1); // will do the right thing the first time |
pDevice = HIDGetFirstDevice(); // get the first device |
while(pDevice) { |
// if the device has 6 axis try to use it |
if ((pDevice->axis >= 6) && (GetInputElements (pDevice))) // if we can find the axis needed use else continue |
break; |
pDevice = HIDGetNextDevice(pDevice); // check next device |
} |
if (pDevice) // means we found a valid device |
return true; |
else |
return false; |
} |
// --------------------------------- |
void EndHIDInput (void) |
{ |
// remove timer |
if (gHIDTimer) |
RemoveEventLoopTimer (gHIDTimer); |
gHIDTimer = NULL; |
// dump array |
InitHIDInputArray (); |
// dump devices |
if (HIDHaveDeviceList()) |
HIDReleaseDeviceList (); |
} |
// --------------------------------- |
void StartHIDInput (void) |
{ |
EndHIDInput (); // ensure we are overwriting an earlier set up |
// setup inputs |
if (SetupHIDInputs ()) |
InstallEventLoopTimer (GetCurrentEventLoop(), 0, 0.01, GetHIDTimerUPP (), NULL, &gHIDTimer); // start timer 100 hz |
else |
printf ("No 6 DOF device found.\n"); |
} |
Copyright © 2004 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2004-03-26