Line 700: |
Line 700: |
| | | |
| ==Applejack Input Device Driver== | | ==Applejack Input Device Driver== |
− | The Applejack input device driver combines the features of a game-player pad and a mouse or trackball in a small handheld device. Generally, Applejack input devices are attached to a Pippin Power Player (a CD-ROM multimedia player device derived from the PowerPC Macintosh). | + | ===Introduction=== |
| + | The Pippin input device, Applejack, is a custom ADB device containing trackball information and a series of 18 button states. The Applejack driver resides in the Pippin ROM and loads at system boot time. On a Macintosh, the Applejack driver resides in the system extension file. |
| + | |
| + | The Applejack driver uses a 'pipp' button mapping resource which allows any Applejack button to be mapped with either a mouse button or keyboard key function. The trackball data, however, is always treated as a "mouse" and there is no provision for remapping it. |
| + | |
| + | While provision for default button mapping is provided, applications can also include a custom 'pipp' resource for setting button functions. On Pippin ROMs, a custom 'pipp' resource would be loaded automatically when an application is launched. For applications that do not use mouse or keyboard mappings (not highly recommended), the Applejack raw data is directly readable from the driver. |
| + | |
| + | ===Setting Up=== |
| + | The Applejack Software Developer's Kit diskette contains the application for editing the 'pipp' mapping resource, and an system extension file. |
| + | |
| + | # From the SDK diskette, copy the application file to your Macintosh hard drive. |
| + | # Drag-and-drop the system extension file to the "Extensions" folder in your System Folder. |
| + | # Ensure that the Applejack input device driver(s) are plugged into the ADB jack adapter(s) on the backside of your Macintosh. |
| + | # Restart the Macintosh to initialize the system extension file. |
| + | |
| + | You are now ready to customize the Applejack input device driver. |
| + | |
| + | ===Customizing the Applejack=== |
| + | There are two ways to customize the 'pipp' mapping resource of the Applejack input device driver(s). |
| + | |
| + | The simplest way involves using the application as an interface for redefining device button mapping. This mechanism is as simple as aligning an attached Applejack device (or possibly, unattached Applejack device, as the case may be) with a visual device on the Macintosh screen. By clicking on the on-screen buttons, a developer customizes an Applejack device(s). |
| + | |
| + | The second way involves modifying the 'pipp' mapping resource code files manually, specifically defining how the button mechanisms on the device(s) should work. |
| + | |
| + | ====The Applejack Control 2.2.0 Application==== |
| + | The application is the interface used for editing the 'pipp' mapping resource. Double-click on the application icon and a window similar to Figure 1 will appear. |
| + | |
| + | Figure 1 : Applejack Control 2.2.0 Application Launch Window |
| + | |
| + | [[File:Figurea1.gif]] |
| + | |
| + | If the application does not find any Applejack device(s) physically connected to the bus, the window displays a "NO GAME PADS FOUND" message across the window instead, as follows. |
| + | |
| + | Figure 2 : NO GAME PAD FOUND Window |
| + | |
| + | [[File:Figurea2.gif]] |
| + | |
| + | Regardless of whether an Applejack device(s) is connected or not, the button settings may be edited. By clicking on desired buttons, a developer can customize the Applejack device(s). |
| + | |
| + | A dialog box similar to Figure 3 or Figure 4 appears, depending on the button clicked on. |
| + | |
| + | Figure 3 : Applejack Control 2.2.0 Dialog Box--Customizing Keyboard Key Functions |
| + | |
| + | [[File:Figurea3.gif]] |
| + | |
| + | When defining specific keyboard keys, select the "Keyboard Key" option, and press the key desired, which will appear in the character fill-in box. Also, modifiers can be designated (click on appropriate box) with a specific keyboard key, if desired. Then, click on "Ok" to proceed. |
| + | |
| + | When defining mouse button functions, click on the appropriate "mouse" functions, as desired, then click on "Ok" to proceed. |
| + | |
| + | Figure 4 : Applejack Control 2.2.0 Dialog Box--Customizing Mouse Button Functions |
| + | |
| + | [[File:Figurea4.gif]] |
| + | |
| + | By clicking "Ok" after defining each button, the Applejack driver's local data is updated. If an Applejack device is attached, the newly defined button functions can be tested immediately with the newly "customized" Applejack device(s). |
| + | |
| + | By quitting the application, the 'pipp' resource within the system extension file is updated. If you would like to write the 'pipp' resource into a separate file, use the "File:Make Resource..." menu item. |
| + | |
| + | =====Applejack Default Button Settings===== |
| + | The Driver in the Pippin ROM creates default settings for the Applejack buttons if there is no Applejack extension installed. The default Applejack button settings are as follows: |
| + | |
| + | [[File:Sect2.gif]] |
| + | |
| + | ====Modifying the 'pipp' Button Mapping Resource==== |
| + | Alternatively, 'pipp' resources can be built and keys (functions) remapped by looking at the driver's global data. Figure 5 illustrates the Applejack Input Device Driver and its corresponding button mapping. |
| + | |
| + | Figure 5 : Applejack Input Device--Button Mapping |
| + | |
| + | [[File:Figure55.gif]] |
| + | |
| + | The 'pipp' resource is identical to the driver's global data and is a structure of type AJGlobalData. This global data is pointed to by the .refCon field of the Cursor Device Manager record for each Applejack device, as defined in the following code. |
| + | <pre> |
| + | typedef struct SwitchData { |
| + | Byte function; |
| + | Byte modifiers; |
| + | Byte keyCode; |
| + | Byte charCode; |
| + | } SwitchData, *SwitchDataPtr; |
| + | |
| + | typedef struct AJGlobalData { |
| + | long signature; |
| + | Byte MyTalkR0; |
| + | Byte handlerID; |
| + | Byte ourMBState; |
| + | Byte ourLockState; |
| + | long switchStates; |
| + | SwitchData switchMappingArray[18]; |
| + | long nextjADBProc; |
| + | long cursorHandler; |
| + | } AJGlobalData, *AJGlobalDataPtr; |
| + | </pre> |
| + | Most notably in the above code is the signature. The driver installer has initialized the signature to equal 'pipp' so that applications can look through the ADB device table and find this structure. Further, the function field of the SwitchData switchMappingArray is defined as follows: |
| + | <pre> |
| + | enum { |
| + | |
| + | kNothing = 0, // maps to nothing |
| + | kMouse = 1, // maps to standard mouse button operation |
| + | kMouseDblClick = 2, // maps to mouse button double click |
| + | kMouseLock = 3, // toggles the mouse button state |
| + | kKeyboard = 4, // maps to a keyboard key |
| + | kFrontPanel = 5, // not used |
| + | kModifier = 6 // maps to a modifier key |
| + | }; |
| + | </pre> |
| + | Each element of the switchMappingArray array represents one of the switches on Applejack. The array index is equal to the bit numbers, as shown in Figure 6. |
| + | |
| + | Figure 6 : ADB Register 0 Four-Byte Packet and Bit Number to Button Mapping |
| + | |
| + | [[File:Figure66.gif]] |
| + | |
| + | If a button is mapped as kKeyboard, then the Applejack driver posts a keyDown event with the .keyCode, .keyChar and .modifiers fields in the event record. |
| + | |
| + | The following code shows an enumeration of equates for the .modifiers field. |
| + | <pre> |
| + | enum { |
| + | kCommandBit = 0, |
| + | kShiftBit = 1, |
| + | kCapsLockBit = 2, |
| + | kOptionBit = 3, |
| + | kControlBit = 4 |
| + | }; |
| + | </pre> |
| + | If a button is mapped as kModifier, then the Applejack driver sets the keyMap global for the keyCode specified in the .keyCode field. The other fields are ignored in this case. |
| + | |
| + | The following code is another enumeration of equates for the .modifiers field. |
| + | <pre> |
| + | enum { |
| + | kCommandKey = 0x37, |
| + | kShiftKey = 0x38, |
| + | kCapsLockKey = 0x39, |
| + | kOptionKey = 0x3A, |
| + | kControlKey = 0x36 |
| + | }; |
| + | </pre> |
| + | To change the mapping of a button, map a pointer to the AJGlobalData structure, then put in new values for the .switches fields for the desired switch. A good reason to do this would be if you wanted to read the Applejack raw data but did not want a button to also be generating system events. |
| + | |
| + | The following code maps a pointer to the AJGlobalData structure for each connected Applejack, and then changes the selected switch. |
| + | <pre> |
| + | void ChangeSwitchMapping (short whichSwitch, short function, short modifiers, |
| + | short keyCode, short charCode); |
| + | |
| + | void ChangeSwitchMapping (short whichSwitch, short function, short modifiers, |
| + | short keyCode, short charCode); |
| + | { |
| + | ADBAddress address; |
| + | ADBDataBlock dataBlock; |
| + | AJGlobalDataPtr myAJ; |
| + | CursorDevicePtr myCrsrDev; |
| + | short index,i; |
| + | |
| + | //We need to copy these changes into the currently installed drivers. |
| + | //Where are the Applejacks? |
| + | |
| + | //The Applejack driver uses the .refcon field of the cursor device record to |
| + | //store a pointer to its globals, a AJGlobalDataPtr. |
| + | |
| + | if(whichSwitch>=0 && whichSwitch<=17) |
| + | { // where are the AppleJacks? |
| + | index = CountADBs(); |
| + | while(index>0) |
| + | { |
| + | address=GetIndADB(&dataBlock,index); |
| + | if((dataBlock.origADBAddr)==kDevAddr) |
| + | { // make sure that this is really us |
| + | if(dataBlock.dbDataAreaAddr) |
| + | { |
| + | myCrsrDev=(CursorDevicePtr)dataBlock.dbDataAreaAddr; |
| + | if(myCrsrDev) |
| + | { |
| + | myAJ=(AJGlobalDataPtr)myCrsrDev->refCon; |
| + | if(myAJ->signature=='pipp') |
| + | { // got it. |
| + | myAJ->switchMappingArray.function[whichSwitch]=function; |
| + | myAJ->switchMappingArray.modifiers[whichSwitch]=modifiers; |
| + | myAJ->switchMappingArray.keyCode[whichSwitch]=keyCode; |
| + | myAJ->switchMappingArray.charCode[whichSwitch]=charCode; |
| + | } |
| + | } |
| + | } |
| + | } |
| + | index--; |
| + | } |
| + | </pre> |
| + | Some other ways to use this function could be as follows: |
| + | |
| + | * Map the yellow button (S10, bit 9) to do nothing: |
| + | ChangeSwitchMapping(9,kNothing,0,0,0); |
| + | * Map the red button (S8, bit 14) to be equal to command-Q (quit): |
| + | ChangeSwitchMapping(14,kKeyboard,((1<<kCommandBit)),0x0C,'Q'); |
| + | * Map the green button (S7, bit 15) to be equal to the shift key: |
| + | ChangeSwitchMapping(15,kModifier,0,kShiftKey,0); |
| + | |
| + | ===Reading Raw Applejack Data=== |
| + | To read raw Applejack data yourself, use code like the previous sample code, and ensure that you map a pointer to the AJGlobalData for each connected Applejack. You need to do this only once, but remember the pointer since it will not be moved or purged. |
| + | |
| + | Then, examine myAJ->switchStates to read the state of a button. Each button correlates with a bit in switchStates. The bit number is the same as defined in the .switchMappingArray array index. |
| + | |
| + | For example, suppose you want to know if the yellow button is pressed; the following statement might apply: |
| + | <pre> |
| + | if(!((myAJ>switchStates)&(1<<9))) // 0==DOWN |
| + | { // 1==UP |
| + | Do something useful here, yellow button is down... |
| + | } |
| + | </pre> |
| + | Be sure to keep separate pointers for each Applejack found (maximum of 4) even if you only support a single player play. If the bit number returns a value of `0', then the button is pressed. If a value of `1' is returned, the button is not pressed. No other event loop is required. |
| | | |
| ==Pippin Video== | | ==Pippin Video== |