Add XInput UI for mapping buttons (#39)

Perfectly!
This commit is contained in:
flyingtincan 2022-12-30 10:43:33 -05:00 committed by GitHub
parent 27aff1b54c
commit d6d45ba1a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 1484 additions and 40 deletions

View File

@ -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>

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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;