mirror of https://github.com/red-prig/fpPS4.git
parent
27aff1b54c
commit
d6d45ba1a2
31
fpPS4.lpi
31
fpPS4.lpi
|
@ -31,7 +31,7 @@
|
|||
<PackageName Value="LCL"/>
|
||||
</Item1>
|
||||
</RequiredPackages>
|
||||
<Units Count="117">
|
||||
<Units Count="120">
|
||||
<Unit0>
|
||||
<Filename Value="fpPS4.lpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
|
@ -513,21 +513,42 @@
|
|||
<IsPartOfProject Value="True"/>
|
||||
</Unit112>
|
||||
<Unit113>
|
||||
<Filename Value="kernel\mm_adr_direct.pas"/>
|
||||
<Filename Value="src\inputs\formcontroller.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<ComponentName Value="FormControllers"/>
|
||||
<HasResources Value="True"/>
|
||||
<ResourceBaseClass Value="Form"/>
|
||||
<UnitName Value="formController"/>
|
||||
</Unit113>
|
||||
<Unit114>
|
||||
<Filename Value="kernel\mm_adr_virtual.pas"/>
|
||||
<Filename Value="src\inputs\umappableinputs.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="uMappableInputs"/>
|
||||
</Unit114>
|
||||
<Unit115>
|
||||
<Filename Value="kernel\mm_adr_name.pas"/>
|
||||
<Filename Value="src\inputs\formbindbutton.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<ComponentName Value="FormBindButtons"/>
|
||||
<HasResources Value="True"/>
|
||||
<ResourceBaseClass Value="Form"/>
|
||||
<UnitName Value="formBindButton"/>
|
||||
</Unit115>
|
||||
<Unit116>
|
||||
<Filename Value="rtl\trace_manager.pas"/>
|
||||
<Filename Value="kernel\mm_adr_virtual.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit116>
|
||||
<Unit117>
|
||||
<Filename Value="kernel\mm_adr_direct.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit117>
|
||||
<Unit118>
|
||||
<Filename Value="rtl\trace_manager.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit118>
|
||||
<Unit119>
|
||||
<Filename Value="kernel\mm_adr_name.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit119>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
object FormBindButtons: TFormBindButtons
|
||||
Left = 701
|
||||
Height = 401
|
||||
Top = 433
|
||||
Width = 929
|
||||
Caption = 'Button Binding'
|
||||
ClientHeight = 401
|
||||
ClientWidth = 929
|
||||
DesignTimePPI = 192
|
||||
OnShow = FormShow
|
||||
LCLVersion = '2.3.0.0'
|
||||
object BitBtn1: TBitBtn
|
||||
Left = 388
|
||||
Height = 60
|
||||
Top = 272
|
||||
Width = 150
|
||||
Caption = 'Cancel'
|
||||
OnClick = BitBtn1Click
|
||||
TabOrder = 0
|
||||
end
|
||||
object BitBtn2: TBitBtn
|
||||
Left = 328
|
||||
Height = 60
|
||||
Top = 176
|
||||
Width = 272
|
||||
Caption = 'Unbind this button'
|
||||
OnClick = BitBtn2Click
|
||||
TabOrder = 1
|
||||
end
|
||||
object Label1: TLabel
|
||||
Left = 208
|
||||
Height = 32
|
||||
Top = 72
|
||||
Width = 526
|
||||
Caption = 'Press a button or move a joystick / analog trigger'
|
||||
end
|
||||
object CheckInput: TTimer
|
||||
Interval = 100
|
||||
OnTimer = CheckInputTimer
|
||||
Left = 736
|
||||
Top = 216
|
||||
end
|
||||
end
|
|
@ -0,0 +1,76 @@
|
|||
unit formBindButton;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Buttons, StdCtrls,
|
||||
ExtCtrls, uMappableInputs, Windows;
|
||||
|
||||
type
|
||||
|
||||
{ TFormBindButtons }
|
||||
|
||||
TFormBindButtons = class(TForm)
|
||||
BitBtn1: TBitBtn;
|
||||
BitBtn2: TBitBtn;
|
||||
CheckInput: TTimer;
|
||||
Label1: TLabel;
|
||||
procedure BitBtn1Click(Sender: TObject);
|
||||
procedure BitBtn2Click(Sender: TObject);
|
||||
procedure CheckInputTimer(Sender: TObject);
|
||||
procedure FormShow(Sender: TObject);
|
||||
private
|
||||
|
||||
public
|
||||
XInputKey: EnumXInputButtons;
|
||||
ResetToDefault: boolean;
|
||||
end;
|
||||
|
||||
var
|
||||
FormBindButtons: TFormBindButtons;
|
||||
|
||||
implementation
|
||||
|
||||
uses XInput;
|
||||
|
||||
{$R *.lfm}
|
||||
|
||||
{ TFormBindButtons }
|
||||
|
||||
procedure TFormBindButtons.CheckInputTimer(Sender: TObject);
|
||||
var
|
||||
i: integer;
|
||||
state: TXInputState;
|
||||
key: EnumXInputButtons;
|
||||
begin
|
||||
ZeroMemory(@state, SizeOf(TXInputState));
|
||||
if XInputGetState(0, state) = ERROR_SUCCESS then
|
||||
begin
|
||||
key := MappableInputs.XInputStateToKey(state);
|
||||
if key <> EnumXInputButtons.xiUnbound then
|
||||
begin
|
||||
XInputKey := key;
|
||||
ModalResult := mrOk;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFormBindButtons.BitBtn2Click(Sender: TObject);
|
||||
begin
|
||||
XInputKey := xiUnbound;
|
||||
ModalResult := mrOk;
|
||||
end;
|
||||
|
||||
procedure TFormBindButtons.BitBtn1Click(Sender: TObject);
|
||||
begin
|
||||
ModalResult := mrCancel;
|
||||
end;
|
||||
|
||||
procedure TFormBindButtons.FormShow(Sender: TObject);
|
||||
begin
|
||||
XInputKey := xiUnbound;
|
||||
end;
|
||||
|
||||
end.
|
|
@ -0,0 +1,671 @@
|
|||
object FormControllers: TFormControllers
|
||||
Left = 502
|
||||
Height = 1123
|
||||
Top = 247
|
||||
Width = 1873
|
||||
Caption = 'XInput to PS4 Controller Config'
|
||||
ClientHeight = 1123
|
||||
ClientWidth = 1873
|
||||
DesignTimePPI = 192
|
||||
OnClose = FormClose
|
||||
OnCreate = FormCreate
|
||||
OnShow = FormShow
|
||||
LCLVersion = '2.3.0.0'
|
||||
object GroupBox1: TGroupBox
|
||||
Left = 24
|
||||
Height = 328
|
||||
Top = 312
|
||||
Width = 640
|
||||
Caption = 'Left Joystick'
|
||||
ClientHeight = 291
|
||||
ClientWidth = 636
|
||||
TabOrder = 0
|
||||
object Shape1: TShape
|
||||
Left = 240
|
||||
Height = 130
|
||||
Top = 72
|
||||
Width = 130
|
||||
Shape = stCircle
|
||||
end
|
||||
object LJoyUp: TBitBtn
|
||||
Tag = 1
|
||||
Left = 200
|
||||
Height = 43
|
||||
Top = 24
|
||||
Width = 212
|
||||
Caption = 'UP'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 0
|
||||
end
|
||||
object LJoyRight: TBitBtn
|
||||
Tag = 4
|
||||
Left = 400
|
||||
Height = 43
|
||||
Top = 120
|
||||
Width = 212
|
||||
Caption = 'RIGHT'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 1
|
||||
end
|
||||
object LJoyDown: TBitBtn
|
||||
Tag = 2
|
||||
Left = 200
|
||||
Height = 43
|
||||
Top = 240
|
||||
Width = 212
|
||||
Caption = 'DOWN'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 2
|
||||
end
|
||||
object LJoyLeft: TBitBtn
|
||||
Tag = 3
|
||||
Left = 8
|
||||
Height = 43
|
||||
Top = 120
|
||||
Width = 212
|
||||
Caption = 'LEFT'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 3
|
||||
end
|
||||
object Label1: TLabel
|
||||
Left = 480
|
||||
Height = 32
|
||||
Top = 80
|
||||
Width = 56
|
||||
Alignment = taCenter
|
||||
Caption = 'Right'
|
||||
end
|
||||
object Label2: TLabel
|
||||
Left = 288
|
||||
Height = 32
|
||||
Top = -16
|
||||
Width = 30
|
||||
Alignment = taCenter
|
||||
Caption = 'Up'
|
||||
end
|
||||
object Label3: TLabel
|
||||
Left = 88
|
||||
Height = 32
|
||||
Top = 80
|
||||
Width = 40
|
||||
Alignment = taCenter
|
||||
Caption = 'Left'
|
||||
end
|
||||
object Label4: TLabel
|
||||
Left = 272
|
||||
Height = 32
|
||||
Top = 200
|
||||
Width = 62
|
||||
Alignment = taCenter
|
||||
Caption = 'Down'
|
||||
end
|
||||
end
|
||||
object GroupBox6: TGroupBox
|
||||
Left = 464
|
||||
Height = 258
|
||||
Top = 8
|
||||
Width = 578
|
||||
Caption = 'Shoulder buttons / Triggers'
|
||||
ClientHeight = 221
|
||||
ClientWidth = 574
|
||||
TabOrder = 1
|
||||
object R3: TBitBtn
|
||||
Tag = 25
|
||||
Left = 344
|
||||
Height = 60
|
||||
Top = 16
|
||||
Width = 184
|
||||
Caption = 'L3'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 0
|
||||
end
|
||||
object L3: TBitBtn
|
||||
Tag = 22
|
||||
Left = 56
|
||||
Height = 60
|
||||
Top = 16
|
||||
Width = 184
|
||||
Caption = 'L3'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 1
|
||||
end
|
||||
object R2: TBitBtn
|
||||
Tag = 24
|
||||
Left = 344
|
||||
Height = 60
|
||||
Top = 80
|
||||
Width = 184
|
||||
Caption = 'L2'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 2
|
||||
end
|
||||
object L2: TBitBtn
|
||||
Tag = 21
|
||||
Left = 56
|
||||
Height = 60
|
||||
Top = 80
|
||||
Width = 184
|
||||
Caption = 'L2'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 3
|
||||
end
|
||||
object L1: TBitBtn
|
||||
Tag = 20
|
||||
Left = 56
|
||||
Height = 60
|
||||
Top = 144
|
||||
Width = 184
|
||||
Caption = 'L1'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 4
|
||||
end
|
||||
object R1: TBitBtn
|
||||
Tag = 23
|
||||
Left = 344
|
||||
Height = 60
|
||||
Top = 144
|
||||
Width = 184
|
||||
Caption = 'L1'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 5
|
||||
end
|
||||
object Label17: TLabel
|
||||
Left = 16
|
||||
Height = 32
|
||||
Top = 24
|
||||
Width = 24
|
||||
Alignment = taCenter
|
||||
Caption = 'L3'
|
||||
end
|
||||
object Label18: TLabel
|
||||
Left = 16
|
||||
Height = 32
|
||||
Top = 88
|
||||
Width = 24
|
||||
Alignment = taCenter
|
||||
Caption = 'L2'
|
||||
end
|
||||
object Label19: TLabel
|
||||
Left = 16
|
||||
Height = 32
|
||||
Top = 160
|
||||
Width = 24
|
||||
Alignment = taCenter
|
||||
Caption = 'L1'
|
||||
end
|
||||
object Label20: TLabel
|
||||
Left = 280
|
||||
Height = 32
|
||||
Top = 24
|
||||
Width = 27
|
||||
Alignment = taCenter
|
||||
Caption = 'R3'
|
||||
end
|
||||
object Label21: TLabel
|
||||
Left = 280
|
||||
Height = 32
|
||||
Top = 88
|
||||
Width = 27
|
||||
Alignment = taCenter
|
||||
Caption = 'R2'
|
||||
end
|
||||
object Label22: TLabel
|
||||
Left = 280
|
||||
Height = 32
|
||||
Top = 160
|
||||
Width = 27
|
||||
Alignment = taCenter
|
||||
Caption = 'R1'
|
||||
end
|
||||
end
|
||||
object BitBtn17: TBitBtn
|
||||
Tag = 19
|
||||
Left = 1480
|
||||
Height = 60
|
||||
Top = 112
|
||||
Width = 182
|
||||
Caption = 'Start'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 2
|
||||
end
|
||||
object BitBtn18: TBitBtn
|
||||
Tag = 17
|
||||
Left = 1064
|
||||
Height = 60
|
||||
Top = 112
|
||||
Width = 184
|
||||
Caption = 'Share'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 3
|
||||
end
|
||||
object BitBtn19: TBitBtn
|
||||
Tag = 18
|
||||
Left = 1272
|
||||
Height = 60
|
||||
Top = 112
|
||||
Width = 184
|
||||
Caption = 'Touch Screen'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 4
|
||||
end
|
||||
object GroupBox3: TGroupBox
|
||||
Left = 24
|
||||
Height = 328
|
||||
Top = 664
|
||||
Width = 640
|
||||
Caption = 'DPAD'
|
||||
ClientHeight = 291
|
||||
ClientWidth = 636
|
||||
TabOrder = 5
|
||||
object DPadUp: TBitBtn
|
||||
Tag = 9
|
||||
Left = 200
|
||||
Height = 43
|
||||
Top = 24
|
||||
Width = 212
|
||||
Caption = 'UP'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 0
|
||||
end
|
||||
object DPadRight: TBitBtn
|
||||
Tag = 12
|
||||
Left = 400
|
||||
Height = 43
|
||||
Top = 120
|
||||
Width = 212
|
||||
Caption = 'RIGHT'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 1
|
||||
end
|
||||
object DPadDown: TBitBtn
|
||||
Tag = 10
|
||||
Left = 200
|
||||
Height = 43
|
||||
Top = 240
|
||||
Width = 212
|
||||
Caption = 'DOWN'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 2
|
||||
end
|
||||
object DPadLeft: TBitBtn
|
||||
Tag = 11
|
||||
Left = 8
|
||||
Height = 43
|
||||
Top = 120
|
||||
Width = 212
|
||||
Caption = 'LEFT'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 3
|
||||
end
|
||||
object Label5: TLabel
|
||||
Left = 480
|
||||
Height = 32
|
||||
Top = 80
|
||||
Width = 56
|
||||
Alignment = taCenter
|
||||
Caption = 'Right'
|
||||
end
|
||||
object Label6: TLabel
|
||||
Left = 288
|
||||
Height = 32
|
||||
Top = -16
|
||||
Width = 30
|
||||
Alignment = taCenter
|
||||
Caption = 'Up'
|
||||
end
|
||||
object Label7: TLabel
|
||||
Left = 88
|
||||
Height = 32
|
||||
Top = 80
|
||||
Width = 40
|
||||
Alignment = taCenter
|
||||
Caption = 'Left'
|
||||
end
|
||||
object Label8: TLabel
|
||||
Left = 272
|
||||
Height = 32
|
||||
Top = 200
|
||||
Width = 62
|
||||
Alignment = taCenter
|
||||
Caption = 'Down'
|
||||
end
|
||||
object Shape2: TShape
|
||||
Left = 283
|
||||
Height = 34
|
||||
Top = 80
|
||||
Width = 39
|
||||
Shape = stTriangle
|
||||
end
|
||||
object Shape5: TShape
|
||||
Left = 283
|
||||
Height = 34
|
||||
Top = 160
|
||||
Width = 39
|
||||
Shape = stTriangleDown
|
||||
end
|
||||
object Shape6: TShape
|
||||
Left = 331
|
||||
Height = 34
|
||||
Top = 120
|
||||
Width = 39
|
||||
Shape = stTriangleRight
|
||||
end
|
||||
object Shape7: TShape
|
||||
Left = 235
|
||||
Height = 34
|
||||
Top = 120
|
||||
Width = 39
|
||||
Shape = stTriangleLeft
|
||||
end
|
||||
end
|
||||
object GroupBox4: TGroupBox
|
||||
Left = 712
|
||||
Height = 328
|
||||
Top = 664
|
||||
Width = 640
|
||||
Caption = 'Right joystick'
|
||||
ClientHeight = 291
|
||||
ClientWidth = 636
|
||||
TabOrder = 6
|
||||
object Shape3: TShape
|
||||
Left = 240
|
||||
Height = 130
|
||||
Top = 72
|
||||
Width = 130
|
||||
Shape = stCircle
|
||||
end
|
||||
object RJoyUp: TBitBtn
|
||||
Tag = 5
|
||||
Left = 200
|
||||
Height = 43
|
||||
Top = 24
|
||||
Width = 212
|
||||
Caption = 'UP'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 0
|
||||
end
|
||||
object RJoyRight: TBitBtn
|
||||
Tag = 8
|
||||
Left = 400
|
||||
Height = 43
|
||||
Top = 120
|
||||
Width = 212
|
||||
Caption = 'RIGHT'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 1
|
||||
end
|
||||
object RJoyDown: TBitBtn
|
||||
Tag = 6
|
||||
Left = 200
|
||||
Height = 43
|
||||
Top = 240
|
||||
Width = 212
|
||||
Caption = 'DOWN'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 2
|
||||
end
|
||||
object RJoyLeft: TBitBtn
|
||||
Tag = 7
|
||||
Left = 8
|
||||
Height = 43
|
||||
Top = 120
|
||||
Width = 212
|
||||
Caption = 'LEFT'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 3
|
||||
end
|
||||
object Label9: TLabel
|
||||
Left = 488
|
||||
Height = 32
|
||||
Top = 80
|
||||
Width = 56
|
||||
Alignment = taCenter
|
||||
Caption = 'Right'
|
||||
end
|
||||
object Label10: TLabel
|
||||
Left = 288
|
||||
Height = 32
|
||||
Top = -16
|
||||
Width = 30
|
||||
Alignment = taCenter
|
||||
Caption = 'Up'
|
||||
end
|
||||
object Label11: TLabel
|
||||
Left = 88
|
||||
Height = 32
|
||||
Top = 80
|
||||
Width = 40
|
||||
Alignment = taCenter
|
||||
Caption = 'Left'
|
||||
end
|
||||
object Label12: TLabel
|
||||
Left = 272
|
||||
Height = 32
|
||||
Top = 200
|
||||
Width = 62
|
||||
Alignment = taCenter
|
||||
Caption = 'Down'
|
||||
end
|
||||
end
|
||||
object GroupBox5: TGroupBox
|
||||
Left = 712
|
||||
Height = 328
|
||||
Top = 312
|
||||
Width = 640
|
||||
Caption = 'Buttons'
|
||||
ClientHeight = 291
|
||||
ClientWidth = 636
|
||||
TabOrder = 7
|
||||
object Triangle: TBitBtn
|
||||
Tag = 16
|
||||
Left = 200
|
||||
Height = 43
|
||||
Top = 24
|
||||
Width = 212
|
||||
Caption = 'UP'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 0
|
||||
end
|
||||
object Circle: TBitBtn
|
||||
Tag = 14
|
||||
Left = 400
|
||||
Height = 43
|
||||
Top = 120
|
||||
Width = 212
|
||||
Caption = 'RIGHT'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 1
|
||||
end
|
||||
object Cross: TBitBtn
|
||||
Tag = 13
|
||||
Left = 200
|
||||
Height = 43
|
||||
Top = 240
|
||||
Width = 212
|
||||
Caption = 'DOWN'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 2
|
||||
end
|
||||
object Square: TBitBtn
|
||||
Tag = 15
|
||||
Left = 8
|
||||
Height = 43
|
||||
Top = 120
|
||||
Width = 212
|
||||
Caption = 'LEFT'
|
||||
OnClick = ChangeKeyBiding
|
||||
TabOrder = 3
|
||||
end
|
||||
object Label13: TLabel
|
||||
Left = 480
|
||||
Height = 32
|
||||
Top = 80
|
||||
Width = 59
|
||||
Alignment = taCenter
|
||||
Caption = 'Circle'
|
||||
end
|
||||
object Label14: TLabel
|
||||
Left = 264
|
||||
Height = 32
|
||||
Top = -16
|
||||
Width = 84
|
||||
Alignment = taCenter
|
||||
Caption = 'Triangle'
|
||||
end
|
||||
object Label15: TLabel
|
||||
Left = 72
|
||||
Height = 32
|
||||
Top = 80
|
||||
Width = 74
|
||||
Alignment = taCenter
|
||||
Caption = 'Square'
|
||||
end
|
||||
object Label16: TLabel
|
||||
Left = 272
|
||||
Height = 32
|
||||
Top = 200
|
||||
Width = 57
|
||||
Alignment = taCenter
|
||||
Caption = 'Cross'
|
||||
end
|
||||
end
|
||||
object Label23: TLabel
|
||||
Left = 1128
|
||||
Height = 32
|
||||
Top = 72
|
||||
Width = 60
|
||||
Alignment = taCenter
|
||||
Caption = 'Share'
|
||||
end
|
||||
object Label24: TLabel
|
||||
Left = 1296
|
||||
Height = 32
|
||||
Top = 72
|
||||
Width = 143
|
||||
Alignment = taCenter
|
||||
Caption = 'Touch Screen'
|
||||
end
|
||||
object Label25: TLabel
|
||||
Left = 1528
|
||||
Height = 32
|
||||
Top = 72
|
||||
Width = 84
|
||||
Alignment = taCenter
|
||||
Caption = 'Options'
|
||||
end
|
||||
object Save: TBitBtn
|
||||
Left = 1352
|
||||
Height = 60
|
||||
Top = 1032
|
||||
Width = 226
|
||||
Caption = 'Save'
|
||||
OnClick = SaveClick
|
||||
TabOrder = 8
|
||||
end
|
||||
object Cancel: TBitBtn
|
||||
Left = 1618
|
||||
Height = 60
|
||||
Top = 1032
|
||||
Width = 226
|
||||
Caption = 'Cancel'
|
||||
OnClick = CancelClick
|
||||
TabOrder = 9
|
||||
end
|
||||
object SavePreset: TBitBtn
|
||||
Left = 56
|
||||
Height = 60
|
||||
Top = 104
|
||||
Width = 226
|
||||
Caption = 'Save as preset'
|
||||
OnClick = SavePresetClick
|
||||
TabOrder = 10
|
||||
end
|
||||
object LoadPreset: TBitBtn
|
||||
Left = 56
|
||||
Height = 60
|
||||
Top = 184
|
||||
Width = 226
|
||||
Caption = 'Load preset'
|
||||
OnClick = LoadPresetClick
|
||||
TabOrder = 11
|
||||
end
|
||||
object CheckEnabled: TCheckBox
|
||||
Left = 64
|
||||
Height = 36
|
||||
Top = 32
|
||||
Width = 193
|
||||
Caption = 'XInput Enabled'
|
||||
Checked = True
|
||||
OnChange = SaveConfig
|
||||
State = cbChecked
|
||||
TabOrder = 12
|
||||
end
|
||||
object GroupBox2: TGroupBox
|
||||
Left = 1377
|
||||
Height = 282
|
||||
Top = 368
|
||||
Width = 434
|
||||
Caption = 'Dead zones'
|
||||
ClientHeight = 245
|
||||
ClientWidth = 430
|
||||
TabOrder = 13
|
||||
object dzLeft: TTrackBar
|
||||
Left = 112
|
||||
Height = 50
|
||||
Top = 24
|
||||
Width = 280
|
||||
OnChange = SaveConfig
|
||||
Position = 0
|
||||
TabOrder = 0
|
||||
end
|
||||
object dzRight: TTrackBar
|
||||
Left = 112
|
||||
Height = 50
|
||||
Top = 96
|
||||
Width = 280
|
||||
OnChange = SaveConfig
|
||||
Position = 0
|
||||
TabOrder = 1
|
||||
end
|
||||
object Label26: TLabel
|
||||
Left = 16
|
||||
Height = 32
|
||||
Top = 24
|
||||
Width = 40
|
||||
Caption = 'Left'
|
||||
end
|
||||
object Label27: TLabel
|
||||
Left = 16
|
||||
Height = 32
|
||||
Top = 96
|
||||
Width = 56
|
||||
Caption = 'Right'
|
||||
end
|
||||
object Label28: TLabel
|
||||
Left = 16
|
||||
Height = 32
|
||||
Top = 168
|
||||
Width = 84
|
||||
Caption = 'Triggers'
|
||||
end
|
||||
object dzTriggers: TTrackBar
|
||||
Left = 112
|
||||
Height = 50
|
||||
Top = 168
|
||||
Width = 280
|
||||
OnChange = SaveConfig
|
||||
Position = 0
|
||||
TabOrder = 2
|
||||
end
|
||||
end
|
||||
object OpenDialog1: TOpenDialog
|
||||
Filter = 'Ini files|*.ini'
|
||||
Left = 328
|
||||
Top = 66
|
||||
end
|
||||
object SaveDialog1: TSaveDialog
|
||||
Filter = 'Ini file|*.ini'
|
||||
Left = 328
|
||||
Top = 184
|
||||
end
|
||||
end
|
|
@ -0,0 +1,246 @@
|
|||
unit formController;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,
|
||||
Buttons, Interfaces, LResources, ComCtrls;
|
||||
|
||||
type
|
||||
|
||||
{ TFormControllers }
|
||||
|
||||
TFormControllers = class(TForm)
|
||||
CheckEnabled: TCheckBox;
|
||||
GroupBox2: TGroupBox;
|
||||
Label26: TLabel;
|
||||
Label27: TLabel;
|
||||
Label28: TLabel;
|
||||
LJoyUp: TBitBtn;
|
||||
OpenDialog1: TOpenDialog;
|
||||
RJoyRight: TBitBtn;
|
||||
RJoyDown: TBitBtn;
|
||||
RJoyLeft: TBitBtn;
|
||||
dzLeft: TTrackBar;
|
||||
dzRight: TTrackBar;
|
||||
dzTriggers: TTrackBar;
|
||||
SaveDialog1: TSaveDialog;
|
||||
Triangle: TBitBtn;
|
||||
Circle: TBitBtn;
|
||||
Cross: TBitBtn;
|
||||
Square: TBitBtn;
|
||||
BitBtn17: TBitBtn;
|
||||
BitBtn18: TBitBtn;
|
||||
BitBtn19: TBitBtn;
|
||||
LJoyLeft: TBitBtn;
|
||||
L1: TBitBtn;
|
||||
L2: TBitBtn;
|
||||
L3: TBitBtn;
|
||||
R1: TBitBtn;
|
||||
R2: TBitBtn;
|
||||
R3: TBitBtn;
|
||||
Save: TBitBtn;
|
||||
Cancel: TBitBtn;
|
||||
SavePreset: TBitBtn;
|
||||
LoadPreset: TBitBtn;
|
||||
LJoyRight: TBitBtn;
|
||||
LJoyDown: TBitBtn;
|
||||
DPadUp: TBitBtn;
|
||||
DPadRight: TBitBtn;
|
||||
DPadDown: TBitBtn;
|
||||
DPadLeft: TBitBtn;
|
||||
RJoyUp: TBitBtn;
|
||||
GroupBox1: TGroupBox;
|
||||
GroupBox3: TGroupBox;
|
||||
GroupBox4: TGroupBox;
|
||||
GroupBox5: TGroupBox;
|
||||
GroupBox6: TGroupBox;
|
||||
Label1: TLabel;
|
||||
Label10: TLabel;
|
||||
Label11: TLabel;
|
||||
Label12: TLabel;
|
||||
Label13: TLabel;
|
||||
Label14: TLabel;
|
||||
Label15: TLabel;
|
||||
Label16: TLabel;
|
||||
Label17: TLabel;
|
||||
Label18: TLabel;
|
||||
Label19: TLabel;
|
||||
Label2: TLabel;
|
||||
Label20: TLabel;
|
||||
Label21: TLabel;
|
||||
Label22: TLabel;
|
||||
Label23: TLabel;
|
||||
Label24: TLabel;
|
||||
Label25: TLabel;
|
||||
Label3: TLabel;
|
||||
Label4: TLabel;
|
||||
Label5: TLabel;
|
||||
Label6: TLabel;
|
||||
Label7: TLabel;
|
||||
Label8: TLabel;
|
||||
Label9: TLabel;
|
||||
Shape1: TShape;
|
||||
Shape2: TShape;
|
||||
Shape3: TShape;
|
||||
Shape5: TShape;
|
||||
Shape6: TShape;
|
||||
Shape7: TShape;
|
||||
procedure CancelClick(Sender: TObject);
|
||||
procedure ChangeKeyBiding(Sender: TObject);
|
||||
procedure LoadPresetClick(Sender: TObject);
|
||||
procedure SaveConfig(Sender: TObject);
|
||||
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure FormShow(Sender: TObject);
|
||||
procedure SaveClick(Sender: TObject);
|
||||
procedure SavePresetClick(Sender: TObject);
|
||||
private
|
||||
ShouldSaveConfig: boolean;
|
||||
function FindControlByTag(control: TWinControl; pTag: integer): TWinControl;
|
||||
public
|
||||
|
||||
end;
|
||||
|
||||
var
|
||||
FormControllers: TFormControllers;
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.lfm}
|
||||
|
||||
uses formBindButton, uMappableInputs;
|
||||
|
||||
{ TFormControllers }
|
||||
|
||||
procedure TFormControllers.ChangeKeyBiding(Sender: TObject);
|
||||
var
|
||||
keyToChange: integer;
|
||||
begin
|
||||
if Sender is TBitBtn then
|
||||
begin
|
||||
keyToChange := TBitBtn(Sender).Tag;
|
||||
FormBindButtons := TFormBindButtons.Create(Self);
|
||||
Application.CreateForm(TFormBindButtons, FormBindButtons);
|
||||
FormBindButtons.ShowModal;
|
||||
|
||||
if FormBindButtons.ModalResult = mrOk then
|
||||
begin
|
||||
MappableInputs.SetXInputMapping(EnumPS4Buttons(keyToChange), FormBindButtons.XInputKey);
|
||||
TBitBtn(Sender).Caption := MappableInputs.XInputButtonsNames[Ord(FormBindButtons.XInputKey)];
|
||||
end;
|
||||
|
||||
FormBindButtons.Release;
|
||||
FormBindButtons.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFormControllers.LoadPresetClick(Sender: TObject);
|
||||
begin
|
||||
//
|
||||
OpenDialog1.InitialDir:='config';
|
||||
if OpenDialog1.Execute then
|
||||
begin
|
||||
MappableInputs.LoadFromFile(OpenDialog1.FileName);
|
||||
ShowMessage('Config loaded from ' + OpenDialog1.FileName);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFormControllers.SaveConfig(Sender: TObject);
|
||||
begin
|
||||
if ShouldSaveConfig then
|
||||
begin
|
||||
MappableInputs.XInputEnabled := CheckEnabled.Checked;
|
||||
MappableInputs.XInputDeadzoneLeft := dzLeft.Position;
|
||||
MappableInputs.XInputDeadzoneRight := dzRight.Position;
|
||||
MappableInputs.XInputDeadzoneTrigger := dzTriggers.Position;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFormControllers.FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
||||
begin
|
||||
MappableInputs.LoadFromFile(XINPUT_CONFIG_FILE);
|
||||
CloseAction := TCloseAction.caHide;
|
||||
end;
|
||||
|
||||
procedure TFormControllers.CancelClick(Sender: TObject);
|
||||
begin
|
||||
Self.Close;
|
||||
end;
|
||||
|
||||
function TFormControllers.FindControlByTag(control: TWinControl; pTag: integer): TWinControl;
|
||||
var
|
||||
i: integer;
|
||||
begin
|
||||
Result := nil;
|
||||
for i := 0 to control.ControlCount - 1 do
|
||||
begin
|
||||
if control.Controls[i] is TWinControl then
|
||||
begin
|
||||
if control.Controls[i].Tag = pTag then
|
||||
begin
|
||||
Result := TWinControl(control.Controls[i]);
|
||||
exit;
|
||||
end;
|
||||
// recursively check children
|
||||
Result := FindControlByTag(TWinControl(control.Controls[i]), pTag);
|
||||
if Result <> nil then
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFormControllers.FormCreate(Sender: TObject);
|
||||
begin
|
||||
end;
|
||||
|
||||
procedure TFormControllers.FormShow(Sender: TObject);
|
||||
var
|
||||
i: integer;
|
||||
btn: TWinControl;
|
||||
begin
|
||||
// Load mapped buttons into UI
|
||||
ShouldSaveConfig := False;
|
||||
MappableInputs.LoadFromFile(XINPUT_CONFIG_FILE);
|
||||
CheckEnabled.Checked := MappableInputs.XInputEnabled;
|
||||
|
||||
dzTriggers.Max := 255;
|
||||
|
||||
dzLeft.Max := smallint.MaxValue;
|
||||
dzRight.Max := smallint.MaxValue;
|
||||
|
||||
dzLeft.Position := MappableInputs.XInputDeadzoneLeft;
|
||||
dzRight.Position := MappableInputs.XInputDeadzoneRight;
|
||||
dzTriggers.Position := MappableInputs.XInputDeadzoneTrigger;
|
||||
|
||||
for i := 1 to NUM_PS4_BUTTONS do
|
||||
begin
|
||||
btn := FindControlByTag(Self, i);
|
||||
if btn <> nil then
|
||||
begin
|
||||
btn.Caption := MappableInputs.XInputButtonsNames[Ord(MappableInputs.PS4toXInput[i])];
|
||||
end;
|
||||
end;
|
||||
ShouldSaveConfig := True;
|
||||
end;
|
||||
|
||||
procedure TFormControllers.SaveClick(Sender: TObject);
|
||||
begin
|
||||
MappableInputs.SaveToFile(XINPUT_CONFIG_FILE);
|
||||
Self.Close;
|
||||
end;
|
||||
|
||||
procedure TFormControllers.SavePresetClick(Sender: TObject);
|
||||
begin
|
||||
//
|
||||
SaveDialog1.InitialDir:='config';
|
||||
if SaveDialog1.Execute then
|
||||
begin
|
||||
MappableInputs.SaveToFile(SaveDialog1.FileName);
|
||||
ShowMessage('Config saved to ' + SaveDialog1.FileName);
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
|
@ -0,0 +1,382 @@
|
|||
unit uMappableInputs;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, XInput, IniFiles, Math;
|
||||
|
||||
const
|
||||
NUM_PS4_BUTTONS = 25;
|
||||
NUM_XINPUT_BUTTONS = 25;
|
||||
XINPUT_CONFIG_FILE = 'config/xinput.ini';
|
||||
|
||||
type
|
||||
// Mappable inputs of the PS4 controller
|
||||
EnumPS4Buttons = (
|
||||
miUnbound = 0,
|
||||
miLJoyUp = 1,
|
||||
miLJoyDown = 2,
|
||||
miLJoyLeft = 3,
|
||||
miLJoyRight = 4,
|
||||
|
||||
miRJoyUp = 5,
|
||||
miRJoyDown = 6,
|
||||
miRJoyLeft = 7,
|
||||
miRJoyRight = 8,
|
||||
|
||||
miDPadUp = 9,
|
||||
miDPadDown = 10,
|
||||
miDPadLeft = 11,
|
||||
miDPadRight = 12,
|
||||
|
||||
miCross = 13,
|
||||
miCircle = 14,
|
||||
miSquare = 15,
|
||||
miTriangle = 16,
|
||||
|
||||
miShare = 17,
|
||||
miTouchPad = 18,
|
||||
miOptions = 19,
|
||||
|
||||
miL1 = 20,
|
||||
miL2 = 21,
|
||||
miL3 = 22,
|
||||
|
||||
miR1 = 23,
|
||||
miR2 = 24,
|
||||
miR3 = 25
|
||||
);
|
||||
|
||||
// XInput buttons enum
|
||||
EnumXInputButtons = (
|
||||
xiUnbound = 0,
|
||||
xiLJoyUp = 1,
|
||||
xiLJoyDown = 2,
|
||||
xiLJoyLeft = 3,
|
||||
xiLJoyRight = 4,
|
||||
|
||||
xiRJoyUp = 5,
|
||||
xiRJoyDown = 6,
|
||||
xiRJoyLeft = 7,
|
||||
xiRJoyRight = 8,
|
||||
|
||||
xiDPadUp = 9,
|
||||
xiDPadDown = 10,
|
||||
xiDPadLeft = 11,
|
||||
xiDPadRight = 12,
|
||||
|
||||
xiA = 13,
|
||||
xiB = 14,
|
||||
xiX = 15,
|
||||
xiY = 16,
|
||||
|
||||
xiSelect = 17,
|
||||
xiUnused01 = 18,
|
||||
xiStart = 19,
|
||||
|
||||
xiL1 = 20,
|
||||
xiL2 = 21,
|
||||
xiL3 = 22,
|
||||
|
||||
xiR1 = 23,
|
||||
xiR2 = 24,
|
||||
xiR3 = 25
|
||||
);
|
||||
|
||||
type
|
||||
TMappableInputs = class(TObject)
|
||||
public
|
||||
XInputEnabled: boolean;
|
||||
|
||||
PS4toXInput: array[0..NUM_PS4_BUTTONS] of EnumXInputButtons;
|
||||
XInputToPS4: array[0..NUM_XINPUT_BUTTONS] of EnumPS4Buttons;
|
||||
|
||||
XInputButtonsNames: array[0..NUM_XINPUT_BUTTONS] of string;
|
||||
XInputDeadzoneLeft, XInputDeadzoneRight: integer;
|
||||
XInputDeadzoneTrigger : Byte;
|
||||
|
||||
function GetAnalog(input : EnumPS4Buttons; s : TXInputState) : Single;
|
||||
function PS4IsPressed(input: EnumPS4Buttons; s : TXInputState): boolean;
|
||||
|
||||
function XInputStateToKey(state: TXInputState): EnumXInputButtons;
|
||||
function XInputIsTriggered(input: EnumXInputButtons; state: TXInputState): boolean;
|
||||
function XInputIsAnalog(input: EnumXInputButtons): boolean;
|
||||
procedure SetXInputMapping(mappableInput: EnumPS4Buttons; xinput: EnumXInputButtons);
|
||||
|
||||
// Save / load
|
||||
function LoadFromFile(filePath: string): boolean;
|
||||
function SaveToFile(filePath: string): boolean;
|
||||
end;
|
||||
|
||||
var
|
||||
MappableInputs: TMappableInputs;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses TypInfo;
|
||||
|
||||
procedure TMappableInputs.SetXInputMapping(mappableInput: EnumPS4Buttons; xinput: EnumXInputButtons);
|
||||
begin
|
||||
XInputToPS4[Ord(xinput)] := mappableInput;
|
||||
PS4toXInput[Ord(mappableInput)] := xinput;
|
||||
end;
|
||||
|
||||
function TMappableInputs.XInputStateToKey(state: TXInputState): EnumXInputButtons;
|
||||
var
|
||||
i: integer;
|
||||
begin
|
||||
Result := xiUnbound;
|
||||
for i := 1 to NUM_XINPUT_BUTTONS do
|
||||
begin
|
||||
if XInputIsTriggered(EnumXInputButtons(i), state) then
|
||||
begin
|
||||
Result := EnumXInputButtons(i);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMappableInputs.XInputIsAnalog(input: EnumXInputButtons): boolean;
|
||||
begin
|
||||
case (input) of
|
||||
xiLJoyUp, xiLJoyLeft, xiLJoyRight, xiLJoyDown: Result := True;
|
||||
xiRJoyUp, xiRJoyLeft, xiRJoyRight, xiRJoyDown: Result := True;
|
||||
xiL2, xiR2: Result := True;
|
||||
else Result := false;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMappableInputs.GetAnalog(input : EnumPS4Buttons; s : TXInputState) : Single;
|
||||
var
|
||||
xinputButton : EnumXInputButtons;
|
||||
outOfDeadzoneL, outOfDeadzoneR, outOfDeadzoneT : single;
|
||||
begin
|
||||
xInputButton := PS4toXInput[Ord(input)];
|
||||
|
||||
if XInputIsAnalog(xInputButton) then
|
||||
begin
|
||||
outOfDeadzoneL := IfThen(Trunc(sqrt(s.Gamepad.sThumbLX*s.Gamepad.sThumbLX+s.Gamepad.sThumbLY*s.Gamepad.sThumbLY)) > XInputDeadzoneLeft, 1, 0);
|
||||
outOfDeadzoneR := IfThen(Trunc(sqrt(s.Gamepad.sThumbRX*s.Gamepad.sThumbRX+s.Gamepad.sThumbRY*s.Gamepad.sThumbRY)) > XInputDeadzoneRight, 1, 0);
|
||||
outOfDeadzoneT := IfThen(s.Gamepad.bLeftTrigger > XInputDeadzoneTrigger, 1, 0);
|
||||
|
||||
case (xInputButton) of
|
||||
xiLJoyUp: Result := Max(s.Gamepad.sThumbLY, 0) * outOfDeadzoneL / 32767.0;
|
||||
xiLJoyDown: Result := Min(s.Gamepad.sThumbLY, 0) * outOfDeadzoneL / 32767.0;
|
||||
xiLJoyRight: Result := Max(s.Gamepad.sThumbLX, 0) * outOfDeadzoneL / 32767.0;
|
||||
xiLJoyLeft: Result := Min(s.Gamepad.sThumbLX, 0) * outOfDeadzoneL / 32767.0;
|
||||
|
||||
xiRJoyUp: Result := s.Gamepad.sThumbRY * outOfDeadzoneR / 32767.0;
|
||||
xiRJoyDown: Result := s.Gamepad.sThumbRY * outOfDeadzoneR / 32767.0;
|
||||
xiRJoyRight: Result := s.Gamepad.sThumbRX * outOfDeadzoneR / 32767.0;
|
||||
xiRJoyLeft: Result := s.Gamepad.sThumbRX * outOfDeadzoneR / 32767.0;
|
||||
|
||||
xiL2: Result := IfThen(s.Gamepad.bLeftTrigger > XInputDeadzoneTrigger, s.Gamepad.bLeftTrigger / 255.0, 0);
|
||||
xiR2: Result := IfThen(s.Gamepad.bRightTrigger > XInputDeadzoneTrigger, s.Gamepad.bLeftTrigger / 255.0, 0);
|
||||
else Result := 0;
|
||||
end;
|
||||
|
||||
end else begin
|
||||
// is button
|
||||
Result := IfThen(XInputIsTriggered(xinputButton, s), 1.0, 0.0);
|
||||
end;
|
||||
|
||||
// clamp between 0 and 1
|
||||
Result := Max(Min(Abs(Result), 1.0), 0.00);
|
||||
end;
|
||||
|
||||
function TMappableInputs.PS4IsPressed(input: EnumPS4Buttons; s: TXInputState): boolean;
|
||||
begin
|
||||
Result := XInputIsTriggered(PS4toXInput[Ord(input)], s);
|
||||
end;
|
||||
|
||||
function TMappableInputs.LoadFromFile(filePath: string): boolean;
|
||||
var
|
||||
iniFile: TIniFile;
|
||||
i: integer;
|
||||
xInputButton : Integer;
|
||||
begin
|
||||
Result := False;
|
||||
|
||||
if not FileExists(filePath) then exit;
|
||||
|
||||
iniFile := TIniFile.Create(filePath);
|
||||
Self.XInputEnabled := iniFile.ReadBool('XInput', 'XInputEnabled', True);
|
||||
Self.XInputDeadzoneLeft := iniFile.ReadInteger('XInput', 'XInputDeadzoneLeft', XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
|
||||
Self.XInputDeadzoneRight := iniFile.ReadInteger('XInput', 'XInputDeadzoneRight', XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);
|
||||
Self.XInputDeadzoneTrigger := iniFile.ReadInteger('XInput', 'XInputDeadzoneTrigger', XINPUT_GAMEPAD_TRIGGER_THRESHOLD);
|
||||
for i := 1 to NUM_PS4_BUTTONS do
|
||||
begin
|
||||
xInputButton := iniFile.ReadInteger('XInput', GetEnumName(TypeInfo(EnumPS4Buttons), i), 0);
|
||||
SetXInputMapping(EnumPS4Buttons(i), EnumXInputButtons(xInputButton));
|
||||
end;
|
||||
iniFile.Free;
|
||||
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TMappableInputs.SaveToFile(filePath: string): boolean;
|
||||
var
|
||||
iniFile: TIniFile;
|
||||
i: integer;
|
||||
xInputButton : Integer;
|
||||
begin
|
||||
Result := False;
|
||||
|
||||
iniFile := TIniFile.Create(filePath);
|
||||
iniFile.WriteBool('XInput', 'XInputEnabled', Self.XInputEnabled);
|
||||
iniFile.WriteInteger('XInput', 'XInputDeadzoneLeft', Self.XInputDeadzoneLeft);
|
||||
iniFile.WriteInteger('XInput', 'XInputDeadzoneRight', Self.XInputDeadzoneRight);
|
||||
iniFile.WriteInteger('XInput', 'XInputDeadzoneTrigger', Self.XInputDeadzoneTrigger);
|
||||
for i := 1 to NUM_PS4_BUTTONS do
|
||||
begin
|
||||
xInputButton := Ord(PS4toXInput[i]);
|
||||
iniFile.WriteInteger('XInput', GetEnumName(TypeInfo(EnumPS4Buttons), i), xInputButton);
|
||||
end;
|
||||
iniFile.Free;
|
||||
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TMappableInputs.XInputIsTriggered(input: EnumXInputButtons; state: TXInputState): boolean;
|
||||
begin
|
||||
case (input) of
|
||||
xiLJoyUp: Result := state.Gamepad.sThumbLY > self.XInputDeadzoneLeft;
|
||||
xiLJoyDown: Result := state.Gamepad.sThumbLY < -self.XInputDeadzoneLeft;
|
||||
xiLJoyLeft: Result := state.Gamepad.sThumbLX < -self.XInputDeadzoneLeft;
|
||||
xiLJoyRight: Result := state.Gamepad.sThumbLX > self.XInputDeadzoneLeft;
|
||||
|
||||
xiRJoyUp: Result := state.Gamepad.sThumbRY > self.XInputDeadzoneRight;
|
||||
xiRJoyDown: Result := state.Gamepad.sThumbRY < -self.XInputDeadzoneRight;
|
||||
xiRJoyLeft: Result := state.Gamepad.sThumbRX < -self.XInputDeadzoneRight;
|
||||
xiRJoyRight: Result := state.Gamepad.sThumbRX > self.XInputDeadzoneRight;
|
||||
|
||||
xiA: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_A) <> 0;
|
||||
xiB: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_B) <> 0;
|
||||
xiX: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_X) <> 0;
|
||||
xiY: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_Y) <> 0;
|
||||
|
||||
xiDPadUp: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_DPAD_UP) <> 0;
|
||||
xiDPadDown: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_DPAD_DOWN) <> 0;
|
||||
xiDPadLeft: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_DPAD_LEFT) <> 0;
|
||||
xiDPadRight: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_DPAD_RIGHT) <> 0;
|
||||
|
||||
xiSelect: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_BACK) <> 0;
|
||||
xiStart: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_START) <> 0;
|
||||
|
||||
xiL1: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_LEFT_SHOULDER) <> 0;
|
||||
xiL2: Result := state.Gamepad.bLeftTrigger > self.XInputDeadzoneTrigger;
|
||||
xiL3: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_LEFT_THUMB) <> 0;
|
||||
xiR1: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_RIGHT_SHOULDER) <> 0;
|
||||
xiR2: Result := state.Gamepad.bRightTrigger > self.XInputDeadzoneTrigger;
|
||||
xiR3: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_RIGHT_THUMB) <> 0;
|
||||
else Result := false;
|
||||
end;
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
MappableInputs := TMappableInputs.Create;
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiUnbound)] := 'Unbound';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiLJoyUp)] := 'LJOY_UP';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiLJoyDown)] := 'LJOY_DOWN';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiLJoyLeft)] := 'LJOY_LEFT';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiLJoyRight)] := 'LJOY_RIGHT';
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiRJoyUp)] := 'RJOY_UP';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiRJoyDown)] := 'RJOY_DOWN';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiRJoyLeft)] := 'RJOY_LEFT';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiRJoyRight)] := 'RJOY_RIGHT';
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiDPadUp)] := 'DPAD_UP';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiDPadDown)] := 'DPAD_DOWN';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiDPadLeft)] := 'DPAD_LEFT';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiDPadRight)] := 'DPAD_RIGHT';
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiA)] := 'A';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiB)] := 'B';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiX)] := 'X';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiY)] := 'Y';
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiSelect)] := 'SELECT';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiUnused01)] := 'UNUSED01';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiStart)] := 'START';
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiL1)] := 'L1';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiL2)] := 'L2';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiL3)] := 'L3';
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiR1)] := 'R1';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiR2)] := 'R2';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiR3)] := 'R3';
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiUnbound)] := 'Unbound';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiLJoyUp)] := 'LJOY_UP';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiLJoyDown)] := 'LJOY_DOWN';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiLJoyLeft)] := 'LJOY_LEFT';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiLJoyRight)] := 'LJOY_RIGHT';
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiRJoyUp)] := 'RJOY_UP';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiRJoyDown)] := 'RJOY_DOWN';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiRJoyLeft)] := 'RJOY_LEFT';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiRJoyRight)] := 'RJOY_RIGHT';
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiDPadUp)] := 'DPAD_UP';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiDPadDown)] := 'DPAD_DOWN';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiDPadLeft)] := 'DPAD_LEFT';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiDPadRight)] := 'DPAD_RIGHT';
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiA)] := 'A';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiB)] := 'B';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiX)] := 'X';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiY)] := 'Y';
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiSelect)] := 'SELECT';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiUnused01)] := 'UNUSED01';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiStart)] := 'START';
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiL1)] := 'L1';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiL2)] := 'L2';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiL3)] := 'L3';
|
||||
|
||||
MappableInputs.XInputButtonsNames[Ord(xiR1)] := 'R1';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiR2)] := 'R2';
|
||||
MappableInputs.XInputButtonsNames[Ord(xiR3)] := 'R3';
|
||||
|
||||
// Default mapping
|
||||
MappableInputs.XInputEnabled := True;
|
||||
MappableInputs.XInputDeadzoneLeft := XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;
|
||||
MappableInputs.XInputDeadzoneRight := XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;
|
||||
MappableInputs.XInputDeadzoneTrigger := XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
|
||||
MappableInputs.SetXInputMapping(miUnbound, xiUnbound);
|
||||
MappableInputs.SetXInputMapping(miLJoyUp, xiLJoyUp);
|
||||
MappableInputs.SetXInputMapping(miLJoyDown, xiLJoyDown);
|
||||
MappableInputs.SetXInputMapping(miLJoyLeft, xiLJoyLeft);
|
||||
MappableInputs.SetXInputMapping(miLJoyRight, xiLJoyRight);
|
||||
MappableInputs.SetXInputMapping(miRJoyUp, xiRJoyUp);
|
||||
MappableInputs.SetXInputMapping(miRJoyDown, xiRJoyDown);
|
||||
MappableInputs.SetXInputMapping(miRJoyLeft, xiRJoyLeft);
|
||||
MappableInputs.SetXInputMapping(miRJoyRight, xiRJoyRight);
|
||||
MappableInputs.SetXInputMapping(miDPadUp, xiDPadUp);
|
||||
MappableInputs.SetXInputMapping(miDPadDown, xiDPadDown);
|
||||
MappableInputs.SetXInputMapping(miDPadLeft, xiDPadLeft);
|
||||
MappableInputs.SetXInputMapping(miDPadRight, xiDPadRight);
|
||||
MappableInputs.SetXInputMapping(miCross, xiA);
|
||||
MappableInputs.SetXInputMapping(miCircle, xiB);
|
||||
MappableInputs.SetXInputMapping(miSquare, xiX);
|
||||
MappableInputs.SetXInputMapping(miTriangle, xiY);
|
||||
MappableInputs.SetXInputMapping(miShare, xiUnbound);
|
||||
MappableInputs.SetXInputMapping(miTouchPad, xiSelect);
|
||||
MappableInputs.SetXInputMapping(miOptions, xiStart);
|
||||
MappableInputs.SetXInputMapping(miL1, xiL1);
|
||||
MappableInputs.SetXInputMapping(miL2, xiL2);
|
||||
MappableInputs.SetXInputMapping(miL3, xiL3);
|
||||
MappableInputs.SetXInputMapping(miR1, xiR1);
|
||||
MappableInputs.SetXInputMapping(miR2, xiR2);
|
||||
MappableInputs.SetXInputMapping(miR3, xiR3);
|
||||
|
||||
MappableInputs.LoadFromFile(XINPUT_CONFIG_FILE);
|
||||
end.
|
|
@ -11,12 +11,13 @@ uses
|
|||
sys_signal,
|
||||
Classes,
|
||||
SysUtils,
|
||||
xinput;
|
||||
xinput,
|
||||
formController;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
ps4_libSceVideoOut;
|
||||
ps4_libSceVideoOut, uMappableInputs;
|
||||
|
||||
const
|
||||
SCE_PAD_ERROR_INVALID_ARG =-2137915391; // 0x80920001
|
||||
|
@ -313,7 +314,7 @@ end;
|
|||
function ps4_scePadReadState(handle:Integer;data:PScePadData):Integer; SysV_ABI_CDecl;
|
||||
var
|
||||
mPoint,delta:TPoint;
|
||||
controllerState:TXInputState;
|
||||
cs:TXInputState;
|
||||
controllerIndex,stateResult:DWORD;
|
||||
|
||||
function GetAsyncKeyState(vKey:longint):Boolean; inline;
|
||||
|
@ -354,7 +355,7 @@ begin
|
|||
if GetTickCount64 > xinput_last_poll + 10000 then
|
||||
begin
|
||||
for controllerIndex := 0 to XUSER_MAX_COUNT - 1 do
|
||||
xinput_controllers_connected[controllerIndex] := XInputGetState(controllerIndex, controllerState) <> ERROR_DEVICE_NOT_CONNECTED;
|
||||
xinput_controllers_connected[controllerIndex] := XInputGetState(controllerIndex, cs) <> ERROR_DEVICE_NOT_CONNECTED;
|
||||
|
||||
xinput_last_poll := GetTickCount64;
|
||||
end;
|
||||
|
@ -362,63 +363,58 @@ begin
|
|||
// xinput for controllers
|
||||
for controllerIndex := 0 to XUSER_MAX_COUNT - 1 do
|
||||
begin
|
||||
if not MappableInputs.XInputEnabled then break;
|
||||
if not xinput_controllers_connected[controllerIndex] then
|
||||
continue;
|
||||
ZeroMemory(@controllerState, SizeOf(controllerState));
|
||||
stateResult := XInputGetState(controllerIndex, controllerState);
|
||||
ZeroMemory(@cs, SizeOf(cs));
|
||||
stateResult := XInputGetState(controllerIndex, cs);
|
||||
|
||||
if stateResult = ERROR_SUCCESS then
|
||||
begin
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_A) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miCross, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CROSS;
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_B) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miCircle, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CIRCLE;
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_X) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miSquare, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_SQUARE;
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_Y) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miTriangle, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_TRIANGLE;
|
||||
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_START) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miOptions, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_OPTIONS;
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_BACK) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miTouchPad, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_TOUCH_PAD;
|
||||
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_LEFT_SHOULDER) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miL1, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L1;
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_RIGHT_SHOULDER) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miR1, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R1;
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_LEFT_THUMB) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miL3, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L3;
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_RIGHT_THUMB) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miR3, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R3;
|
||||
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_DPAD_UP) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miDPadUp, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_UP;
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_DPAD_DOWN) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miDPadDown, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_DOWN;
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_DPAD_LEFT) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miDPadLeft, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_LEFT;
|
||||
if (controllerState.Gamepad.wButtons and XINPUT_GAMEPAD_DPAD_RIGHT) <> 0 then
|
||||
if MappableInputs.PS4IsPressed(miDPadRight, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_RIGHT;
|
||||
|
||||
if (Abs(controllerState.Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) then
|
||||
data^.leftStick.x:=Trunc(((controllerState.Gamepad.sThumbLX / 32767.0)*0.5+0.5)*255);
|
||||
if (Abs(controllerState.Gamepad.sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) then
|
||||
data^.leftStick.y:=Trunc(255-((controllerState.Gamepad.sThumbLY / 32767.0)*0.5+0.5)*255);
|
||||
data^.leftStick.x:=Trunc(128+(MappableInputs.GetAnalog(miLJoyRight, cs)-MappableInputs.GetAnalog(miLJoyLeft, cs))*127);
|
||||
data^.leftStick.y:=Trunc(128+(MappableInputs.GetAnalog(miLJoyDown, cs)-MappableInputs.GetAnalog(miLJoyUp, cs))*127);
|
||||
|
||||
if (Abs(controllerState.Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) then
|
||||
data^.rightStick.x:=Trunc(((controllerState.Gamepad.sThumbRX / 32767.0)*0.5+0.5)*255);
|
||||
if (Abs(controllerState.Gamepad.sThumbRY) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) then
|
||||
data^.rightStick.y:=Trunc(255-((controllerState.Gamepad.sThumbRY / 32767.0)*0.5+0.5)*255);
|
||||
data^.rightStick.x:=Trunc(128+(MappableInputs.GetAnalog(miRJoyRight, cs)-MappableInputs.GetAnalog(miRJoyLeft, cs))*127);
|
||||
data^.rightStick.y:=Trunc(128+(MappableInputs.GetAnalog(miLJoyDown, cs)-MappableInputs.GetAnalog(miLJoyUp, cs))*127);
|
||||
|
||||
if (controllerState.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) then
|
||||
data^.analogButtons.l2:=controllerState.Gamepad.bLeftTrigger;
|
||||
if (controllerState.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) then
|
||||
data^.analogButtons.r2:=controllerState.Gamepad.bRightTrigger;
|
||||
data^.analogButtons.l2:=Trunc(MappableInputs.GetAnalog(miL2, cs)*255);
|
||||
data^.analogButtons.r2:=Trunc(MappableInputs.GetAnalog(miR2, cs)*255);
|
||||
|
||||
if (controllerState.Gamepad.bLeftTrigger > 250) then
|
||||
if MappableInputs.PS4IsPressed(miL2, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L2;
|
||||
if (controllerState.Gamepad.bRightTrigger > 250) then
|
||||
if MappableInputs.PS4IsPressed(miR2, cs) then
|
||||
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R2;
|
||||
end;
|
||||
end;
|
||||
|
|
|
@ -257,7 +257,8 @@ uses
|
|||
ps4_time,
|
||||
spinlock,
|
||||
hamt,
|
||||
param_sfo;
|
||||
param_sfo,
|
||||
formController;
|
||||
|
||||
type
|
||||
PQNode=^TQNode;
|
||||
|
@ -542,6 +543,11 @@ begin
|
|||
|
||||
UnlockRealizeBounds;
|
||||
end;
|
||||
|
||||
if Key = VK_ESCAPE then
|
||||
begin
|
||||
FormControllers.Show;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TVideoOut.OnVblank(Sender:TObject);
|
||||
|
@ -585,10 +591,13 @@ begin
|
|||
FForm.SetCaptionFPS(0);
|
||||
FForm.OnClose:=@FForm.CloseEvent;
|
||||
FForm.OnKeyDown:=@FForm.KeyEvent;
|
||||
FForm.Position:=poScreenCenter;
|
||||
|
||||
Application.UpdateMainForm(FForm);
|
||||
FForm.Show;
|
||||
|
||||
Application.CreateForm(TFormControllers, FormControllers);
|
||||
|
||||
FGpuFlip:=TvFlip.Create(FForm.Handle);
|
||||
FGpuFlip.FNeoMode:=ps4_sceKernelIsNeoMode<>0;
|
||||
|
||||
|
|
Loading…
Reference in New Issue