home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Games / ISp Sample / Source / ISp_Sample.c < prev    next >
Encoding:
Text File  |  2000-09-28  |  27.3 KB  |  814 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        ISp_Sample.c
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                xxx put dri here xxx
  13.  
  14.         Other Contact:        xxx put other contact here xxx
  15.  
  16.         Technology:            xxx put technology here xxx
  17.  
  18.     Writers:
  19.  
  20.         (BWS)    Brent Schorsch
  21.  
  22.     Change History (most recent first):
  23.  
  24.        <SP2>      7/1/99    BWS        Use some new need flags
  25.        <SP1>      7/1/99    BWS        first checked in
  26. */
  27.  
  28. //•    ——————————————————————————————    Includes
  29.  
  30. #define USE_OLD_INPUT_SPROCKET_LABELS 0
  31. #define USE_OLD_ISPNEED_STRUCT 0
  32.  
  33. #include <InputSprocket.h>
  34. #include <CodeFragments.h>
  35. #include <FixMath.h>
  36. #include <Fonts.h>
  37. #include <MacWindows.h>
  38. #include <ToolUtils.h>
  39. #include <TextUtils.h>
  40.  
  41. #include "ISp_Sample.h"
  42. #include "ISp_SampleResources.h"
  43. #include "ErrorAlert.h"
  44. #include "EventHandler.h"
  45.  
  46. //•    ——————————————————————————————    Private Definitions
  47. //•    ——————————————————————————————    Private Types
  48. //•    ——————————————————————————————    Private Variables
  49. Boolean    gKeyboardTypingEnabled = true;
  50. Boolean    gMouseAsMacOSCursorEnabled = true;
  51.  
  52. ISpElementReference            gInputElements[kNeed_NeedCount];
  53. ISpElementListReference     gEventsElementList = NULL;
  54. ISpElementListReference     gYawElementList = NULL;
  55. ISpElementListReference     gThrottleElementList = NULL;
  56.  
  57.  
  58. //•    ——————————————————————————————    Private Functions
  59.  
  60. Boolean    Input_ISpConfigureEventProc (EventRecord * inEvent);
  61.  
  62. static void        Input_GetRoll (Input_GameState * gameState);
  63. static void        Input_GetPitch (Input_GameState * gameState);
  64. static void        Input_GetYaw (Input_GameState * gameState);
  65. static void        Input_GetThrottle (Input_GameState * gameState);
  66.  
  67. static SInt32    ISpAxisToSampleAxis (ISpAxisData axisValue, SInt32 min, SInt32 max);
  68.  
  69. //•    ——————————————————————————————    Public Variables
  70.  
  71. //•    ————————————————————    Input_Available
  72. Boolean  Input_Available (void)
  73. {
  74.     Boolean iSpAvailable = false;
  75.     
  76.     if ((ProcPtr) ISpGetVersion != (ProcPtr) kUnresolvedCFragSymbolAddress)
  77.     {
  78.         NumVersion iSpNumVersion = ISpGetVersion();
  79.         UInt32 inputSprocketVersion = * (UInt32 *) &(iSpNumVersion);
  80.         
  81.         // require InputSprocket 1.2.0 (we need delta types)
  82.         if (inputSprocketVersion >= 0x01200000)
  83.             iSpAvailable = true;
  84.     }
  85.     
  86.     return iSpAvailable;
  87. }
  88.  
  89. //•    ————————————————————    Input_Initialize
  90. OSStatus Input_Initialize (void)
  91. {
  92.     OSStatus    theError;
  93.  
  94.     //•    This structure defines the input needs that we'll be requesting from InputSprocket
  95.     ISpNeed        tempNeed;
  96.     ISpNeed        myNeeds[kNeed_NeedCount];
  97.     
  98.     tempNeed.reserved1 = 0;
  99.     tempNeed.reserved2 = 0;
  100.     tempNeed.reserved3 = 0;
  101.  
  102.     //• we'll init all the player 1 items now (everything but quit unless we add a second player)
  103.     tempNeed.playerNum = 1;
  104.     
  105.     // First we init (player 1) items that are not part of a group (group 0)
  106.     tempNeed.group = 0;
  107.  
  108.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_FireWeapon + 1);
  109.     tempNeed.iconSuiteResourceId = 1000 + kNeed_FireWeapon;
  110.     tempNeed.theKind = kISpElementKind_Button;
  111.     tempNeed.theLabel = kISpElementLabel_Btn_Fire;
  112.     tempNeed.flags = kISpNeedFlag_Button_ActiveWhenDown | kISpNeedFlag_EventsOnly;
  113.     myNeeds[kNeed_FireWeapon] = tempNeed;
  114.     
  115.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_StartPause + 1);
  116.     tempNeed.iconSuiteResourceId = 1000 + kNeed_StartPause;
  117.     tempNeed.theKind = kISpElementKind_Button;
  118.     tempNeed.theLabel = kISpNeedFlag_NoAutoConfig | kISpElementLabel_Btn_StartPause;
  119.     tempNeed.flags = kISpNeedFlag_EventsOnly;
  120.     myNeeds[kNeed_StartPause] = tempNeed;
  121.  
  122.     // Now group 1, which is for changing the current weapon
  123.     tempNeed.group = 1;
  124.     tempNeed.flags = kISpNeedFlag_EventsOnly;
  125.  
  126.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_NextWeapon + 1);
  127.     tempNeed.iconSuiteResourceId = 1000 + kNeed_NextWeapon;
  128.     tempNeed.theKind = kISpElementKind_Button;
  129.     tempNeed.theLabel = kISpElementLabel_Btn_Next;
  130.     myNeeds[kNeed_NextWeapon] = tempNeed;
  131.     
  132.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_PreviousWeapon + 1);
  133.     tempNeed.iconSuiteResourceId = 1000 + kNeed_PreviousWeapon;
  134.     tempNeed.theKind = kISpElementKind_Button;
  135.     tempNeed.theLabel = kISpElementLabel_Btn_Previous;
  136.     myNeeds[kNeed_PreviousWeapon] = tempNeed;
  137.     
  138.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Weapon_MachineGun + 1);
  139.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Weapon_MachineGun;
  140.     tempNeed.theKind = kISpElementKind_Button;
  141.     tempNeed.theLabel = kISpElementLabel_None;
  142.     tempNeed.flags = kISpNeedFlag_NoConfig;
  143.     myNeeds[kNeed_Weapon_MachineGun] = tempNeed;
  144.     
  145.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Weapon_Cannon + 1);
  146.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Weapon_Cannon;
  147.     tempNeed.theKind = kISpElementKind_Button;
  148.     tempNeed.theLabel = kISpElementLabel_None;
  149.     myNeeds[kNeed_Weapon_Cannon] = tempNeed;
  150.     
  151.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Weapon_Laser + 1);
  152.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Weapon_Laser;
  153.     tempNeed.theKind = kISpElementKind_Button;
  154.     tempNeed.theLabel = kISpElementLabel_None;
  155.     tempNeed.flags = kISpNeedFlag_NoConfig;
  156.     myNeeds[kNeed_Weapon_Laser] = tempNeed;
  157.     
  158.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Weapon_Missle + 1);
  159.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Weapon_Missle;
  160.     tempNeed.theKind = kISpElementKind_Button;
  161.     tempNeed.theLabel = kISpElementLabel_None;
  162.     tempNeed.flags = kISpNeedFlag_NoConfig;
  163.     myNeeds[kNeed_Weapon_Missle] = tempNeed;
  164.     
  165.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Weapon_PrecisionBomb + 1);
  166.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Weapon_PrecisionBomb;
  167.     tempNeed.theKind = kISpElementKind_Button;
  168.     tempNeed.theLabel = kISpElementLabel_None;
  169.     tempNeed.flags = kISpNeedFlag_NoConfig;
  170.     myNeeds[kNeed_Weapon_PrecisionBomb] = tempNeed;
  171.     
  172.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Weapon_ClusterBomb + 1);
  173.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Weapon_ClusterBomb;
  174.     tempNeed.theKind = kISpElementKind_Button;
  175.     tempNeed.theLabel = kISpElementLabel_None;
  176.     tempNeed.flags = kISpNeedFlag_NoConfig;
  177.     myNeeds[kNeed_Weapon_ClusterBomb] = tempNeed;
  178.  
  179.     // Now group 2, which is for changing roll
  180.     tempNeed.group = 2;
  181.  
  182.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Roll + 1);
  183.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Roll;
  184.     tempNeed.theKind = kISpElementKind_Axis;
  185.     tempNeed.theLabel = kISpElementLabel_Axis_Roll;
  186.     tempNeed.flags = kISpNeedFlag_Axis_AlreadyDelta;
  187.     myNeeds[kNeed_Roll] = tempNeed;
  188.     
  189.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Roll_AsDelta + 1);
  190.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Roll_AsDelta;
  191.     tempNeed.theKind = kISpElementKind_Delta;
  192.     tempNeed.theLabel = kISpElementLabel_Delta_Roll;
  193.     tempNeed.flags = kISpNeedFlag_Delta_AlreadyAxis;
  194.     myNeeds[kNeed_Roll_AsDelta] = tempNeed;
  195.     
  196.     // Now group 3, which is for changing pitch
  197.     tempNeed.group = 3;
  198.  
  199.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Pitch + 1);
  200.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Pitch;
  201.     tempNeed.theKind = kISpElementKind_Axis;
  202.     tempNeed.theLabel = kISpElementLabel_Axis_Pitch;
  203.     tempNeed.flags = kISpNeedFlag_Axis_AlreadyDelta;
  204.     myNeeds[kNeed_Pitch] = tempNeed;
  205.     
  206.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Pitch_AsDelta + 1);
  207.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Pitch_AsDelta;
  208.     tempNeed.theKind = kISpElementKind_Delta;
  209.     tempNeed.theLabel = kISpElementLabel_Delta_Pitch;
  210.     tempNeed.flags = kISpNeedFlag_Delta_AlreadyAxis;
  211.     myNeeds[kNeed_Pitch_AsDelta] = tempNeed;
  212.     
  213.     // Now group 4, which is for changing yaw
  214.     tempNeed.group = 4;
  215.  
  216.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Yaw + 1);
  217.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Yaw;
  218.     tempNeed.theKind = kISpElementKind_Axis;
  219.     tempNeed.theLabel = kISpElementLabel_Axis_Yaw;
  220.     tempNeed.flags = kISpNeedFlag_Axis_AlreadyDelta | kISpNeedFlag_Axis_AlreadyButton;
  221.     myNeeds[kNeed_Yaw] = tempNeed;
  222.     
  223.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Yaw_AsDelta + 1);
  224.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Yaw_AsDelta;
  225.     tempNeed.theKind = kISpElementKind_Delta;
  226.     tempNeed.theLabel = kISpElementLabel_Delta_Yaw;
  227.     tempNeed.flags = kISpNeedFlag_Delta_AlreadyAxis | kISpNeedFlag_Delta_AlreadyButton;
  228.     myNeeds[kNeed_Yaw_AsDelta] = tempNeed;
  229.     
  230.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Yaw_Left + 1);
  231.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Yaw_Left;
  232.     tempNeed.theKind = kISpElementKind_Button;
  233.     tempNeed.theLabel = kISpElementLabel_None;
  234.     tempNeed.flags = kISpNeedFlag_Button_AlreadyAxis | kISpNeedFlag_Button_AlreadyDelta | kISpNeedFlag_EventsOnly;
  235.     myNeeds[kNeed_Yaw_Left] = tempNeed;
  236.     
  237.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Yaw_Center + 1);
  238.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Yaw_Center;
  239.     tempNeed.theKind = kISpElementKind_Button;
  240.     tempNeed.theLabel = kISpElementLabel_None;
  241.     tempNeed.flags = kISpNeedFlag_Button_AlreadyAxis | kISpNeedFlag_Button_AlreadyDelta | kISpNeedFlag_EventsOnly;
  242.     myNeeds[kNeed_Yaw_Center] = tempNeed;
  243.     
  244.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Yaw_Right + 1);
  245.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Yaw_Right;
  246.     tempNeed.theKind = kISpElementKind_Button;
  247.     tempNeed.theLabel = kISpElementLabel_None;
  248.     tempNeed.flags = kISpNeedFlag_Button_AlreadyAxis | kISpNeedFlag_Button_AlreadyDelta | kISpNeedFlag_EventsOnly;
  249.     myNeeds[kNeed_Yaw_Right] = tempNeed;
  250.     
  251.     // Now group 5, which is for changing throttle
  252.     tempNeed.group = 5;
  253.  
  254.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Throttle + 1);
  255.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Throttle;
  256.     tempNeed.theKind = kISpElementKind_Axis;
  257.     tempNeed.theLabel = kISpElementLabel_Axis_Throttle;
  258.     tempNeed.flags = kISpNeedFlag_Axis_Asymetric | kISpNeedFlag_Axis_AlreadyButton;
  259.     myNeeds[kNeed_Throttle] = tempNeed;
  260.     
  261.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Throttle_Min + 1);
  262.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Throttle_Min;
  263.     tempNeed.theKind = kISpElementKind_Button;
  264.     tempNeed.theLabel = kISpElementLabel_None;
  265.     tempNeed.flags = kISpNeedFlag_Button_AlreadyAxis | kISpNeedFlag_EventsOnly;
  266.     myNeeds[kNeed_Throttle_Min] = tempNeed;
  267.     
  268.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Throttle_Decrease + 1);
  269.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Throttle_Decrease;
  270.     tempNeed.theKind = kISpElementKind_Button;
  271.     tempNeed.theLabel = kISpElementLabel_None;
  272.     tempNeed.flags = kISpNeedFlag_Button_AlreadyAxis | kISpNeedFlag_EventsOnly;
  273.     myNeeds[kNeed_Throttle_Decrease] = tempNeed;
  274.     
  275.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Throttle_Increase + 1);
  276.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Throttle_Increase;
  277.     tempNeed.theKind = kISpElementKind_Button;
  278.     tempNeed.theLabel = kISpElementLabel_None;
  279.     tempNeed.flags = kISpNeedFlag_Button_AlreadyAxis | kISpNeedFlag_EventsOnly;
  280.     myNeeds[kNeed_Throttle_Increase] = tempNeed;
  281.     
  282.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Throttle_Max + 1);
  283.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Throttle_Max;
  284.     tempNeed.theKind = kISpElementKind_Button;
  285.     tempNeed.theLabel = kISpElementLabel_None;
  286.     tempNeed.flags = kISpNeedFlag_Button_AlreadyAxis | kISpNeedFlag_EventsOnly;
  287.     myNeeds[kNeed_Throttle_Max] = tempNeed;
  288.     
  289.     //• now we init utility needs that affect all players (just have quit for now)
  290.     tempNeed.playerNum = 0;
  291.     tempNeed.group = 0;
  292.  
  293.     GetIndString (tempNeed.name, kSTRn_NeedNames, kNeed_Quit + 1);
  294.     tempNeed.iconSuiteResourceId = 1000 + kNeed_Quit;
  295.     tempNeed.theKind = kISpElementKind_Button;
  296.     tempNeed.theLabel = kISpElementLabel_Btn_Quit;
  297.     tempNeed.flags = kISpNeedFlag_NoAutoConfig | kISpNeedFlag_EventsOnly;
  298.     myNeeds[kNeed_Quit] = tempNeed;
  299.     
  300.     //• Alright, now that the array is set up, we can call ISp to init stuff
  301.     theError = ISpStartup ();
  302.     if (theError)
  303.         ErrorAlert("\pCould not Initialize InputSprocket.", theError, true);
  304.  
  305.     //•    Setup the input sprocket elements
  306.     theError = ISpElement_NewVirtualFromNeeds(kNeed_NeedCount, myNeeds, gInputElements, 0);
  307.     if (theError)
  308.         ErrorAlert("\pCould not create ISp virtual controls from needs.", theError, true);
  309.  
  310.     //•    Init InputSprocket and tell it our needs
  311.     theError = ISpInit (kNeed_NeedCount, myNeeds, gInputElements, 
  312.                     kISpSampleCreator, kISpSampleNeedsVersion, 
  313.                     0, ksetl_ISpSample, 0); 
  314.     if (theError)
  315.         ErrorAlert("\pCould not initialize high-level ISp.", theError, true);
  316.  
  317.     //• Create a element list containg all the 'normal' buttons (we get events on these)
  318.     theError = ISpElementList_New(0, NULL, &gEventsElementList, 0);
  319.     if (theError)
  320.         ErrorAlert("\pCould not create button element list.", theError, true);
  321.     
  322.     //• we set the refcon to the need enum value, so we can use it later
  323.     //• doing some shortcut error checking for readability
  324.     theError  = ISpElementList_AddElements (gEventsElementList, 
  325.                     kNeed_FireWeapon,         1, &gInputElements[kNeed_FireWeapon]);
  326.     theError |= ISpElementList_AddElements (gEventsElementList, 
  327.                     kNeed_StartPause,         1, &gInputElements[kNeed_StartPause]);
  328.  
  329.     theError |= ISpElementList_AddElements (gEventsElementList, 
  330.                     kNeed_NextWeapon,         1, &gInputElements[kNeed_NextWeapon]);
  331.     theError |= ISpElementList_AddElements (gEventsElementList, 
  332.                     kNeed_PreviousWeapon,     1, &gInputElements[kNeed_PreviousWeapon]);
  333.  
  334.     theError |= ISpElementList_AddElements (gEventsElementList, 
  335.                     kNeed_Weapon_MachineGun, 1, &gInputElements[kNeed_Weapon_MachineGun]);
  336.     theError |= ISpElementList_AddElements (gEventsElementList, 
  337.                     kNeed_Weapon_Cannon,     1, &gInputElements[kNeed_Weapon_Cannon]);
  338.     theError |= ISpElementList_AddElements (gEventsElementList, 
  339.                     kNeed_Weapon_Laser,     1, &gInputElements[kNeed_Weapon_Laser]);
  340.     theError |= ISpElementList_AddElements (gEventsElementList, 
  341.                     kNeed_Weapon_Missle,     1, &gInputElements[kNeed_Weapon_Missle]);
  342.     theError |= ISpElementList_AddElements (gEventsElementList, 
  343.                     kNeed_Weapon_PrecisionBomb,1, &gInputElements[kNeed_Weapon_PrecisionBomb]);
  344.     theError |= ISpElementList_AddElements (gEventsElementList, 
  345.                     kNeed_Weapon_ClusterBomb,1, &gInputElements[kNeed_Weapon_ClusterBomb]);
  346.  
  347.     theError |= ISpElementList_AddElements (gEventsElementList, 
  348.                     kNeed_Quit,             1, &gInputElements[kNeed_Quit]);
  349.  
  350.     if (theError)
  351.         ErrorAlert("\pCould not fill button element list. Error number may be inaccurate.", theError, true);
  352.  
  353.     // create element list for rudder
  354.     //•• we need to treat this differently from regular buttons, because we don't know whether the
  355.     //•• axis will be moved or the button will be hit, we need to support both at once
  356.     theError = ISpElementList_New(0, NULL, &gYawElementList, 0);
  357.     if (theError)
  358.         ErrorAlert("\pCould not create yaw element list.", theError, true);
  359.  
  360.     //• doing some shortcut error checking for readability
  361.     theError  = ISpElementList_AddElements (gYawElementList, 
  362.                     kNeed_Yaw_Left, 1, &gInputElements[kNeed_Yaw_Left]);
  363.     theError |= ISpElementList_AddElements (gYawElementList, 
  364.                     kNeed_Yaw_Center, 1, &gInputElements[kNeed_Yaw_Center]);
  365.     theError |= ISpElementList_AddElements (gYawElementList, 
  366.                     kNeed_Yaw_Right, 1, &gInputElements[kNeed_Yaw_Right]);
  367.     if (theError)
  368.         ErrorAlert("\pCould not fill yaw element list. Error number may be inaccurate.", theError, true);
  369.  
  370.     // create element list for throttle
  371.     //•• we need to treat this differently from regular buttons, because we don't know whether the
  372.     //•• axis will be moved or the button will be hit, we need to support both at once
  373.     theError = ISpElementList_New(0, NULL, &gThrottleElementList, 0);
  374.     if (theError)
  375.         ErrorAlert("\pCould not create throttle element list.", theError, true);
  376.     
  377.     //• doing some shortcut error checking for readability
  378.     theError  = ISpElementList_AddElements (gThrottleElementList, 
  379.                     kNeed_Throttle_Min, 1, &gInputElements[kNeed_Throttle_Min]);
  380.     theError |= ISpElementList_AddElements (gThrottleElementList, 
  381.                     kNeed_Throttle_Decrease, 1, &gInputElements[kNeed_Throttle_Decrease]);
  382.     theError |= ISpElementList_AddElements (gThrottleElementList, 
  383.                     kNeed_Throttle_Increase, 1, &gInputElements[kNeed_Throttle_Increase]);
  384.     theError |= ISpElementList_AddElements (gThrottleElementList, 
  385.                     kNeed_Throttle_Max, 1, &gInputElements[kNeed_Throttle_Max]);
  386.     if (theError)
  387.         ErrorAlert("\pCould not fill throttle element list. Error number may be inaccurate.", theError, true);
  388.     
  389.     //•    Enable speech input (we commit to calling ISpTickle at WNE time)
  390.      ISpDevices_ActivateClass (kISpDeviceClass_SpeechRecognition);
  391.     
  392.     //• we leave kayboard and mouse disabled. We will enable them when the 'game' is active
  393.     
  394.     return noErr;
  395. }
  396.  
  397.  
  398. //•    ————————————————————    Input_Terminate
  399. OSStatus Input_Terminate (void)
  400. {
  401.     return ISpShutdown ();
  402. }
  403.  
  404. //•    ————————————————————    Input_InitializeState
  405. void    Input_InitializeState (Input_GameState * gameState)
  406. {
  407.     ISpAxisData            axisValue;
  408.     OSStatus            error = noErr;
  409.     
  410.     gameState->gameInProgress = false;
  411.     gameState->gamePaused = false;
  412.  
  413.     gameState->fireWeaponState = false;
  414.     gameState->fireWeaponCount = 0;
  415.     
  416.     gameState->currentWeapon = kWeapon_MachineGun;
  417.     
  418.     gameState->rollInput = 0;
  419.     gameState->pitchInput = 0;
  420.     gameState->yawInput = 0;
  421.     gameState->throttleInput = 0;
  422.     
  423.     gameState->deltaRoll = 0;
  424.     gameState->deltaPitch = 0;
  425.     gameState->deltaYaw = 0;
  426.  
  427.     error = ISpElement_GetSimpleState(gInputElements[kNeed_Roll], &axisValue);
  428.     if (!error) gameState->rollInput = ISpAxisToSampleAxis (axisValue, kMin_Roll, kMax_Roll);
  429.     
  430.     error = ISpElement_GetSimpleState(gInputElements[kNeed_Pitch], &axisValue);
  431.     if (!error) gameState->pitchInput = ISpAxisToSampleAxis (axisValue, kMin_Pitch, kMax_Pitch);
  432.     
  433.     error = ISpElement_GetSimpleState(gInputElements[kNeed_Yaw], &axisValue);
  434.     if (!error) gameState->yawInput = ISpAxisToSampleAxis (axisValue, kMin_Yaw, kMax_Yaw);
  435.     
  436.     error = ISpElement_GetSimpleState(gInputElements[kNeed_Throttle], &axisValue);
  437.     if (!error) gameState->throttleInput = ISpAxisToSampleAxis (axisValue, kMin_Throttle, kMax_Throttle);
  438. }
  439.     
  440. //•    ————————————————————    Input_Suspend
  441. OSStatus Input_Suspend (void)
  442. {
  443.     return ISpSuspend ();
  444. }
  445.  
  446. //•    ————————————————————    Input_Resume
  447. OSStatus Input_Resume (void)
  448. {
  449.     return ISpResume ();
  450. }
  451.  
  452. //•    ————————————————————    Input_ShowConfigureDialog
  453. void    Input_ShowConfigureDialog (void)
  454. {
  455.     // we want to configure the mouse and keyboard, so they must be on before configure
  456.     Input_DisableKeyboardForTyping();
  457.     Input_DisableMouseForCursor();
  458.  
  459.     ISpConfigure (&Input_ISpConfigureEventProc);
  460.     
  461.     // restore the mouse and keyboard, so we can use for MacOS things
  462.     Input_EnableKeyboardForTyping();
  463.     Input_EnableMouseForCursor();
  464. }
  465.  
  466. //•    ————————————————————    Input_ISpConfigureEventProc (private)
  467. Boolean  Input_ISpConfigureEventProc (EventRecord * inEvent)
  468. {
  469. #pragma unused(inEvent)
  470.     // maintain network connections, etc here
  471.     
  472.     return false;
  473. }
  474.  
  475.  
  476. //•    ————————————————————    Input_GetButtonEvents
  477. void    Input_GetButtonEvents (Input_GameState * gameState)
  478. {
  479.     OSStatus            error = noErr;
  480.     ISpElementEvent        event;
  481.     Boolean             wasEvent;
  482.     
  483.     
  484.     // give time to some non-interrupt driven input drivers (like speech recognition)
  485.     ISpTickle ();
  486.     
  487.     // get all pending events
  488.     do
  489.     {
  490.         error = ISpElementList_GetNextEvent (gEventsElementList, sizeof (event), &event, &wasEvent);
  491.         
  492.         if (wasEvent && !error)
  493.         {
  494.             switch (event.refCon)
  495.             {
  496.                 case kNeed_FireWeapon:
  497.                     if (event.data == kISpButtonDown)
  498.                     {
  499.                         gameState->fireWeaponState = true;
  500.                         gameState->fireWeaponCount++;
  501.                     }
  502.                     else // (event.data == kISpButtonUp)
  503.                         gameState->fireWeaponState = false;
  504.                     break;
  505.                     
  506.                 case kNeed_StartPause:
  507.                     if (event.data == kISpButtonDown)
  508.                     {
  509.                         if (!gameState->gameInProgress)
  510.                             gameState->gameInProgress = true;
  511.                         else
  512.                             gameState->gamePaused = !gameState->gamePaused;
  513.                     }
  514.                     break;
  515.                     
  516.                 case kNeed_NextWeapon:
  517.                     if (event.data == kISpButtonDown)
  518.                     {
  519.                         gameState->currentWeapon++;
  520.                         if (gameState->currentWeapon >= kWeapon_WeaponCount)
  521.                             gameState->currentWeapon = 0;
  522.                     }
  523.                     break;
  524.                     
  525.                 case kNeed_PreviousWeapon:
  526.                     if (event.data == kISpButtonDown)
  527.                     {
  528.                         gameState->currentWeapon--;
  529.                         if (gameState->currentWeapon < 0)
  530.                             gameState->currentWeapon = kWeapon_WeaponCount - 1;
  531.                     }
  532.                     break;
  533.                     
  534.                 case kNeed_Weapon_MachineGun:
  535.                     if (event.data == kISpButtonDown)
  536.                         gameState->currentWeapon = kWeapon_MachineGun;
  537.                     break;
  538.                     
  539.                 case kNeed_Weapon_Cannon:
  540.                     if (event.data == kISpButtonDown)
  541.                         gameState->currentWeapon = kWeapon_Cannon;
  542.                     break;
  543.                     
  544.                 case kNeed_Weapon_Laser:
  545.                     if (event.data == kISpButtonDown)
  546.                         gameState->currentWeapon = kWeapon_Laser;
  547.                     break;
  548.                     
  549.                 case kNeed_Weapon_Missle:
  550.                     if (event.data == kISpButtonDown)
  551.                         gameState->currentWeapon = kWeapon_Missle;
  552.                     break;
  553.                     
  554.                 case kNeed_Weapon_PrecisionBomb:
  555.                     if (event.data == kISpButtonDown)
  556.                         gameState->currentWeapon = kWeapon_PrecisionBomb;
  557.                     break;
  558.                     
  559.                 case kNeed_Weapon_ClusterBomb:
  560.                     if (event.data == kISpButtonDown)
  561.                         gameState->currentWeapon = kWeapon_ClusterBomb;
  562.                     break;
  563.                     
  564.                 case kNeed_Quit:
  565.                     gameState->gameInProgress = false;
  566.                     break;
  567.             }
  568.         }
  569.     }
  570.     while (wasEvent && !error);
  571. }
  572.  
  573. //•    ————————————————————    Input_PollAxisValues
  574. void    Input_PollAxisValues (Input_GameState * gameState)
  575. {
  576.     Input_GetRoll (gameState);
  577.     Input_GetPitch (gameState);
  578.     Input_GetYaw (gameState);
  579.     Input_GetThrottle (gameState);
  580. }
  581.  
  582. //•    ————————————————————    Input_GetRoll
  583. void    Input_GetRoll (Input_GameState * gameState)
  584. {
  585.     OSStatus            error = noErr;
  586.     ISpElementEvent        event;
  587.     Boolean             wasEvent;
  588.     ISpAxisData            axisValue;
  589.     SInt32                rollValue = gameState->rollInput;
  590.     
  591.     // we check the axis, to see if _it_ was moved, if so, we use that value
  592.     error = ISpElement_GetNextEvent (gInputElements[kNeed_Roll], sizeof (event), &event, &wasEvent);
  593.     if (!error && wasEvent)
  594.     {
  595.         error = ISpElement_GetSimpleState(gInputElements[kNeed_Roll], &axisValue);
  596.         if (!error) 
  597.             rollValue = ISpAxisToSampleAxis (axisValue, kMin_Roll, kMax_Roll);
  598.  
  599.         ISpElement_Flush(gInputElements[kNeed_Roll]);
  600.     }
  601.     
  602.     gameState->rollInput = rollValue;
  603.     
  604.     //• also check the delta values
  605.     gameState->deltaRoll = 0;
  606.     do
  607.     {
  608.         error = ISpElement_GetNextEvent (gInputElements[kNeed_Roll_AsDelta], sizeof (event), &event, &wasEvent);
  609.         if (wasEvent && !error)
  610.             gameState->deltaRoll += (Fixed) event.data;
  611.     }
  612.     while (wasEvent && !error);
  613. }
  614.  
  615. //•    ————————————————————    Input_GetPitch
  616. void    Input_GetPitch (Input_GameState * gameState)
  617. {
  618.     OSStatus            error = noErr;
  619.     ISpElementEvent        event;
  620.     Boolean             wasEvent;
  621.     ISpAxisData            axisValue;
  622.     SInt32                pitchValue = gameState->pitchInput;
  623.  
  624.     // we check the axis, to see if _it_ was moved, if so, we use that value
  625.     error = ISpElement_GetNextEvent (gInputElements[kNeed_Pitch], sizeof (event), &event, &wasEvent);
  626.     if (!error && wasEvent)
  627.     {
  628.         error = ISpElement_GetSimpleState(gInputElements[kNeed_Pitch], &axisValue);
  629.         if (!error) 
  630.             pitchValue = ISpAxisToSampleAxis (axisValue, kMin_Pitch, kMax_Pitch);
  631.  
  632.         ISpElement_Flush(gInputElements[kNeed_Pitch]);
  633.     }
  634.     
  635.     gameState->pitchInput = pitchValue;
  636.     
  637.     //• also check the delta values
  638.     gameState->deltaPitch = 0;
  639.     do
  640.     {
  641.         error = ISpElement_GetNextEvent (gInputElements[kNeed_Pitch_AsDelta], sizeof (event), &event, &wasEvent);
  642.         if (wasEvent && !error)
  643.             gameState->deltaPitch += (Fixed) event.data;
  644.     }
  645.     while (wasEvent && !error);
  646. }
  647.  
  648. //•    ————————————————————    Input_GetYaw
  649. void    Input_GetYaw (Input_GameState * gameState)
  650. {
  651.     OSStatus            error = noErr;
  652.     ISpElementEvent        event;
  653.     Boolean             wasEvent;
  654.     ISpAxisData            axisValue;
  655.     SInt32                yawValue = gameState->yawInput;
  656.     
  657.     // we check the axis, to see if _it_ was moved, if so, we use that value
  658.     error = ISpElement_GetNextEvent (gInputElements[kNeed_Yaw], sizeof (event), &event, &wasEvent);
  659.     if (!error && wasEvent)
  660.     {
  661.         // we wish to ignore all button presses _prior_ to this moment
  662.         ISpElementList_Flush(gYawElementList);
  663.  
  664.         // get the current value
  665.         error = ISpElement_GetSimpleState(gInputElements[kNeed_Yaw], &axisValue);
  666.         if (!error) 
  667.             yawValue = ISpAxisToSampleAxis (axisValue, kMin_Yaw, kMax_Yaw);
  668.  
  669.         ISpElement_Flush(gInputElements[kNeed_Yaw]);
  670.     }
  671.     // otherwise, we check to see if one of the yaw buttons was pressed
  672.     else do
  673.     {
  674.         error = ISpElementList_GetNextEvent (gYawElementList, sizeof (event), &event, &wasEvent);
  675.         
  676.         // only process valid keydown events (all the yaw events ignore button ups)
  677.         if (wasEvent && !error && (event.data == kISpButtonDown))
  678.         {
  679.             switch (event.refCon)
  680.             {
  681.                 case kNeed_Yaw_Left:
  682.                     yawValue -= kIncrement_Yaw;
  683.                     if (yawValue < kMin_Yaw) yawValue = kMin_Yaw; 
  684.                     break;
  685.                 case kNeed_Yaw_Center:
  686.                     yawValue = kMin_Yaw + ((kMax_Yaw - kMin_Yaw) / 2);
  687.                     break;
  688.                 case kNeed_Yaw_Right:
  689.                     yawValue += kIncrement_Yaw;
  690.                     if (yawValue > kMax_Yaw) yawValue = kMax_Yaw; 
  691.                     break;
  692.             }
  693.         }
  694.     }
  695.     while (wasEvent && !error);
  696.     
  697.     gameState->yawInput = yawValue;
  698.     
  699.     //• also check the delta values
  700.     gameState->deltaYaw = 0;
  701.     do
  702.     {
  703.         error = ISpElement_GetNextEvent (gInputElements[kNeed_Yaw_AsDelta], sizeof (event), &event, &wasEvent);
  704.         if (wasEvent && !error)
  705.             gameState->deltaYaw += (Fixed) event.data;
  706.     }
  707.     while (wasEvent && !error);
  708. }
  709.  
  710. //•    ————————————————————    Input_GetThrottle
  711. void    Input_GetThrottle (Input_GameState * gameState)
  712. {
  713.     OSStatus            error = noErr;
  714.     ISpElementEvent        event;
  715.     Boolean             wasEvent;
  716.     ISpAxisData            axisValue;
  717.     SInt32                throttleValue = gameState->throttleInput;
  718.     
  719.     // we check the axis, to see if _it_ was moved, if so, we use that value
  720.     error = ISpElement_GetNextEvent (gInputElements[kNeed_Throttle], sizeof (event), &event, &wasEvent);
  721.     if (!error && wasEvent)
  722.     {
  723.         // we wish to ignore all button presses _prior_ to this moment
  724.         ISpElementList_Flush(gThrottleElementList);
  725.  
  726.         // get the current value
  727.         error = ISpElement_GetSimpleState(gInputElements[kNeed_Throttle], &axisValue);
  728.         if (!error) 
  729.             throttleValue = ISpAxisToSampleAxis (axisValue, kMin_Throttle, kMax_Throttle);
  730.  
  731.         ISpElement_Flush(gInputElements[kNeed_Throttle]);
  732.     }
  733.     // otherwise, we check to see if one of the throttle buttons was pressed
  734.     else do
  735.     {
  736.         error = ISpElementList_GetNextEvent (gThrottleElementList, sizeof (event), &event, &wasEvent);
  737.         
  738.         // only process valid keydown events (all the throttle events ignore button ups)
  739.         if (wasEvent && !error && (event.data == kISpButtonDown))
  740.         {
  741.             switch (event.refCon)
  742.             {
  743.                 case kNeed_Throttle_Min:
  744.                     throttleValue = kMin_Throttle;
  745.                     break;
  746.                 case kNeed_Throttle_Decrease:
  747.                     throttleValue -= kIncrement_Throttle;
  748.                     if (throttleValue < kMin_Throttle) throttleValue = kMin_Throttle; 
  749.                     break;
  750.                 case kNeed_Throttle_Increase:
  751.                     throttleValue += kIncrement_Throttle;
  752.                     if (throttleValue > kMax_Throttle) throttleValue = kMax_Throttle; 
  753.                     break;
  754.                 case kNeed_Throttle_Max:
  755.                     throttleValue = kMax_Throttle;
  756.                     break;
  757.             }
  758.         }
  759.     }
  760.     while (wasEvent && !error);
  761.     
  762.     gameState->throttleInput = throttleValue;
  763. }
  764.  
  765.  
  766. //•    ————————————————————    Input_EnableKeyboardForTyping
  767. void    Input_EnableKeyboardForTyping (void)
  768. {
  769.     // Note, deactivating inside ISp means we can use for normal MacOS
  770.     if (!gKeyboardTypingEnabled)
  771.         ISpDevices_DeactivateClass (kISpDeviceClass_Keyboard);
  772.     
  773.     gKeyboardTypingEnabled = true;
  774. }
  775.  
  776. //•    ————————————————————    Input_DisableKeyboardForTyping
  777. void    Input_DisableKeyboardForTyping (void)
  778. {
  779.     // Note, activating inside ISp means unavailable for normal MacOS
  780.     if (gKeyboardTypingEnabled)
  781.         ISpDevices_ActivateClass (kISpDeviceClass_Keyboard);
  782.     
  783.     gKeyboardTypingEnabled = false;
  784. }
  785.  
  786.  
  787. //•    ————————————————————    Input_EnableMouseForCursor
  788. void    Input_EnableMouseForCursor (void)
  789. {
  790.     // Note, deactivating inside ISp means we can use for normal MacOS
  791.     if (!gMouseAsMacOSCursorEnabled)
  792.         ISpDevices_DeactivateClass (kISpDeviceClass_Mouse);
  793.     
  794.     gMouseAsMacOSCursorEnabled = true;
  795. }
  796.  
  797. //•    ————————————————————    Input_DisableMouseForCursor
  798. void    Input_DisableMouseForCursor (void)
  799. {
  800.     // Note, activating inside ISp means unavailable for normal MacOS
  801.     if (gMouseAsMacOSCursorEnabled)
  802.         ISpDevices_ActivateClass (kISpDeviceClass_Mouse);
  803.     
  804.     gMouseAsMacOSCursorEnabled = false;
  805. }
  806.  
  807. //•    ————————————————————    ISpAxisToSampleAxis
  808. SInt32    ISpAxisToSampleAxis (ISpAxisData axisValue, SInt32 min, SInt32 max)
  809. {
  810.     UInt32 divisor = kISpAxisMaximum / (max - min);
  811.     
  812.     return ((axisValue / divisor) + min);
  813. }
  814.