DIFF1.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:26k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /**************************************************************************
  2.     DIFF1.CPP - DirectInput simple force feedback sample 1
  3.     Demonstrates an application which plays a force on the joystick
  4.     in response to mouse clicks.
  5.  **************************************************************************/
  6. /**************************************************************************
  7.     (C) Copyright 1997 Microsoft Corp.  All rights reserved.
  8.     You have a royalty-free right to use, modify, reproduce and
  9.     distribute the Sample Files (and/or any modified version) in
  10.     any way you find useful, provided that you agree that
  11.     Microsoft has no warranty obligations or liability for any
  12.     Sample Application Files which are modified.
  13.  **************************************************************************/
  14. #include "diff1.h"
  15. #include <windowsx.h>
  16. #include <dinput.h>
  17. #include <math.h>
  18. /****************************************************************************
  19.  *
  20.  *      Global variables
  21.  *
  22.  ****************************************************************************/
  23. char c_szClassName[] = "DIFF1";
  24. HINSTANCE       g_hinst;                /* My instance handle */
  25. BOOL            g_fPaused = TRUE;       /* Should I be paused? */
  26. int             g_xForce;               /* Coordinates of the active force */
  27. int             g_yForce;
  28. int             g_cxClient;             /* Client window size */
  29. int             g_cyClient;
  30. /****************************************************************************
  31.  *
  32.  *      DirectInput globals
  33.  *
  34.  ****************************************************************************/
  35. LPDIRECTINPUT           g_pdi;
  36. LPDIRECTINPUTDEVICE2    g_pJoystick;
  37. LPDIRECTINPUTEFFECT     g_pEffect;
  38. /****************************************************************************
  39.  *
  40.  *      Complain
  41.  *
  42.  *      Whine and moan.
  43.  *
  44.  ****************************************************************************/
  45. void
  46. Complain(
  47.     HWND hwndOwner,
  48.     HRESULT hr,
  49.     LPCSTR pszMessage
  50. )
  51. {
  52.     MessageBox(hwndOwner, pszMessage, "DirectInput Sample", MB_OK);
  53. }
  54. /****************************************************************************
  55.  *
  56.  *      EnumFFJoysticksCallback
  57.  *
  58.  *      Called once for each enumerated force feedback joystick.
  59.  *
  60.  *      If we find one, create a device interface on it so we can
  61.  *      play with it.
  62.  *
  63.  *      Parameters:
  64.  *
  65.  *          pinst
  66.  *
  67.  *              Pointer to DIDEVICEINSTANCE structure which describes
  68.  *              the device.
  69.  *
  70.  *          lpvContext
  71.  *
  72.  *              The pointer we passed to EnumDevices which we don't
  73.  *              use for anything.
  74.  *
  75.  ****************************************************************************/
  76. BOOL CALLBACK
  77. EnumFFJoysticksCallback(LPCDIDEVICEINSTANCE pinst, LPVOID lpvContext)
  78. {
  79.     HRESULT hr;
  80.     LPDIRECTINPUTDEVICE pdev;
  81.     LPDIRECTINPUTDEVICE2 pdev2;
  82.     /*
  83.      *  Obtain an interface to the enumerated force feedback joystick.
  84.      *
  85.      *  Parameters:
  86.      *
  87.      *      pinst->guidInstance
  88.      *
  89.      *          The instance GUID for the device we wish to access.
  90.      *
  91.      *      &pdev
  92.      *
  93.      *          Receives pointer to the IDirectInputDevice interface
  94.      *          that was created.
  95.      *
  96.      *      NULL
  97.      *
  98.      *          We do not use OLE aggregation, so this parameter
  99.      *          must be NULL.
  100.      *
  101.      */
  102.     hr = g_pdi->CreateDevice(pinst->guidInstance, &pdev, NULL);
  103.     /*
  104.      *  If it failed, then we can't use this joystick for some
  105.      *  bizarre reason.  (Maybe the user unplugged it while we
  106.      *  were in the middle of enumerating it.)
  107.      *
  108.      *  Continue enumerating; maybe we'll have better luck with the
  109.      *  next one.
  110.      */
  111.     if (FAILED(hr)) {
  112.         return DIENUM_CONTINUE;
  113.     }
  114.     /*
  115.      *  We really want to use IDirectInputDevice2, so move there
  116.      *  once and for all.
  117.      *
  118.      *  Parameters:
  119.      *
  120.      *      IID_IDirectInputDevice2
  121.      *
  122.      *          The interface we are requesting.
  123.      *
  124.      *      &pdev2
  125.      *
  126.      *          Receives a pinter to the new interface.
  127.      */
  128.     hr = pdev->QueryInterface(IID_IDirectInputDevice2,
  129.                               (LPVOID *)&pdev2);
  130.     /*
  131.      *  Whether or not the QueryInterface worked, we are finished
  132.      *  with the old interface.
  133.      */
  134.     pdev->Release();
  135.     /*
  136.      *  If the QueryInterface failed, then something weird happened.
  137.      *  Maybe the currently-installed version of DirectInput doesn't
  138.      *  support force feedback.
  139.      *
  140.      *  Continue enumerating; maybe we'll have better luck with the
  141.      *  next one.
  142.      */
  143.     if (FAILED(hr)) {
  144.         return DIENUM_CONTINUE;
  145.     }
  146.     /*
  147.      *  We successfully created an IDirectInputDevice2.
  148.      *
  149.      *  No point in looking for another one.
  150.      */
  151.     g_pJoystick = pdev2;
  152.     return DIENUM_STOP;
  153. }
  154. /****************************************************************************
  155.  *
  156.  *      DIInit
  157.  *
  158.  *      Initialize the DirectInput variables.
  159.  *
  160.  *      This entails the following four functions:
  161.  *
  162.  *          DirectInputCreate
  163.  *          IDirectInput::EnumDevices           (to find a joystick)
  164.  *          IDirectInputDevice2::SetDataFormat
  165.  *          IDirectInputDevice2::SetCooperativeLevel
  166.  *          IDirectInputDevice2::SetProperty    (to disable auto-center)
  167.  *          IDirectInputDevice2::CreateEffect
  168.  *
  169.  ****************************************************************************/
  170. BOOL
  171. DIInit(HWND hwnd)
  172. {
  173.     HRESULT hr;
  174.     /*
  175.      *  Register with the DirectInput subsystem and get a pointer
  176.      *  to a IDirectInput interface we can use.
  177.      *
  178.      *  Parameters:
  179.      *
  180.      *      g_hinst
  181.      *
  182.      *          Instance handle to our application or DLL.
  183.      *
  184.      *      DIRECTINPUT_VERSION
  185.      *
  186.      *          The version of DirectInput we were designed for.
  187.      *          We take the value from the <dinput.h> header file.
  188.      *
  189.      *      &g_pdi
  190.      *
  191.      *          Receives pointer to the IDirectInput interface
  192.      *          that was created.
  193.      *
  194.      *      NULL
  195.      *
  196.      *          We do not use OLE aggregation, so this parameter
  197.      *          must be NULL.
  198.      *
  199.      */
  200.     hr = DirectInputCreate(g_hinst, DIRECTINPUT_VERSION, &g_pdi, NULL);
  201.     if (FAILED(hr)) {
  202.         Complain(hwnd, hr, "DirectInputCreate");
  203.         return FALSE;
  204.     }
  205.     /*
  206.      *  Look for a force feedback joystick we can use for this
  207.      *  sample program.
  208.      *
  209.      *  Parameters:
  210.      *
  211.      *      DIDEVTYPE_JOYSTICK
  212.      *
  213.      *          Enumerate only joystick devices.
  214.      *
  215.      *      EnumFFJoysticksCallback
  216.      *
  217.      *          Callback function that is called once for
  218.      *          each force feedback joystick found.
  219.      *
  220.      *      NULL
  221.      *
  222.      *          Context which is passed to the callback function.
  223.      *
  224.      *      DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK
  225.      *
  226.      *          Flags that further restrict the enumeration.
  227.      *
  228.      *          We are interested only in attached joysticks
  229.      *          which support force feedback.
  230.      */
  231.     hr = g_pdi->EnumDevices(DIDEVTYPE_JOYSTICK,
  232.                             EnumFFJoysticksCallback,
  233.                             NULL,
  234.                             DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK);
  235.     if (g_pJoystick == NULL) {
  236.         Complain(hwnd, hr, "Couldn't find any force feedback joysticks");
  237.         return FALSE;
  238.     }
  239.     /*
  240.      *  Set the data format to "simple joystick format".
  241.      *
  242.      *  A data format specifies which controls on a device we
  243.      *  are interested in, and how they should be reported.
  244.      *
  245.      *  This tells DirectInput that we will be passing a
  246.      *  DIJOYSTATE structure to IDirectInputDevice2::GetDeviceState.
  247.      *  Even though we won't actually do it in this sample.
  248.      *  But setting the data format is important so that
  249.      *  the DIJOFS_* values work properly.
  250.      *
  251.      *  Parameters:
  252.      *
  253.      *      c_dfDIJoystick
  254.      *
  255.      *          Predefined data format which describes
  256.      *          a DIJOYSTATE structure.
  257.      */
  258.     hr = g_pJoystick->SetDataFormat(&c_dfDIJoystick);
  259.     if (FAILED(hr)) {
  260.         Complain(hwnd, hr, "SetDataFormat");
  261.         return FALSE;
  262.     }
  263.     /*
  264.      *  Set the cooperativity level to let DirectInput know how
  265.      *  this device should interact with the system and with other
  266.      *  DirectInput applications.
  267.      *
  268.      *  Parameters:
  269.      *
  270.      *      DISCL_EXCLUSIVE
  271.      *
  272.      *          Exclusive access is required in order to perform
  273.      *          force feedback.
  274.      *
  275.      *      DISCL_FOREGROUND
  276.      *
  277.      *          If the user switches away from our application,
  278.      *          automatically release the joystick back to the system.
  279.      *
  280.      */
  281.     hr = g_pJoystick->SetCooperativeLevel(hwnd,
  282.                                           DISCL_EXCLUSIVE | DISCL_FOREGROUND);
  283.     if (FAILED(hr)) {
  284.         Complain(hwnd, hr, "SetCooperativeLevel");
  285.         return FALSE;
  286.     }
  287.     /*
  288.      *  Since we will be playing force feedback effects,
  289.      *  we should disable the auto-centering spring.
  290.      *
  291.      *  DIPROPDWORD::diph.dwSize
  292.      *
  293.      *      Must be sizeof(DIPROPDWORD)
  294.      *
  295.      *  DIPROPDWORD::diph.dwHeaderSize
  296.      *
  297.      *      Must be sizeof(DIPROPHEADER)
  298.      *
  299.      *  DIPROPDWORD::diph.dwObj
  300.      *
  301.      *      Must be zero for device properties.
  302.      *
  303.      *  DIPROPDWORD::diph.dwHow
  304.      *
  305.      *      DIPH_DEVICE for device properties.
  306.      *
  307.      *  DIPROPDWORD::dwData
  308.      *
  309.      *      FALSE to disable auto-centering.
  310.      */
  311.     DIPROPDWORD dipdw;
  312.     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  313.     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  314.     dipdw.diph.dwObj = 0;
  315.     dipdw.diph.dwHow = DIPH_DEVICE;
  316.     dipdw.dwData = FALSE;
  317.     hr = g_pJoystick->SetProperty(DIPROP_AUTOCENTER, &dipdw.diph);
  318.     if (FAILED(hr)) {
  319.         Complain(hwnd, hr, "SetProperty(Autocenter)");
  320.         return FALSE;
  321.     }
  322.     /*
  323.      *  This application needs only one effect:  Applying raw forces.
  324.      *
  325.      *  DIEFFECT::dwSize
  326.      *
  327.      *          Must be sizeof(DIEFFECT).
  328.      *
  329.      *  DIEFFECT::dwFlags
  330.      *
  331.      *          DIEFF_CARTESIAN because we will be applying X and Y
  332.      *          forces, not angles.
  333.      *
  334.      *          DIEFF_OBJECTOFFSETS because we will be using the
  335.      *          DIJOFS_* macros to specify the axes.
  336.      *
  337.      *  DIEFFECT::dwDuration
  338.      *
  339.      *          INFINITE because we want the force to continue playing
  340.      *          indefinitely until we explicitly change it.
  341.      *
  342.      *  DIEFFECT::dwSamplePeriod
  343.      *
  344.      *          0 means "use default".  Using a custom sample period
  345.      *          is a special effect which we don't particularly care
  346.      *          about.
  347.      *
  348.      *  DIEFFECT::dwGain
  349.      *
  350.      *          DI_FFNOMINALMAX to play all values at exactly the
  351.      *          strength we specify.
  352.      *
  353.      *  DIEFFECT::dwTriggerButton
  354.      *
  355.      *          DIEB_NOTRIGGER because we don't want this effect
  356.      *          to be associated with a trigger.
  357.      *
  358.      *  DIEFFECT::dwTriggerRepeatInterval
  359.      *
  360.      *          0 because there no trigger.
  361.      *
  362.      *  DIEFFECT::cAxes
  363.      *
  364.      *          2 because we have two axes, X and Y.
  365.      *
  366.      *  DIEFFECT::rgdwAxes
  367.      *
  368.      *          Points to an array which identifies the two axes
  369.      *          we want to talk to, namely X and Y.
  370.      *
  371.      *  DIEFFECT::rglDirection
  372.      *
  373.      *          Points to an array which gives the direction in
  374.      *          which the force should be applied.
  375.      *          Nothing yet.
  376.      *
  377.      *  DIEFFECT::lpEnvelope
  378.      *
  379.      *          NULL because we don't want to apply an envelope
  380.      *          to the effect.
  381.      *
  382.      *  DIEFFECT::cbTypeSpecificParameters
  383.      *  DIEFFECT::lpvTypeSpecificParameters
  384.      *
  385.      *          Size of and pointer to type-specific parameters.
  386.      *          For a constant force effect, we need a
  387.      *          DICONSTANTFORCE structure.
  388.      */
  389.     DIEFFECT eff;
  390.     DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y };
  391.     LONG rglDirection[2] = { 0, 0 };
  392.     DICONSTANTFORCE cf = { 0 };
  393.     eff.dwSize = sizeof(DIEFFECT);
  394.     eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
  395.     eff.dwDuration = INFINITE;
  396.     eff.dwSamplePeriod = 0;
  397.     eff.dwGain = DI_FFNOMINALMAX;
  398.     eff.dwTriggerButton = DIEB_NOTRIGGER;
  399.     eff.dwTriggerRepeatInterval = 0;
  400.     eff.cAxes = 2;
  401.     eff.rgdwAxes = rgdwAxes;
  402.     eff.rglDirection = rglDirection;
  403.     eff.lpEnvelope = 0;
  404.     eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
  405.     eff.lpvTypeSpecificParams = &cf;
  406.     /*
  407.      *  Now create this effect we prepared.
  408.      *
  409.      *  Parameters:
  410.      *
  411.      *      GUID_ConstantForce
  412.      *
  413.      *          We are playing a raw force, plain and simple.
  414.      *
  415.      *      &eff
  416.      *
  417.      *          The DIEFFECT structure that describes it.
  418.      *
  419.      *      &g_pEffect
  420.      *
  421.      *          Receives pointer to the IDirectInputEffect interface
  422.      *          that was created.
  423.      *
  424.      *      NULL
  425.      *
  426.      *          We do not use OLE aggregation, so this parameter
  427.      *          must be NULL.
  428.      *
  429.      */
  430.     hr = g_pJoystick->CreateEffect(GUID_ConstantForce,
  431.                                    &eff,
  432.                                    &g_pEffect,
  433.                                    NULL);
  434.     if (FAILED(hr)) {
  435.         Complain(hwnd, hr, "CreateEffect");
  436.         return FALSE;
  437.     }
  438.     return TRUE;
  439. }
  440. /****************************************************************************
  441.  *
  442.  *      DITerm
  443.  *
  444.  *      Terminate our usage of DirectInput.
  445.  *
  446.  ****************************************************************************/
  447. void
  448. DITerm(void)
  449. {
  450.     /*
  451.      *  Destroy any lingering IDirectInputEffect object.
  452.      */
  453.     if (g_pEffect) {
  454.         g_pEffect->Release();
  455.         g_pEffect = NULL;
  456.     }
  457.     /*
  458.      *  Destroy any lingering IDirectInputDevice object.
  459.      */
  460.     if (g_pJoystick) {
  461.         /*
  462.          *  Cleanliness is next to godliness.  Unacquire the device
  463.          *  one last time just in case we got really confused and tried
  464.          *  to exit while the device is still acquired.
  465.          */
  466.         g_pJoystick->Unacquire();
  467.         g_pJoystick->Release();
  468.         g_pJoystick = NULL;
  469.     }
  470.     /*
  471.      *  Destroy any lingering IDirectInput object.
  472.      */
  473.     if (g_pdi) {
  474.         g_pdi->Release();
  475.         g_pdi = NULL;
  476.     }
  477. }
  478. /****************************************************************************
  479.  *
  480.  *      joySetForcesXY
  481.  *
  482.  *      Apply the X and Y forces to the effect we prepared.
  483.  *
  484.  *      Parameters:
  485.  *
  486.  *          peff
  487.  *
  488.  *              Pointer to a constant-force LPDIRECTINPUEFFECT
  489.  *              which we will push in the appropriate direction
  490.  *              with the appropriate amount of force.
  491.  *
  492.  *          x, y
  493.  *
  494.  *              X and Y forces to apply, respectively, in the
  495.  *              range -DI_FFNOMINALMAX to +DI_FFNOMINALMAX.
  496.  *
  497.  ****************************************************************************/
  498. HRESULT
  499. joySetForcesXY(LPDIRECTINPUTEFFECT peff, int x, int y)
  500. {
  501.     HRESULT hres;
  502.     /*
  503.      *  Modifying an effect is basically the same as creating
  504.      *  a new one, except you need only specify the parameters
  505.      *  you are modifying; the rest are left alone.
  506.      *
  507.      *  DIEFFECT::dwSize
  508.      *
  509.      *          Must be sizeof(DIEFFECT).
  510.      *
  511.      *  DIEFFECT::dwFlags
  512.      *
  513.      *          DIEFF_CARTESIAN because we will be applying X and Y
  514.      *          forces, not angles.
  515.      *
  516.      *          DIEFF_OBJECTOFFSETS because we used the
  517.      *          DIJOFS_* macros to specify the axes.
  518.      *
  519.      *  DIEFFECT::cAxes
  520.      *
  521.      *          2 because we have two axes, X and Y.
  522.      *
  523.      *  DIEFFECT::rglDirection
  524.      *
  525.      *          Points to an array which gives the direction in
  526.      *          which the force should be applied.
  527.      *
  528.      *          We use the x and y values directly to specify
  529.      *          the direction.  Note that DirectInput currently
  530.      *          uses these values to specify direction only, not
  531.      *          magnitude.  Magnitude needs to be specified
  532.      *          elsewhere.  (See below.)
  533.      *
  534.      *  DIEFFECT::cbTypeSpecificParameters
  535.      *  DIEFFECT::lpvTypeSpecificParameters
  536.      *
  537.      *          Size of and pointer to type-specific parameters.
  538.      *          For a constant force effect, we need a
  539.      *          DICONSTANTFORCE structure.
  540.      *
  541.      *  DICONSTANTFORCE::lMagnitude
  542.      *
  543.      *          The total magnitude of the force, which is
  544.      *          the hypotenuse of x and y.
  545.      */
  546.     LONG rglDirection[2] = { x, y };
  547.     DICONSTANTFORCE cf;
  548.     cf.lMagnitude = (DWORD)sqrt((double)x * (double)x +
  549.                                 (double)y * (double)y);
  550.     DIEFFECT eff;
  551.     eff.dwSize = sizeof(DIEFFECT);
  552.     eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
  553.     eff.cAxes = 2;
  554.     eff.rglDirection = rglDirection;
  555.     eff.lpEnvelope = 0;
  556.     eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
  557.     eff.lpvTypeSpecificParams = &cf;
  558.     /*
  559.      *  Now set the new parameters and start the effect immediately.
  560.      *
  561.      *  Parameters:
  562.      *
  563.      *      &eff
  564.      *
  565.      *          The DIEFFECT structure that describes the new parameters.
  566.      *
  567.      *      DIEP_DIRECTION
  568.      *      DIEP_TYPESPECIFICPARAMS
  569.      *
  570.      *          We want to change the direction and the DICONSTANTFORCE.
  571.      *
  572.      *      DIEP_START
  573.      *
  574.      *          Start the effect as soon as the parameters are downloaded.
  575.      */
  576.     hres = peff->SetParameters(&eff, DIEP_DIRECTION |
  577.                                      DIEP_TYPESPECIFICPARAMS |
  578.                                      DIEP_START);
  579.     return hres;
  580. }
  581. /****************************************************************************
  582.  *
  583.  *      Ex_SyncAcquire
  584.  *
  585.  *      Acquire or unacquire the joystick, depending on the the g_fPaused
  586.  *      flag.  This synchronizes the device with our internal view of
  587.  *      the world.
  588.  *
  589.  ****************************************************************************/
  590. void
  591. Ex_SyncAcquire(HWND hwnd)
  592. {
  593.     if (g_fPaused) {
  594.         if (g_pJoystick) {
  595.             g_pJoystick->Unacquire();
  596.         }
  597.     } else {
  598.         if (g_pJoystick) g_pJoystick->Acquire();
  599.         if (g_pEffect) {
  600.             g_pEffect->Start(1, 0);
  601.         }
  602.     }
  603. }
  604. /****************************************************************************
  605.  *
  606.  *      Ex_OnSize
  607.  *
  608.  *      The window client size changed.  Remember the new size.
  609.  *
  610.  ****************************************************************************/
  611. void
  612. Ex_OnSize(HWND hwnd, UINT state, int cx, int cy)
  613. {
  614.     g_cxClient = cx;
  615.     g_cyClient = cy;
  616. }
  617. /****************************************************************************
  618.  *
  619.  *      Ex_OnPaint
  620.  *
  621.  *      Paint our little target area thingie.
  622.  *
  623.  *      We draw a small crosshairs at the center (so the user knows
  624.  *      where the center is)
  625.  *
  626.  ****************************************************************************/
  627. void
  628. Ex_OnPaint(HWND hwnd)
  629. {
  630.     PAINTSTRUCT ps;
  631.     HDC hdc = BeginPaint(hwnd, &ps);
  632.     if (hdc) {
  633.         HPEN hpenOld, hpenBlack;
  634.         HBRUSH hbrOld, hbrBlack;
  635.         int x, y;
  636.         /*
  637.          *  Everything is scaled to the size of the window.
  638.          */
  639.         hpenBlack = GetStockPen(BLACK_PEN);
  640.         hpenOld = SelectPen(hdc, hpenBlack);
  641.         x = g_cxClient / 2;
  642.         y = g_cyClient / 2;
  643.         MoveToEx(hdc, x, y - 10, NULL);
  644.         LineTo(hdc, x, y + 10 + 1);
  645.         MoveToEx(hdc, x - 10, y, NULL);
  646.         LineTo(hdc, x + 10 + 1, y);
  647.         hbrBlack = GetStockBrush(BLACK_BRUSH);
  648.         hbrOld = SelectBrush(hdc, hbrBlack);
  649.         x = MulDiv(g_cxClient, g_xForce + DI_FFNOMINALMAX, 2 * DI_FFNOMINALMAX);
  650.         y = MulDiv(g_cyClient, g_yForce + DI_FFNOMINALMAX, 2 * DI_FFNOMINALMAX);
  651.         Ellipse(hdc, x-5, y-5, x+6, y+6);
  652.         SelectBrush(hdc, hbrOld);
  653.         SelectPen(hdc, hpenOld);
  654.         EndPaint(hwnd, &ps);
  655.     }
  656. }
  657. /****************************************************************************
  658.  *
  659.  *      Ex_CoordToForce
  660.  *
  661.  *      Convert a coordinate 0 <= x <= cx to a force value
  662.  *      in the range -DI_FFNOMINALMAX to +DI_FFNOMINALMAX.
  663.  *
  664.  ****************************************************************************/
  665. int
  666. Ex_CoordToForce(int x, int cx)
  667. {
  668.     x = MulDiv(x, 2 * DI_FFNOMINALMAX, cx) - DI_FFNOMINALMAX;
  669.     if (x < -DI_FFNOMINALMAX) {
  670.         x = -DI_FFNOMINALMAX;
  671.     }
  672.     if (x > +DI_FFNOMINALMAX) {
  673.         x = +DI_FFNOMINALMAX;
  674.     }
  675.     return x;
  676. }
  677. /****************************************************************************
  678.  *
  679.  *      Ex_OnMouseMove
  680.  *
  681.  *      If the mouse button is down, then change the direction of
  682.  *      the force to match the new location.
  683.  *
  684.  ****************************************************************************/
  685. void
  686. Ex_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
  687. {
  688.     if (keyFlags & MK_LBUTTON) {
  689.         g_xForce = Ex_CoordToForce(x, g_cxClient);
  690.         g_yForce = Ex_CoordToForce(y, g_cyClient);
  691.         InvalidateRect(hwnd, 0, TRUE);
  692.         UpdateWindow(hwnd);
  693.         joySetForcesXY(g_pEffect, g_xForce, g_yForce);
  694.     }
  695. }
  696. /****************************************************************************
  697.  *
  698.  *      Ex_OnLButtonDown
  699.  *
  700.  *      Capture the mouse so we can follow it, and start updating the
  701.  *      force information.
  702.  *
  703.  ****************************************************************************/
  704. void
  705. Ex_OnLButtonDown(HWND hwnd, BOOL fDblClk, int x, int y, UINT keyFlags)
  706. {
  707.     SetCapture(hwnd);
  708.     Ex_OnMouseMove(hwnd, x, y, MK_LBUTTON);
  709. }
  710. /****************************************************************************
  711.  *
  712.  *      Ex_OnLButtonUp
  713.  *
  714.  *      Stop capturing the mouse when the button goes up.
  715.  *
  716.  ****************************************************************************/
  717. void
  718. Ex_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
  719. {
  720.     ReleaseCapture();
  721. }
  722. /****************************************************************************
  723.  *
  724.  *      Ex_WndProc
  725.  *
  726.  *      Window procedure for simple force feedback sample.
  727.  *
  728.  ****************************************************************************/
  729. LRESULT CALLBACK
  730. Ex_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  731. {
  732.     switch (msg) {
  733.     HANDLE_MSG(hwnd, WM_PAINT, Ex_OnPaint);
  734.     HANDLE_MSG(hwnd, WM_MOUSEMOVE, Ex_OnMouseMove);
  735.     HANDLE_MSG(hwnd, WM_LBUTTONDOWN, Ex_OnLButtonDown);
  736.     HANDLE_MSG(hwnd, WM_LBUTTONUP, Ex_OnLButtonUp);
  737.     HANDLE_MSG(hwnd, WM_SIZE, Ex_OnSize);
  738.     /*
  739.      *  WM_ACTIVATE
  740.      *
  741.      *      Windows sends this message when the window becomes
  742.      *      the active window or stops being the active window.
  743.      *
  744.      *      wParam = WA_INACTIVE if window is no longer active
  745.      *
  746.      *      wParam = WA_ACTIVE or WA_CLICKACTIVE if window is now active
  747.      *
  748.      *      If we are losing activation, then pause.
  749.      *
  750.      *      If we are gaining activation, then unpause.
  751.      *
  752.      *      After deciding whether we are paused or unpaused,
  753.      *      tell DirectInput that we don't (paused) or do (unpaused)
  754.      *      want access to the joystick.
  755.      *
  756.      */
  757.     case WM_ACTIVATE:
  758.         g_fPaused = wParam == WA_INACTIVE;
  759.         Ex_SyncAcquire(hwnd);
  760.         break;
  761.     case WM_DESTROY:
  762.         PostQuitMessage(0);
  763.         break;
  764.     }
  765.     return DefWindowProc(hwnd, msg, wParam, lParam);
  766. }
  767. /****************************************************************************
  768.  *
  769.  *      AppInit
  770.  *
  771.  *      Set up everything the application needs to get started.
  772.  *
  773.  ****************************************************************************/
  774. HWND
  775. AppInit(
  776.     HINSTANCE hinst,
  777.     int nCmdShow
  778. )
  779. {
  780.     /*
  781.      *  Save instance handle for future reference.
  782.      */
  783.     g_hinst = hinst;
  784.     /*
  785.      *  Set up the window class.
  786.      */
  787.     WNDCLASS wc;
  788.     wc.hCursor        = LoadCursor(0, IDC_ARROW);
  789.     wc.hIcon          = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION));
  790.     wc.lpszMenuName   = NULL;
  791.     wc.lpszClassName  = c_szClassName;
  792.     wc.hbrBackground  = GetStockBrush(WHITE_BRUSH);
  793.     wc.hInstance      = hinst;
  794.     wc.style          = CS_HREDRAW | CS_VREDRAW;
  795.     wc.lpfnWndProc    = Ex_WndProc;
  796.     wc.cbClsExtra     = 0;
  797.     wc.cbWndExtra     = 0;
  798.     if (!RegisterClass(&wc)) {
  799.         return NULL;
  800.     }
  801.     HWND hwnd = CreateWindow(
  802.                     c_szClassName,                  // Class name
  803.                     "DIFF1 - Click in target to change force value", // Caption
  804.                     WS_OVERLAPPEDWINDOW,            // Style
  805.                     CW_USEDEFAULT, CW_USEDEFAULT,   // Position
  806.                     CW_USEDEFAULT, CW_USEDEFAULT,   // Size
  807.                     NULL,                           // No parent
  808.                     NULL,                           // No menu
  809.                     g_hinst,                        // inst handle
  810.                     0                               // no params
  811.                     );
  812.     if (!DIInit(hwnd)) {
  813.         DestroyWindow(hwnd);
  814.         return NULL;
  815.     }
  816.     ShowWindow(hwnd, nCmdShow);
  817.     return hwnd;
  818. }
  819. /****************************************************************************
  820.  *
  821.  *      WinMain
  822.  *
  823.  *      Application entry point.
  824.  *
  825.  ****************************************************************************/
  826. int PASCAL
  827. WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR szCmdLine, int nCmdShow)
  828. {
  829.     MSG msg;
  830.     msg.wParam = 0;         /* In case something goes horribly wrong */
  831.     HWND hwnd = AppInit(hinst, nCmdShow);
  832.     if (hwnd) {
  833.         /*
  834.          *  Standard message loop.
  835.          */
  836.         while (GetMessage(&msg, NULL, 0, 0)) {
  837.             TranslateMessage(&msg);
  838.             DispatchMessage(&msg);
  839.         }
  840.     }
  841.     DITerm();
  842.     return msg.wParam;
  843. }