Using InputSprocket
This section illustrates basic ways of using InputSprocket. In particular, it provides source code samples that show how you can
- Initialize need structures and allocate virtual elements
- Build an element list
- Process input data during game play
- Deactivate keyboard and mouse devices
- Note
- The code samples shown in this section provide no error handling.
Initializing Need Structures and Allocating Virtual Elements
During initialization the game describes its requirements for input by filling out aISpNeed
data structure for each requirement (the structure is described on (page 3-29). The need structure has fields for an element kind and an element label, so the game can describe the data and its intended use. Other fields specify how to use the keyboard and mouse for keyboard emulation. The game also provides a string and an icon to identify the input requirement in a user interface.After filling out the need structures, the game allocates a virtual element to meet each input requirement. Allocation of virtual elements must happen before you call
ISpInit
because after that call the device driver may begin using the virtual elements.The
InitNeeds
routine shown in Listing 3-1 creates an array of initialized ISpNeed structures. It then uses theISpElement_NewVirtualFromNeeds
function (page 3-36) to allocate virtual elements. You can useISpElement_NewVirtualFromNeeds
only with built-in element kinds, which is the case in the example. Otherwise, you allocate virtual elements individually using theISpElement_NewVirtual
function (page 3-36).Listing 3-1 Initializing need structures and allocating virtual elements
OSStatus InitNeeds(ISpNeed *theNeeds,ISpElementReference *elements) { ISpNeed tempNeeds[kNumNeeds] = { { "\pForward Thrust", kIconSuiteID_YThrust, kISpElementKind_Axis, kISpElementLabel_YAxis, 0 }, { "\pSide Thrust", kISpElementKind_Axis, kISpElementLabel_XAxis, 0 }, { "\pVertical Thrust", kIconSuiteID_ZThrust, kISpElementKind_Axis, kISpElementLabel_ZAxis, 0 }, { "\pLook", kIconSuiteID_Look, kISpElementKind_Movement, kISpElementLabel_None, 0 }, { "\pLaser", kIconSuiteID_Fire, kISpElementKind_Button, kISpElementLabel_Fire, 0 }, { "\pMissle", kIconSuiteID_Pause, kISpElementKind_Button, kISpElementLabel_Fire, 0 }, { "\pShields", kIconSuiteID_Shields, kISpElementKind_Button, kISpElementLabel_None, 0 }, { "\pStart/Stop", kIconSuiteID_Start, kISpElementKind_Button, kISpElementLabel_Start, kISpNeedFlag_NoMultiConfig } }; int itr; for(itr = 0; itr < kNumNeeds; itr++) { theNeeds[itr] = tempNeeds[itr]; } OSStatus result = ISpElement_NewVirtualFromNeeds(kNumNeeds, theNeeds, elements, 0); return result; }Building an Element List
When configuration is finished and virtual elements are allocated, you probably want to build a list of elements the game wants to get events for during play. Listing 3-2 shows the BuildMyElementList routine, which puts all the button and directional pad elements on an element list. Games usually poll axis and movement elements, so they are not included on the list.
BuildMyElementList
also makes the reference constant returned byISpElementList_AddElements
for each element it adds equal to the index of the element in the array of need structures passed to the drivers during autoconfiguration. This is also the same as the index of the element in the list of virtual elements allocated during the autoconfiguration process (see Listing 3-1 for an example of creating virtual elements). The game uses the reference constant (which is passed in theISpElementEvent
structure) to identify the element when it gets element events usingISpElementList_GetNextEvent
.Listing 3-2 Building an element list
ISpElementListReference BuildMyElementList(UInt32 count, ISpNeed *needs, ISpElementReference *elements) { int itr; ISpElementListReference theList = nil; ISpElementList_New(0, nil, &theList, 0); for(itr = 0; itr < count; itr++) { if ((needs[itr].theKind == kISpElementKind_Button) || (needs[itr].theKind == kISpElementKind_DPad)) { ISpElementList_AddElements(theList, itr, 1, &(elements[itr])); } } return theList; }
BuildMyElementList
first defines an element list reference to the list that will be built. It next uses the ISpElementList_New function (page 3-51) to create an empty element list. Finally,BuildMyElementList
uses the ISpElementList_AddElements function (page 3-53) to add elements of kindkISpElementKind_Button
andkISpElementKind_DPad
to the list. They are added one at a time so that each element can be assigned the reference constant that corresponds to its index in the array of need structures.Processing Input Data During Play
During game play the game obtains data from all the input devices either by polling or getting events. Listing 3-3 shows theProcessInput
routine. This routine runs the main game loop, polling for the state of axis and movement elements and getting events from button elements.
ProcessInput
takes an element list that has been built so that the index of each element corresponds to its position in the array of need structures passed to the drivers during autoconfiguration (see Listing 3-2 for an example of how to do this).Notice that there are two routines for getting the state of an element--
ISpElement_GetSimpleState
andISpElement_GetComplexState
. TheISpElement_GetSimpleState
function (page 3-47) is for elements whose data fits in an unsigned 32-bit integer. For other elements, in this case, movement kind elements, useISpElement_GetComplexState
(page 3-47) where you can specify the size of the buffer needed to hold the data.Buttons work in a variety of ways and the code illustrates how to get events for three types--a firing button, where only down events matter (the laser and missile buttons); a toggle (the stop button); and a hold-to-activate button (the shield button).
Listing 3-3 Processing input data
enum { kForwardThrust = 0, kSideThrust, kVerticalThrust, kLook, kLaser, kMissle, kShields, kStartStop, kNumNeeds }; typedef struct InputData { UInt32 x,y,z; // x,y and z thrust UInt32 xLook, yLook; Boolean fireLasers; Boolean fireMissles; Boolean shields; // down activates; up deactivates Boolean stopped; // toggle } InputData; void ProcessInput(ISpElementReference *theElements, ISpElementListReference myList, InputData *myInput) { ISpElement_GetSimpleState(theElements[kForwardThrust], &(myInput->x)); ISpElement_GetSimpleState(theElements[kSideThrust], &(myInput->y)); ISpElement_GetSimpleState(theElements[kVerticalThrust], &(myInput->z)); ISpMovementData tempMovement; ISpElement_GetComplexState(theElements[kLook], sizeof(ISpMovementData),&tempMovement); myInput->xLook = tempMovement.xAxis; myInput->yLook = tempMovement.yAxis; myInput->fireLasers = false; myInput->fireMissles = false; Boolean wasEvent; ISpElementEvent theEvent; while(1) { ISpElementList_GetNextEvent(myList, sizeof(ISpElementEvent), &theEvent, &wasEvent); switch(theEvent.refCon) { case kLaser: if (theEvent.data == kISpButtonDown) { myInput->fireLasers = true; } break; case kMissle: if (theEvent.data == kISpButtonDown) { myInput->fireMissles = true; } break; case kShields: if (theEvent.data == kISpButtonDown) { myInput->shields = true; } else if (theEvent.data == kISpButtonUp) { myInput->shields = false; } break; case kStartStop: if (theEvent.data == kISpButtonDown) { myInput->stopped = !myInput->stopped; } break; } if (!wasEvent) { return; } } }
Turning the Keyboard and Mouse On and Off
By default, keyboard and mouse input devices are inactive. This is fine for games that run in a window where the user probably expects the mouse and keyboard to behave normally. However, most games will want to activate the keyboard and mouse. Later, there may be a point in the game where the user needs to enter text, in which case, you would want to deactivate the keyboard and mouse as game input devices so that you can return to using the standard methods provided by the OS to manage them.Listing 3-4 shows the
SetKeyboardMouseActivation
function that deactivates and activates the keyboard and mouse devices.Listing 3-4 Turning off keyboard and mouse devices
Thevoid SetKeyboardMouseActivation(Boolean active) { enum { kSimple = 100 }; ISpDeviceReference buffer[kSimple]; UInt32 count; ISpDevices_ExtractByClass(kISpDeviceClass_Mouse, kSimple, &count, buffer); if (active) { ISpDevices_Activate(count,buffer); } else { ISpDevices_Deactivate(count, buffer); } ISpDevices_ExtractByClass(kISpDeviceClass_Keyboard,kSimple,&count, buffer); if (active) { ISpDevices_Activate(count,buffer); } else { ISpDevices_Deactivate(count, buffer); } }
SetKeyboardMouseActivation
function usesISpDevices_ExtractByClass
(page 3-39) to find the keyboard and mouse devices. Notice that the buffer allocated to hold the device references is allocated for 100 devices, a number likely to be sufficient. TheISpDevices_Deactivate
function is described on (page 3-41);ISpDevices_Activate
is on (page 3-41).