diff --git a/fpPS4.lpi b/fpPS4.lpi index 525be1d5..7993a06e 100644 --- a/fpPS4.lpi +++ b/fpPS4.lpi @@ -31,7 +31,7 @@ - + @@ -513,21 +513,42 @@ - + + + + + - + + - + + + + + - + + + + + + + + + + + + + diff --git a/src/inputs/formbindbutton.lfm b/src/inputs/formbindbutton.lfm new file mode 100644 index 00000000..853d32a9 --- /dev/null +++ b/src/inputs/formbindbutton.lfm @@ -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 diff --git a/src/inputs/formbindbutton.pas b/src/inputs/formbindbutton.pas new file mode 100644 index 00000000..80260e44 --- /dev/null +++ b/src/inputs/formbindbutton.pas @@ -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. diff --git a/src/inputs/formcontroller.lfm b/src/inputs/formcontroller.lfm new file mode 100644 index 00000000..c9d45ad5 --- /dev/null +++ b/src/inputs/formcontroller.lfm @@ -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 diff --git a/src/inputs/formcontroller.pas b/src/inputs/formcontroller.pas new file mode 100644 index 00000000..dc5ceaec --- /dev/null +++ b/src/inputs/formcontroller.pas @@ -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. diff --git a/src/inputs/umappableinputs.pas b/src/inputs/umappableinputs.pas new file mode 100644 index 00000000..3c7f6f9d --- /dev/null +++ b/src/inputs/umappableinputs.pas @@ -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. diff --git a/src/ps4_libscepad.pas b/src/ps4_libscepad.pas index 2f4bf084..05013830 100644 --- a/src/ps4_libscepad.pas +++ b/src/ps4_libscepad.pas @@ -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; diff --git a/src/ps4_libscevideoout.pas b/src/ps4_libscevideoout.pas index d90f5a50..e9370beb 100644 --- a/src/ps4_libscevideoout.pas +++ b/src/ps4_libscevideoout.pas @@ -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;