AsphyreJoystick.pas
上传用户:ctlcnc
上传日期:2021-12-10
资源大小:4933k
文件大小:14k
源码类别:

2D图形编程

开发平台:

Delphi

  1. unit AsphyreJoystick;
  2. //---------------------------------------------------------------------------
  3. // AsphyreJoystick.pas                                  Modified: 28-Jan-2007
  4. // Joystick/Gamepad DirectInput wrapper for Asphyre              Version 1.04
  5. //---------------------------------------------------------------------------
  6. // Important Notice:
  7. //
  8. // If you modify/use this code or one of its parts either in original or
  9. // modified form, you must comply with Mozilla Public License v1.1,
  10. // specifically section 3, "Distribution Obligations". Failure to do so will
  11. // result in the license breach, which will be resolved in the court.
  12. // Remember that violating author's rights is considered a serious crime in
  13. // many countries. Thank you!
  14. //
  15. // !! Please *read* Mozilla Public License 1.1 document located at:
  16. //  http://www.mozilla.org/MPL/
  17. //
  18. // If you require any clarifications about the license, feel free to contact
  19. // us or post your question on our forums at: http://www.afterwarp.net
  20. //---------------------------------------------------------------------------
  21. // The contents of this file are subject to the Mozilla Public License
  22. // Version 1.1 (the "License"); you may not use this file except in
  23. // compliance with the License. You may obtain a copy of the License at
  24. // http://www.mozilla.org/MPL/
  25. //
  26. // Software distributed under the License is distributed on an "AS IS"
  27. // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  28. // License for the specific language governing rights and limitations
  29. // under the License.
  30. //
  31. // The Original Code is AsphyreJoystick.pas.
  32. //
  33. // The Initial Developer of the Original Code is M. Sc. Yuriy Kotsarenko.
  34. // Portions created by M. Sc. Yuriy Kotsarenko are Copyright (C) 2007,
  35. // Afterwarp Interactive. All Rights Reserved.
  36. //---------------------------------------------------------------------------
  37. interface
  38. //---------------------------------------------------------------------------
  39. uses
  40.  Windows, DirectInput, AsphyreAsserts;
  41. //---------------------------------------------------------------------------
  42. type
  43.  TAsphyreJoysticks = class;
  44. //---------------------------------------------------------------------------
  45.  TAsphyreJoystick = class
  46.  private
  47.   FOwner: TAsphyreJoysticks;
  48.   
  49.   FInitialized: Boolean;
  50.   FInputDevice: IDirectInputDevice8;
  51.   FJoyState   : TDIJoyState2;
  52.   FButtonCount: Integer;
  53.   FAxisCount  : Integer;
  54.   FPOVCount   : Integer;
  55.   FDeviceCaps : TDIDevCaps;
  56.   FForeground : Boolean;
  57.   procedure SetForeground(const Value: Boolean);
  58.  public
  59.   property Owner: TAsphyreJoysticks read FOwner;
  60.   
  61.   property Initialized: Boolean read FInitialized;
  62.   property InputDevice: IDirectInputDevice8 read FInputDevice;
  63.   property DeviceCaps : TDIDevCaps read FDeviceCaps;
  64.   property JoyState   : TDIJoyState2 read FJoyState;
  65.   property Foreground : Boolean read FForeground write SetForeground;
  66.   property ButtonCount: Integer read FButtonCount;
  67.   property AxisCount  : Integer read FAxisCount;
  68.   property POVCount   : Integer read FPOVCount;
  69.   function Initialize(ddi: PDIDeviceInstance; hWnd: Integer): Boolean;
  70.   procedure Finalize();
  71.   function Poll(): Boolean;
  72.   constructor Create(AOwner: TAsphyreJoysticks);
  73.   destructor Destroy(); override;
  74.  published
  75.  end;
  76. //---------------------------------------------------------------------------
  77.  TAsphyreJoysticks = class
  78.  private
  79.   FOwnerInput: TObject;
  80.   Data: array of TAsphyreJoystick;
  81.   FForeground : Boolean;
  82.   FInitialized: Boolean;
  83.   function GetCount(): Integer;
  84.   function GetJoystick(Num: Integer): TAsphyreJoystick;
  85.   procedure ReleaseJoysticks();
  86.  protected
  87.   function AddJoy(): TAsphyreJoystick;
  88.  public
  89.   // A reference to owner of this component; it must be TAsphyreInput.
  90.   property OwnerInput: TObject read FOwnerInput;
  91.   // Indicates whether the component has been initialized properly.
  92.   property Initialized: Boolean read FInitialized;
  93.   // This indicates whether the component should have joysticks acquired
  94.   // even when the application has no focus.
  95.   property Foreground: Boolean read FForeground write FForeground;
  96.   property Count: Integer read GetCount;
  97.   property Joystick[Num: Integer]: TAsphyreJoystick read GetJoystick; default;
  98.   function Update(): Boolean;
  99.   function Initialize(): Boolean;
  100.   procedure Finalize();
  101.   constructor Create(AOwnerInput: TObject);
  102.   destructor Destroy(); override;
  103.  end;
  104. //---------------------------------------------------------------------------
  105. implementation
  106. //---------------------------------------------------------------------------
  107. uses
  108.  AsphyreInputs;
  109. //---------------------------------------------------------------------------
  110. type
  111.  PJoysEnumRef = ^TJoysEnumRef;
  112.  TJoysEnumRef = record
  113.   Referrer: TAsphyreJoysticks;
  114.   Success : Boolean;
  115.  end;
  116. //---------------------------------------------------------------------------
  117.  PJoyEnumRef = ^TJoyEnumRef;
  118.  TJoyEnumRef = record
  119.   Referrer: TAsphyreJoystick;
  120.   Success : Boolean;
  121.  end;
  122. //---------------------------------------------------------------------------
  123. function AxisEnumCallback(var ddoi: TDIDeviceObjectInstance;
  124.  Ref: Pointer): Boolean; stdcall;
  125. var
  126.  DIPropRange: TDIPropRange;
  127.  EnumRef    : PJoyEnumRef;
  128.  Res        : Integer;
  129. begin
  130.  // (1) Retreive enumeration reference for further use.
  131.  EnumRef:= Ref;
  132.  // (2) Configure the axis.
  133.  DIPropRange.diph.dwSize:= SizeOf(TDIPropRange);
  134.  DIPropRange.diph.dwHeaderSize:= SizeOf(TDIPropHeader);
  135.  DIPropRange.diph.dwHow:= DIPH_BYID;
  136.  DIPropRange.diph.dwObj:= ddoi.dwType;
  137.  // -> use range [-32768..32767]
  138.  DIPropRange.lMin:= Low(SmallInt);
  139.  DIPropRange.lMax:= High(SmallInt);
  140.  // (3) Set axis properties.
  141.  Res:= EnumRef.Referrer.InputDevice.SetProperty(DIPROP_RANGE,
  142.   DIPropRange.diph);
  143.  if (Res <> DI_OK) then
  144.   begin
  145.    Result:= DIENUM_STOP;
  146.    EnumRef.Success:= False;
  147.   end else Result:= DIENUM_CONTINUE;
  148. end;
  149. //---------------------------------------------------------------------------
  150. function JoyEnumCallback(ddi: PDIDeviceInstance;
  151.  Ref: Pointer): Boolean; stdcall;
  152. var
  153.  EnumRef : PJoysEnumRef;
  154.  Joystick: TAsphyreJoystick;
  155. begin
  156.  // (1) Retreive enumeration reference for further use.
  157.  EnumRef:= Ref;
  158.  // (2) Create new TJoystick class.
  159.  Joystick:= EnumRef.Referrer.AddJoy();
  160.  // (3) Initialize the created joystick.
  161.  EnumRef.Success:= Joystick.Initialize(ddi,
  162.   TAsphyreInput(EnumRef.Referrer.FOwnerInput).WindowHandle);
  163.  if (not EnumRef.Success) then
  164.   Result:= DIENUM_STOP else Result:= DIENUM_CONTINUE;
  165. end;
  166. //---------------------------------------------------------------------------
  167. constructor TAsphyreJoystick.Create(AOwner: TAsphyreJoysticks);
  168. begin
  169.  inherited Create();
  170.  FOwner:= AOwner;
  171.  Assert(FOwner <> nil, msgNoOwnerSpecified);
  172.  FInitialized:= False;
  173.  FForeground := True;
  174. end;
  175. //---------------------------------------------------------------------------
  176. destructor TAsphyreJoystick.Destroy();
  177. begin
  178.  if (FInitialized) then Finalize();
  179.  inherited;
  180. end;
  181. //---------------------------------------------------------------------------
  182. procedure TAsphyreJoystick.SetForeground(const Value: Boolean);
  183. begin
  184.  if (not FInitialized) then FForeground:= Value;
  185. end;
  186. //---------------------------------------------------------------------------
  187. function TAsphyreJoystick.Initialize(ddi: PDIDeviceInstance;
  188.  hWnd: Integer): Boolean;
  189. var
  190.  Input  : TAsphyreInput;
  191.  EnumRef: TJoyEnumRef;
  192.  Flags  : Cardinal;
  193. begin
  194.  // (1) Retreive a valid reference to TAsphyreInput from the owner.
  195.  Input:= TAsphyreInput(FOwner.OwnerInput);
  196.  // (2) Create input device.
  197.  Result:= Succeeded(Input.DirectInput8.CreateDevice(ddi.guidInstance,
  198.   FInputDevice, nil));
  199.  if (not Result) then Exit;
  200.  // (3) Set data format.
  201.  Result:= Succeeded(FInputDevice.SetDataFormat(c_dfDIJoystick2));
  202.  if (not Result) then
  203.   begin
  204.    FInputDevice:= nil;
  205.    Exit;
  206.   end;
  207.  // (4) Prepare cooperative flags.
  208.  Flags:= DISCL_FOREGROUND or DISCL_EXCLUSIVE;
  209.  if (not FForeground) then Flags:= DISCL_BACKGROUND or DISCL_NONEXCLUSIVE;
  210.  // (5) Set joystick cooperative level.
  211.  Result:= Succeeded(FInputDevice.SetCooperativeLevel(hWnd, Flags));
  212.  if (not Result) then
  213.   begin
  214.    FInputDevice:= nil;
  215.    Exit;
  216.   end;
  217.  // (6) Enumerate joystick axes.
  218.  EnumRef.Referrer:= Self;
  219.  EnumRef.Success := True;
  220.  Result:= Succeeded(FInputDevice.EnumObjects(@AxisEnumCallback, @EnumRef,
  221.   DIDFT_AXIS))and(EnumRef.Success);
  222.  if (not Result) then
  223.   begin
  224.    FInputDevice:= nil;
  225.    Exit;
  226.   end;
  227.  // (7) Get device capabilities.
  228.  FillChar(FDeviceCaps, SizeOf(TDIDevCaps), 0);
  229.  FDeviceCaps.dwSize:= SizeOf(TDIDevCaps);
  230.  Result:= Succeeded(FInputDevice.GetCapabilities(FDeviceCaps));
  231.  if (not Result) then
  232.   begin
  233.    FInputDevice:= nil;
  234.    Exit;
  235.   end;
  236.  // (8) Retreive useful info.
  237.  FButtonCount:= FDeviceCaps.dwButtons;
  238.  FAxisCount  := FDeviceCaps.dwAxes;
  239.  FPOVCount   := FDeviceCaps.dwPOVs;
  240.  // (9) Set status to [Initialized].
  241.  FInitialized:= True;
  242. end;
  243. //---------------------------------------------------------------------------
  244. procedure TAsphyreJoystick.Finalize();
  245. begin
  246.  if (FInputDevice <> nil) then
  247.   begin
  248.    FInputDevice.Unacquire();
  249.    FInputDevice:= nil;
  250.   end;
  251.  FInitialized:= False;
  252. end;
  253. //---------------------------------------------------------------------------
  254. function TAsphyreJoystick.Poll(): Boolean;
  255. var
  256.  Res: Integer;
  257. begin
  258.  Result:= True;
  259.  
  260.  // (1) Attempt polling Joystick.
  261.  Res:= FInputDevice.Poll();
  262.  // failures?
  263.  if (Res <> DI_OK)and(Res <> DI_NOEFFECT) then
  264.   begin
  265.    // we can handle Lost Input & Non-Acquired problems
  266.    if (Res <> DIERR_INPUTLOST)and(Res <> DIERR_NOTACQUIRED) then
  267.     begin
  268.      Result:= False;
  269.      Exit;
  270.     end;
  271.    // Acquire the device!
  272.    Result:= Succeeded(FInputDevice.Acquire());
  273.    if (Result) then
  274.     begin
  275.      Res:= FInputDevice.Poll();
  276.      if (Res <> DI_OK)and(Res <> DI_NOEFFECT) then
  277.       begin
  278.        Result:= False;
  279.        Exit;
  280.       end;
  281.     end else Exit;
  282.   end;
  283.  // (2) Retreive joystick state.
  284.  Res:= FInputDevice.GetDeviceState(SizeOf(TDIJoyState2), @FJoyState);
  285.  if (Res <> DI_OK) then
  286.   begin
  287.    // we can handle Lost Input & Non-Acquired problems
  288.    if (Res <> DIERR_INPUTLOST)and(Res <> DIERR_NOTACQUIRED) then
  289.     begin
  290.      Result:= False;
  291.      Exit;
  292.     end;
  293.    // Again, try to acquire the device.
  294.    Result:= Succeeded(FInputDevice.Acquire());
  295.    if (Result) then
  296.     begin
  297.      Result:= Succeeded(FInputDevice.GetDeviceState(SizeOf(TDIJoyState2),
  298.       @FJoyState));
  299.      if (not Result) then Exit;
  300.     end;
  301.   end;
  302. end;
  303. //---------------------------------------------------------------------------
  304. constructor TAsphyreJoysticks.Create(AOwnerInput: TObject);
  305. begin
  306.  inherited Create();
  307.  FOwnerInput:= AOwnerInput;
  308.  Assert((FOwnerInput <> nil)and(FOwnerInput is TAsphyreInput), msgNoOwnerInput);
  309.  FForeground := True;
  310.  FInitialized:= False;
  311. end;
  312. //---------------------------------------------------------------------------
  313. destructor TAsphyreJoysticks.Destroy();
  314. begin
  315.  if (FInitialized) then Finalize();
  316.  inherited;
  317. end;
  318. //---------------------------------------------------------------------------
  319. procedure TAsphyreJoysticks.ReleaseJoysticks();
  320. var
  321.  i: Integer;
  322. begin
  323.  for i:= 0 to Length(Data) - 1 do
  324.   if (Data[i] <> nil) then
  325.    begin
  326.     Data[i].Free();
  327.     Data[i]:= nil;
  328.    end;
  329.    
  330.  SetLength(Data, 0);
  331. end;
  332. //---------------------------------------------------------------------------
  333. function TAsphyreJoysticks.GetCount(): Integer;
  334. begin
  335.  Result:= Length(Data);
  336. end;
  337. //---------------------------------------------------------------------------
  338. function TAsphyreJoysticks.GetJoystick(Num: Integer): TAsphyreJoystick;
  339. begin
  340.  Assert((Num >= 0)and(Num < Length(Data)), msgIndexOutOfBounds);
  341.  Result:= nil;
  342.  if (Num >= 0)and(Num < Length(Data)) then
  343.   Result:= Data[Num];
  344. end;
  345. //---------------------------------------------------------------------------
  346. function TAsphyreJoysticks.AddJoy(): TAsphyreJoystick;
  347. var
  348.  Index: Integer;
  349. begin
  350.  Index:= Length(Data);
  351.  SetLength(Data, Length(Data) + 1);
  352.  Data[Index]:= TAsphyreJoystick.Create(Self);
  353.  Data[Index].Foreground:= FForeground;
  354.  Result:= Data[Index];
  355. end;
  356. //---------------------------------------------------------------------------
  357. function TAsphyreJoysticks.Initialize(): Boolean;
  358. var
  359.  EnumRef: TJoysEnumRef;
  360.  Input  : TAsphyreInput;
  361. begin
  362.  Assert(not FInitialized, msgAlreadyInitialized);
  363.  // (1) Acquire a valid TAsphyreInput reference.
  364.  Input:= TAsphyreInput(FOwnerInput);
  365.  // (2) Make sure that TAsphyreInput is also initialized
  366.  if (not Input.Initialized) then
  367.   begin
  368.    Result:= Input.Initialize();
  369.    if (not Result) then Exit;
  370.   end;
  371.  // (2) Release any previously created joysticks.
  372.  ReleaseJoysticks();
  373.  // (3) Enumerate joysticks.
  374.  EnumRef.Referrer:= Self;
  375.  EnumRef.Success := False;
  376.  Result:= Succeeded(Input.DirectInput8.EnumDevices(DI8DEVCLASS_GAMECTRL,
  377.   @JoyEnumCallback, @EnumRef, DIEDFL_ATTACHEDONLY))and(EnumRef.Success);
  378.  if (not Result) then ReleaseJoysticks();
  379.  // (4) Set status to [Initialized]
  380.  FInitialized:= Result;
  381. end;
  382. //---------------------------------------------------------------------------
  383. procedure TAsphyreJoysticks.Finalize();
  384. begin
  385.  ReleaseJoysticks();
  386.  FInitialized:= False;
  387. end;
  388. //---------------------------------------------------------------------------
  389. function TAsphyreJoysticks.Update(): Boolean;
  390. var
  391.  i: Integer;
  392. begin
  393.  Result:= True;
  394.  if (not FInitialized) then
  395.   begin
  396.    Result:= Initialize();
  397.    if (not Result) then Exit;
  398.   end;
  399.  for i:= 0 to Length(Data) - 1 do
  400.   if (Data[i] <> nil)and(Data[i].Initialized) then
  401.    begin
  402.     Result:= Data[i].Poll();
  403.     if (not Result) then Break;
  404.    end;
  405. end;
  406. //---------------------------------------------------------------------------
  407. end.