diff --git a/fpPS4.lpi b/fpPS4.lpi
index 91cdbce9..8703b2d5 100644
--- a/fpPS4.lpi
+++ b/fpPS4.lpi
@@ -31,7 +31,7 @@
-
+
@@ -640,6 +640,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fpPS4.lpr b/fpPS4.lpr
index ecdf9a20..0d8e0bdb 100644
--- a/fpPS4.lpr
+++ b/fpPS4.lpr
@@ -94,13 +94,15 @@ begin
Writeln('Copyright (c) 2021-2023 by red-prig');
Writeln('PS4 compatibility layer (emulator) written with Free Pascal '+{$I %FPCVERSION%});
Writeln(' Parameters:');
- Writeln(' -e //Decrypted ELF or SELF file name');
- Writeln(' -f //Folder of app (/app0)');
- Writeln(' -p //Folder of patch (/app1)');
- Writeln(' -s //Savedata path');
- Writeln(' -w //Fullscreen mode');
+ Writeln(' -e //Decrypted ELF or SELF file name');
+ Writeln(' -f //Folder of app (/app0)');
+ Writeln(' -p //Folder of patch (/app1)');
+ Writeln(' -s //Savedata path');
+ Writeln(' -w //Fullscreen mode');
+ Writeln(' -pad //Gamepad interface selection (xinput,sdl2,keyboard) default:xinput');
+ Writeln(' -led //Initial LED color of Gamepad ($rrggbb)');
- Writeln(' -h //enable hack');
+ Writeln(' -h //enable hack');
Writeln(' DEPTH_DISABLE_HACK //Disables depth buffer');
Writeln(' COMPUTE_DISABLE_HACK //Disables compute shaders');
Writeln(' MEMORY_BOUND_HACK //Limits the amount of GPU allocated memory (iGPU)');
@@ -117,12 +119,14 @@ begin
For i:=1 to ParamCount do
begin
case LowerCase(ParamStr(i)) of
- '-e':n:=0;
- '-f':n:=1;
- '-p':n:=2;
- '-s':n:=3;
- '-h':n:=4;
- '-w':ps4_libSceVideoOut.FULLSCREEN_MODE:=True;
+ '-e':n:=0;
+ '-f':n:=1;
+ '-p':n:=2;
+ '-s':n:=3;
+ '-h':n:=4;
+ '-w':ps4_libSceVideoOut.FULLSCREEN_MODE:=True;
+ '-pad':n:=5;
+ '-led':n:=6;
else
if (n<>-1) then
begin
@@ -147,6 +151,12 @@ begin
3:begin
ps4_app.save_path:=Trim(ParamStr(i));
end;
+ 5:begin
+ select_pad_interface(Trim(ParamStr(i)));
+ end;
+ 6:begin
+ select_led_color(Trim(ParamStr(i)));
+ end;
4:begin
case UpperCase(ParamStr(i)) of
'DEPTH_DISABLE_HACK' :ps4_videodrv.DEPTH_DISABLE_HACK:=True;
@@ -475,7 +485,6 @@ begin
_pthread_run_entry(@main,GetSceUserMainThreadName,GetSceUserMainThreadStackSize);
ps4_libSceVideoOut.App_Run;
-
//KillALLThreads TODO
//readln;
end.
diff --git a/src/inputs/kbm_pad_interface.pas b/src/inputs/kbm_pad_interface.pas
new file mode 100644
index 00000000..8d9a8eb1
--- /dev/null
+++ b/src/inputs/kbm_pad_interface.pas
@@ -0,0 +1,183 @@
+unit kbm_pad_interface;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+ Windows,
+ sysutils,
+ spinlock,
+ sce_pad_types,
+ sce_pad_interface;
+
+type
+ TKbmPadHandle=class(TScePadHandle)
+ function ReadState(data:PScePadData):Integer; override;
+ end;
+
+ TKbmPadInterface=class(TScePadInterface)
+ class function Open(index:Integer;var handle:TScePadHandle):Integer; override;
+ end;
+
+ TMouseAsTouchpad=class
+ class var
+ last_mouse_lock :Pointer;
+ last_mouse_point:TPoint;
+ last_mouse_init :Integer;
+ class function ReadState(data:PScePadData):Integer;
+ end;
+
+implementation
+
+class function TKbmPadInterface.Open(index:Integer;var handle:TScePadHandle):Integer;
+begin
+ Result:=0;
+ if (index<0) or (index>15) then Exit(SCE_PAD_ERROR_INVALID_ARG);
+ if (pad_opened[index]<>nil) then Exit(SCE_PAD_ERROR_ALREADY_OPENED);
+
+ handle:=TKbmPadHandle.Create;
+ TKbmPadHandle(handle).index:=index;
+
+ pad_opened[index]:=handle;
+end;
+
+function GetAsyncKeyState(vKey:longint):Boolean; inline;
+begin
+ Result:=(Windows.GetKeyState(vKey) and $8000)<>0;
+end;
+
+class function TMouseAsTouchpad.ReadState(data:PScePadData):Integer;
+var
+ mPoint,delta:TPoint;
+begin
+ Result:=0;
+
+ //mouse as touch pad
+
+ spin_lock(last_mouse_lock);
+
+ GetCursorPos(mPoint);
+
+ if (last_mouse_init=0) then
+ begin
+ last_mouse_init :=1;
+ last_mouse_point:=mPoint;
+ end else
+ if QWORD(mPoint)<>QWORD(last_mouse_point) then
+ begin
+ data^.touchData.touchNum:=1;
+ data^.touchData.touch[0].id:=0;
+
+ delta:=mPoint;
+
+ if (delta.X<0) then delta.X:=0;
+ if (delta.Y<0) then delta.Y:=0;
+
+ if (delta.X>1919) then delta.X:=1919;
+ if (delta.Y>941) then delta.Y:=941;
+
+ data^.touchData.touch[0].x:=delta.X;
+ data^.touchData.touch[0].y:=delta.Y;
+
+ last_mouse_point:=mPoint;
+ end;
+
+ spin_unlock(last_mouse_lock);
+
+ if GetAsyncKeyState(VK_LBUTTON) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_TOUCH_PAD;
+end;
+
+function TKbmPadHandle.ReadState(data:PScePadData):Integer;
+begin
+ Result:=0;
+
+ TMouseAsTouchpad.ReadState(data);
+
+ //keymapping
+
+ if GetAsyncKeyState(VK_W) then
+ data^.leftStick.y:=0;
+
+ if GetAsyncKeyState(VK_S) then
+ data^.leftStick.y:=$FF;
+
+ if GetAsyncKeyState(VK_A) then
+ data^.leftStick.x:=0;
+
+ if GetAsyncKeyState(VK_D) then
+ data^.leftStick.x:=$FF;
+
+ //
+
+ if GetAsyncKeyState(VK_I) then
+ data^.rightStick.y:=0;
+
+ if GetAsyncKeyState(VK_K) then
+ data^.rightStick.y:=$FF;
+
+ if GetAsyncKeyState(VK_J) then
+ data^.rightStick.x:=0;
+
+ if GetAsyncKeyState(VK_L) then
+ data^.rightStick.x:=$FF;
+
+ //
+
+ if GetAsyncKeyState(VK_RETURN) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_OPTIONS;
+
+ if GetAsyncKeyState(VK_UP) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_UP;
+
+ if GetAsyncKeyState(VK_RIGHT) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_RIGHT;
+
+ if GetAsyncKeyState(VK_DOWN) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_DOWN;
+
+ if GetAsyncKeyState(VK_LEFT) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_LEFT;
+
+ if GetAsyncKeyState(VK_NUMPAD8) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_TRIANGLE;
+
+ if GetAsyncKeyState(VK_NUMPAD6) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CIRCLE;
+
+ if GetAsyncKeyState(VK_NUMPAD2) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CROSS;
+
+ if GetAsyncKeyState(VK_NUMPAD4) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_SQUARE;
+
+ if GetAsyncKeyState(VK_Q) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L1;
+
+ if GetAsyncKeyState(VK_1) then
+ begin
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L2;
+ data^.analogButtons.l2:=255;
+ end;
+
+ if GetAsyncKeyState(VK_Z) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L3;
+
+
+ if GetAsyncKeyState(VK_E) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R1;
+
+ if GetAsyncKeyState(VK_4) then
+ begin
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R2;
+ data^.analogButtons.r2:=255;
+ end;
+
+ if GetAsyncKeyState(VK_C) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R3;
+
+end;
+
+end.
+
diff --git a/src/inputs/sce_pad_interface.pas b/src/inputs/sce_pad_interface.pas
new file mode 100644
index 00000000..b2b8e992
--- /dev/null
+++ b/src/inputs/sce_pad_interface.pas
@@ -0,0 +1,95 @@
+unit sce_pad_interface;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+ sce_pad_types,
+ ps4_handles;
+
+type
+ TScePadHandle=class(TClassHandle)
+ var
+ handle:Integer;
+ index:Integer;
+ function ReadState(data:PScePadData):Integer; virtual;
+ function SetLightBar(data:pScePadLightBarParam):Integer; virtual;
+ function ResetLightBar():Integer; virtual;
+ destructor Destroy; override;
+ end;
+
+ TScePadInterface=class
+ class function Load:Boolean; virtual;
+ class procedure Unload; virtual;
+ class function Init:Integer; virtual;
+ class function Done:Integer; virtual;
+ class function Open(index:Integer;var handle:TScePadHandle):Integer; virtual;
+ end;
+
+ TAbstractScePadInterface=class of TScePadInterface;
+
+var
+ pad_handles:TIntegerHandles;
+ pad_opened :array[0..15] of TScePadHandle;
+
+implementation
+
+function TScePadHandle.ReadState(data:PScePadData):Integer;
+begin
+ Result:=SCE_PAD_ERROR_INVALID_HANDLE;
+end;
+
+function TScePadHandle.SetLightBar(data:pScePadLightBarParam):Integer;
+begin
+ Result:=0;
+end;
+
+function TScePadHandle.ResetLightBar():Integer;
+begin
+ Result:=0;
+end;
+
+destructor TScePadHandle.Destroy;
+begin
+ if (index>=0) and (index<16) then
+ begin
+ pad_opened[index]:=nil;
+ end;
+ inherited;
+end;
+
+class function TScePadInterface.Load:Boolean;
+begin
+ Result:=True;
+end;
+
+class procedure TScePadInterface.Unload;
+begin
+ //
+end;
+
+
+class function TScePadInterface.Init:Integer;
+begin
+ Result:=0;
+end;
+
+class function TScePadInterface.Done:Integer;
+begin
+ Result:=0;
+end;
+
+class function TScePadInterface.Open(index:Integer;var handle:TScePadHandle):Integer;
+begin
+ handle:=nil;
+ Result:=SCE_PAD_ERROR_NOT_INITIALIZED;
+end;
+
+initialization
+ pad_handles:=TIntegerHandles.Create(0);
+ pad_handles.max_key:=16;
+
+end.
+
+
diff --git a/src/inputs/sce_pad_types.pas b/src/inputs/sce_pad_types.pas
new file mode 100644
index 00000000..9f940c00
--- /dev/null
+++ b/src/inputs/sce_pad_types.pas
@@ -0,0 +1,283 @@
+unit sce_pad_types;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+const
+ SCE_PAD_ERROR_INVALID_ARG =-2137915391; // 0x80920001
+ SCE_PAD_ERROR_INVALID_PORT =-2137915390; // 0x80920002
+ SCE_PAD_ERROR_INVALID_HANDLE =-2137915389; // 0x80920003
+ SCE_PAD_ERROR_ALREADY_OPENED =-2137915388; // 0x80920004
+ SCE_PAD_ERROR_NOT_INITIALIZED =-2137915387; // 0x80920005
+ SCE_PAD_ERROR_INVALID_LIGHTBAR_SETTING=-2137915386; // 0x80920006
+ SCE_PAD_ERROR_DEVICE_NOT_CONNECTED =-2137915385; // 0x80920007
+ SCE_PAD_ERROR_NO_HANDLE =-2137915384; // 0x80920008
+ SCE_PAD_ERROR_FATAL =-2137915137; // 0x809200FF
+
+ //ScePadButtonDataOffset
+ SCE_PAD_BUTTON_L3 = $00000002;
+ SCE_PAD_BUTTON_R3 = $00000004;
+ SCE_PAD_BUTTON_OPTIONS = $00000008;
+ SCE_PAD_BUTTON_UP = $00000010;
+ SCE_PAD_BUTTON_RIGHT = $00000020;
+ SCE_PAD_BUTTON_DOWN = $00000040;
+ SCE_PAD_BUTTON_LEFT = $00000080;
+ SCE_PAD_BUTTON_L2 = $00000100;
+ SCE_PAD_BUTTON_R2 = $00000200;
+ SCE_PAD_BUTTON_L1 = $00000400;
+ SCE_PAD_BUTTON_R1 = $00000800;
+ SCE_PAD_BUTTON_TRIANGLE = $00001000;
+ SCE_PAD_BUTTON_CIRCLE = $00002000;
+ SCE_PAD_BUTTON_CROSS = $00004000;
+ SCE_PAD_BUTTON_SQUARE = $00008000;
+ SCE_PAD_BUTTON_TOUCH_PAD = $00100000;
+ SCE_PAD_BUTTON_INTERCEPTED = $80000000;
+
+ // This definietion is alias for support old style.
+ SCE_PAD_BUTTON_START=SCE_PAD_BUTTON_OPTIONS;
+
+ //Maximum number of touch points.
+ SCE_PAD_MAX_TOUCH_NUM=2;
+
+ //device unique data size
+ SCE_PAD_MAX_DEVICE_UNIQUE_DATA_SIZE=12;
+
+ SCE_PAD_CONNECTION_TYPE_LOCAL =0;
+ SCE_PAD_CONNECTION_TYPE_REMOTE =1;
+ SCE_PAD_CONNECTION_TYPE_REMOTE_VITA =SCE_PAD_CONNECTION_TYPE_REMOTE;
+ SCE_PAD_CONNECTION_TYPE_REMOTE_DUALSHOCK4=2;
+
+ //ScePadDeviceClass
+ SCE_PAD_DEVICE_CLASS_INVALID = -1;
+ SCE_PAD_DEVICE_CLASS_STANDARD = 0;
+ SCE_PAD_DEVICE_CLASS_GUITAR = 1;
+ SCE_PAD_DEVICE_CLASS_DRUM = 2;
+ SCE_PAD_DEVICE_CLASS_DJ_TURNTABLE = 3;
+ SCE_PAD_DEVICE_CLASS_DANCEMAT = 4;
+ SCE_PAD_DEVICE_CLASS_NAVIGATION = 5;
+ SCE_PAD_DEVICE_CLASS_STEERING_WHEEL = 6;
+ SCE_PAD_DEVICE_CLASS_STICK = 7;
+ SCE_PAD_DEVICE_CLASS_FLIGHT_STICK = 8;
+ SCE_PAD_DEVICE_CLASS_GUN = 9;
+
+ // Personal user
+ SCE_PAD_PORT_TYPE_STANDARD=0; // for standard controller
+ SCE_PAD_PORT_TYPE_SPECIAL =2; // for special controller
+
+ //SYSTEM user(SCE_USER_SERVICE_USER_ID_SYSTEM)
+ SCE_PAD_PORT_TYPE_REMOTE_CONTROL=16; // for remote control(CEC remote control)
+
+type
+ Tvec_float3=packed record
+ x,y,z:Single;
+ end;
+
+ Tvec_float4=packed record
+ x,y,z,w:Single;
+ end;
+
+ ScePadAnalogStick=packed record
+ x,y:Byte;
+ end;
+
+ ScePadAnalogButtons=packed record
+ l2,r2:Byte;
+ padding:Word;
+ end;
+
+ ScePadTouch=packed record
+ x:Word;
+ y:Word;
+ id:Byte;
+ reserve:array[0..2] of Byte;
+ end;
+
+ ScePadTouchData=packed record
+ touchNum:Byte;
+ reserve:array[0..2] of Byte;
+ reserve1:DWORD;
+ touch:array[0..SCE_PAD_MAX_TOUCH_NUM-1] of ScePadTouch;
+ end;
+
+ ScePadExtensionUnitData=packed record
+ extensionUnitId:DWORD;
+ reserve:Byte;
+ dataLength:Byte;
+ data:array[0..9] of Byte;
+ end;
+
+ PScePadData=^ScePadData;
+ ScePadData=packed record
+ buttons :DWORD;
+ leftStick :ScePadAnalogStick;
+ rightStick :ScePadAnalogStick;
+ analogButtons :ScePadAnalogButtons;
+ orientation :Tvec_float4;
+ acceleration :Tvec_float3;
+ angularVelocity :Tvec_float3;
+ touchData :ScePadTouchData;
+ connected :Boolean;
+ _align:array[0..2] of Byte;
+ timestamp :QWORD;
+ extensionUnitData:ScePadExtensionUnitData;
+ connectedCount :Byte;
+ reserve:array[0..1] of Byte;
+ deviceUniqueDataLen:Byte;
+ deviceUniqueData:array[0..SCE_PAD_MAX_DEVICE_UNIQUE_DATA_SIZE-1] of Byte;
+ end;
+
+ ScePadOpenParam=packed record
+ reserve:array[0..7] of Byte;
+ end;
+
+ TPadColor=packed record
+ r,g,b,a:Byte;
+ end;
+
+ PScePadVibrationParam=^ScePadVibrationParam;
+ ScePadVibrationParam=packed record
+ largeMotor:Byte;
+ smallMotor:Byte;
+ end;
+
+ ScePadColor=packed record
+ r:Byte;
+ g:Byte;
+ b:Byte;
+ reserve:Byte;
+ end;
+
+ ScePadLightBarParam=ScePadColor;
+ PScePadLightBarParam=^ScePadLightBarParam;
+
+ ScePadTouchPadInformation=packed record
+ pixelDensity:Single;
+ resolution:packed record
+ x,y:Word;
+ end;
+ end;
+
+ ScePadStickInformation=packed record
+ deadZoneLeft:Byte;
+ deadZoneRight:Byte;
+ end;
+
+ PScePadControllerInformation=^ScePadControllerInformation;
+ ScePadControllerInformation=packed record
+ touchPadInfo:ScePadTouchPadInformation;
+ stickInfo:ScePadStickInformation;
+ connectionType:Byte;
+ connectedCount:Byte;
+ connected:Boolean;
+ _align:array[0..2] of Byte;
+ deviceClass:DWORD; //ScePadDeviceClass
+ reserve:array[0..7] of Byte;
+ end;
+
+ pScePadDeviceClassExtendedInformation=^ScePadDeviceClassExtendedInformation;
+ ScePadDeviceClassExtendedInformation=packed record
+ deviceClass:DWORD; //ScePadDeviceClass
+ reserved:DWORD;
+ classData:packed record
+ Case Byte of
+
+ 0:(steeringWheel:packed record
+ capability:Byte;
+ reserved1:Byte;
+ maxPhysicalWheelAngle:Word;
+ reserved2:QWORD;
+ end);
+
+ 1:(guitar:packed record
+ capability:Byte;
+ quantityOfSelectorSwitch:Byte;
+ reserved1:Word;
+ reserved2:QWORD;
+ end);
+
+ 2:(drum:packed record
+ capability:Byte;
+ reserved1:Byte;
+ reserved2:Word;
+ reserved3:QWORD;
+ end);
+
+ 3:(flightStick:packed record
+ capability:Byte;
+ reserved1:Byte;
+ reserved2:Word;
+ reserved3:QWORD;
+ end);
+
+ 4:(data:array[0..11] of Byte);
+
+ end;
+ end;
+
+ pScePadDeviceClassData=^ScePadDeviceClassData;
+ ScePadDeviceClassData=packed record
+ deviceClass:DWORD; //ScePadDeviceClass
+ bDataValid :Boolean;
+ _align:array[0..2] of Byte;
+ classData:packed record
+ Case Byte of
+
+ 0:(steeringWheel:packed record
+ steeringWheelAngle:Single;
+ steeringWheel :Word;
+ acceleratorPedal :Word;
+ brakePedal :Word;
+ clutchPedal :Word;
+ handBlake :Word;
+ gear :Byte;
+ reserved :Byte;
+ end); //SCE_PAD_DEVICE_CLASS_STEERING_WHEEL
+
+ 1:(guitar:packed record
+ toneNumber:Byte;
+ whammyBar :Byte;
+ tilt :Byte;
+ fret :Byte;
+ fretSolo :Byte;
+ reserved:array[0..10] of Byte;
+ end); //SCE_PAD_DEVICE_CLASS_GUITAR
+
+ 2:(drum:packed record
+ snare :Byte;
+ tom1 :Byte;
+ tom2 :Byte;
+ floorTom :Byte;
+ hihatCymbal:Byte;
+ rideCymbal :Byte;
+ crashCymbal:Byte;
+ reserved:array[0..8] of Byte;
+ end); //SCE_PAD_DEVICE_CLASS_DRUM
+
+ 3:(flightStick:packed record
+ stickAxisX :Word;
+ stickAxisY :Word;
+ stickTwist :Byte;
+ throttle :Byte;
+ trigger :Byte;
+ rudderPedal :Byte;
+ brakePedalLeft :Byte;
+ brakePedalRight:Byte;
+ antennaKnob :Byte;
+ rangeKnob :Byte;
+ reserved:array[0..3] of Byte;
+ end); //SCE_PAD_DEVICE_CLASS_FLIGHT_STICK
+
+ 4:(others:packed record
+ dataLen:Byte;
+ reserved:array[0..2] of Byte;
+ data:array[0..SCE_PAD_MAX_DEVICE_UNIQUE_DATA_SIZE-1] of Byte;
+ end); //Not Supported device
+
+ end;
+ end;
+
+implementation
+
+end.
+
diff --git a/src/inputs/sdl2.pas b/src/inputs/sdl2.pas
new file mode 100644
index 00000000..b2a42083
--- /dev/null
+++ b/src/inputs/sdl2.pas
@@ -0,0 +1,1091 @@
+unit sdl2;
+
+{
+ Clipped headers from "SDL2-for-Pascal"
+}
+
+{$mode objfpc}{$H+}
+
+interface
+
+ {$IFDEF WINDOWS}
+ uses
+ dynlibs,
+ ctypes,
+ Windows;
+ {$ENDIF}
+
+ {$IF DEFINED(UNIX) AND NOT DEFINED(ANDROID)}
+ uses
+ {$IFDEF FPC}
+ ctypes,
+ UnixType,
+ {$ENDIF}
+ {$IFDEF DARWIN}
+ CocoaAll;
+ {$ELSE}
+ X,
+ XLib;
+ {$ENDIF}
+ {$ENDIF}
+
+const
+
+ {$IFDEF WINDOWS}
+ SDL_LibName = 'SDL2.dll';
+ {$ENDIF}
+
+ {$IFDEF UNIX}
+ {$IFDEF DARWIN}
+ SDL_LibName = 'libSDL2.dylib';
+ {$ELSE}
+ SDL_LibName = 'libSDL2.so';
+ {$ENDIF}
+ {$ENDIF}
+
+ {$IFDEF MACOS}
+ SDL_LibName = 'SDL2';
+ {$ENDIF}
+
+type
+ PPSDL_Init = ^PSDL_Init;
+ PSDL_Init = ^TSDL_Init;
+ TSDL_Init = type cuint32;
+
+const
+ SDL_INIT_JOYSTICK = TSDL_Init($00000200); // SDL_INIT_JOYSTICK implies SDL_INIT_EVENTS
+ SDL_INIT_GAMECONTROLLER = TSDL_Init($00002000); //turn on game controller also implicitly does JOYSTICK
+
+type
+ PSDL_ScanCode = ^TSDL_ScanCode;
+ TSDL_ScanCode = type cint;
+
+ PSDL_KeyCode = ^TSDL_KeyCode;
+ TSDL_KeyCode = type cint32;
+
+ PPSDL_Keysym = ^PSDL_Keysym;
+ PSDL_Keysym = ^TSDL_Keysym;
+ TSDL_Keysym = record
+ scancode: TSDL_ScanCode; // SDL physical key code - see SDL_Scancode for details
+ sym: TSDL_KeyCode; // SDL virtual key code - see SDL_Keycode for details
+ mod_: cuint16; // current key modifiers
+ unicode: cuint32; // (deprecated) use SDL_TextInputEvent instead
+ end;
+
+ PSDL_TouchID = ^TSDL_TouchID;
+ TSDL_TouchID = type cint64;
+
+ PSDL_FingerID = ^TSDL_FingerID;
+ TSDL_FingerID = type cint64;
+
+ PSDL_GestureID = ^TSDL_GestureID;
+ TSDL_GestureID = type cint64;
+
+ PSDL_EventType = ^TSDL_EventType;
+ TSDL_EventType = type cuint32;
+
+ PPSDL_GameController = ^PSDL_GameController;
+ PSDL_GameController = ^TSDL_GameController;
+ TSDL_GameController = record end;
+
+ PPSDL_GameControllerType = ^PSDL_GameControllerType;
+ PSDL_GameControllerType = ^TSDL_GameControllerType;
+ TSDL_GameControllerType = type cint;
+
+const
+ SDL_CONTROLLER_TYPE_UNKNOWN = TSDL_GameControllerType(0);
+ SDL_CONTROLLER_TYPE_XBOX360 = TSDL_GameControllerType(1);
+ SDL_CONTROLLER_TYPE_XBOXONE = TSDL_GameControllerType(2);
+ SDL_CONTROLLER_TYPE_PS3 = TSDL_GameControllerType(3);
+ SDL_CONTROLLER_TYPE_PS4 = TSDL_GameControllerType(4);
+ SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO = TSDL_GameControllerType(5);
+ SDL_CONTROLLER_TYPE_VIRTUAL = TSDL_GameControllerType(6);
+ SDL_CONTROLLER_TYPE_PS5 = TSDL_GameControllerType(7);
+ SDL_CONTROLLER_TYPE_AMAZON_LUNA = TSDL_GameControllerType(8);
+ SDL_CONTROLLER_TYPE_GOOGLE_STADIA = TSDL_GameControllerType(9);
+ SDL_CONTROLLER_TYPE_NVIDIA_SHIELD = TSDL_GameControllerType(10);
+ SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT = TSDL_GameControllerType(11);
+ SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT = TSDL_GameControllerType(12);
+ SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR = TSDL_GameControllerType(13);
+
+type
+ PPSDL_GameControllerBindType = ^PSDL_GameControllerBindType;
+ PSDL_GameControllerBindType = ^TSDL_GameControllerBindType;
+ TSDL_GameControllerBindType = type cint;
+
+const
+ SDL_CONTROLLER_BINDTYPE_NONE = TSDL_GameControllerBindType(0);
+ SDL_CONTROLLER_BINDTYPE_BUTTON = TSDL_GameControllerBindType(1);
+ SDL_CONTROLLER_BINDTYPE_AXIS = TSDL_GameControllerBindType(2);
+ SDL_CONTROLLER_BINDTYPE_HAT = TSDL_GameControllerBindType(3);
+
+type
+ THat = record
+ hat: cint;
+ hat_mask: cint;
+ end;
+
+ PPSDL_GameControllerButtonBind = ^PSDL_GameControllerButtonBind;
+ PSDL_GameControllerButtonBind = ^TSDL_GameControllerButtonBind;
+ TSDL_GameControllerButtonBind = record
+ bindType: TSDL_GameControllerBindType;
+ case cint of
+ 0: ( button: cint; );
+ 1: ( axis: cint; );
+ 2: ( hat: THat; );
+ end;
+
+type
+ PPSDL_Joystick = ^PSDL_Joystick;
+ PSDL_Joystick = ^TSDL_Joystick;
+ TSDL_Joystick = record end;
+
+ PPSDL_JoystickGUID = ^PSDL_JoystickGUID;
+ PSDL_JoystickGUID = ^TSDL_JoystickGUID;
+ TSDL_JoystickGUID = type TGUID;
+
+ PPSDL_JoystickID = ^PSDL_JoystickID;
+ PSDL_JoystickID = ^TSDL_JoystickID;
+ TSDL_JoystickID = type cint32;
+
+type
+ PPSDL_JoystickType = ^PSDL_JoystickType;
+ PSDL_JoystickType = ^TSDL_JoystickType;
+ TSDL_JoystickType = type Integer;
+
+const
+ SDL_JOYSTICK_TYPE_UNKNOWN = TSDL_JoystickType(0);
+ SDL_JOYSTICK_TYPE_GAMECONTROLLER = TSDL_JoystickType(1);
+ SDL_JOYSTICK_TYPE_WHEEL = TSDL_JoystickType(2);
+ SDL_JOYSTICK_TYPE_ARCADE_STICK = TSDL_JoystickType(3);
+ SDL_JOYSTICK_TYPE_FLIGHT_STICK = TSDL_JoystickType(4);
+ SDL_JOYSTICK_TYPE_DANCE_PAD = TSDL_JoystickType(5);
+ SDL_JOYSTICK_TYPE_GUITAR = TSDL_JoystickType(6);
+ SDL_JOYSTICK_TYPE_DRUM_KIT = TSDL_JoystickType(7);
+ SDL_JOYSTICK_TYPE_ARCADE_PAD = TSDL_JoystickType(8);
+ SDL_JOYSTICK_TYPE_THROTTLE = TSDL_JoystickType(9);
+
+type
+ PPSDL_JoystickPowerLevel = ^PSDL_JoystickPowerLevel;
+ PSDL_JoystickPowerLevel = ^TSDL_JoystickPowerLevel;
+ TSDL_JoystickPowerLevel = type Integer;
+
+const
+ SDL_JOYSTICK_POWER_UNKNOWN = TSDL_JoystickPowerLevel(-1);
+ SDL_JOYSTICK_POWER_EMPTY = TSDL_JoystickPowerLevel(0); {* <= 5% *}
+ SDL_JOYSTICK_POWER_LOW = TSDL_JoystickPowerLevel(1); {* <= 20% *}
+ SDL_JOYSTICK_POWER_MEDIUM = TSDL_JoystickPowerLevel(2); {* <= 70% *}
+ SDL_JOYSTICK_POWER_FULL = TSDL_JoystickPowerLevel(3); {* <= 100% *}
+ SDL_JOYSTICK_POWER_WIRED = TSDL_JoystickPowerLevel(4);
+ SDL_JOYSTICK_POWER_MAX = TSDL_JoystickPowerLevel(5);
+
+const
+ SDL_IPHONE_MAX_GFORCE = 5.0;
+
+type
+ PPSDL_GameControllerButton = ^PSDL_GameControllerButton;
+ PSDL_GameControllerButton = ^TSDL_GameControllerButton;
+ TSDL_GameControllerButton = type cint;
+
+const
+ SDL_CONTROLLER_BUTTON_INVALID = TSDL_GameControllerButton(-1);
+ SDL_CONTROLLER_BUTTON_A = TSDL_GameControllerButton(0);
+ SDL_CONTROLLER_BUTTON_B = TSDL_GameControllerButton(1);
+ SDL_CONTROLLER_BUTTON_X = TSDL_GameControllerButton(2);
+ SDL_CONTROLLER_BUTTON_Y = TSDL_GameControllerButton(3);
+ SDL_CONTROLLER_BUTTON_BACK = TSDL_GameControllerButton(4);
+ SDL_CONTROLLER_BUTTON_GUIDE = TSDL_GameControllerButton(5);
+ SDL_CONTROLLER_BUTTON_START = TSDL_GameControllerButton(6);
+ SDL_CONTROLLER_BUTTON_LEFTSTICK = TSDL_GameControllerButton(7);
+ SDL_CONTROLLER_BUTTON_RIGHTSTICK = TSDL_GameControllerButton(8);
+ SDL_CONTROLLER_BUTTON_LEFTSHOULDER = TSDL_GameControllerButton(9);
+ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER = TSDL_GameControllerButton(10);
+ SDL_CONTROLLER_BUTTON_DPAD_UP = TSDL_GameControllerButton(11);
+ SDL_CONTROLLER_BUTTON_DPAD_DOWN = TSDL_GameControllerButton(12);
+ SDL_CONTROLLER_BUTTON_DPAD_LEFT = TSDL_GameControllerButton(13);
+ SDL_CONTROLLER_BUTTON_DPAD_RIGHT = TSDL_GameControllerButton(14);
+ SDL_CONTROLLER_BUTTON_MISC1 = TSDL_GameControllerButton(15); {**< Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button *}
+ SDL_CONTROLLER_BUTTON_PADDLE1 = TSDL_GameControllerButton(16); {**< Xbox Elite paddle P1 *}
+ SDL_CONTROLLER_BUTTON_PADDLE2 = TSDL_GameControllerButton(17); {**< Xbox Elite paddle P3 *}
+ SDL_CONTROLLER_BUTTON_PADDLE3 = TSDL_GameControllerButton(18); {**< Xbox Elite paddle P2 *}
+ SDL_CONTROLLER_BUTTON_PADDLE4 = TSDL_GameControllerButton(19); {**< Xbox Elite paddle P4 *}
+ SDL_CONTROLLER_BUTTON_TOUCHPAD = TSDL_GameControllerButton(20); {**< PS4/PS5 touchpad button *}
+ SDL_CONTROLLER_BUTTON_MAX = TSDL_GameControllerButton(21);
+
+type
+ PPSDL_GameControllerAxis = ^PSDL_GameControllerAxis;
+ PSDL_GameControllerAxis = ^TSDL_GameControllerAxis;
+ TSDL_GameControllerAxis = type cint;
+
+const
+ SDL_CONTROLLER_AXIS_INVALID = TSDL_GameControllerAxis(-1);
+ SDL_CONTROLLER_AXIS_LEFTX = TSDL_GameControllerAxis(0);
+ SDL_CONTROLLER_AXIS_LEFTY = TSDL_GameControllerAxis(1);
+ SDL_CONTROLLER_AXIS_RIGHTX = TSDL_GameControllerAxis(2);
+ SDL_CONTROLLER_AXIS_RIGHTY = TSDL_GameControllerAxis(3);
+ SDL_CONTROLLER_AXIS_TRIGGERLEFT = TSDL_GameControllerAxis(4);
+ SDL_CONTROLLER_AXIS_TRIGGERRIGHT = TSDL_GameControllerAxis(5);
+ SDL_CONTROLLER_AXIS_MAX = TSDL_GameControllerAxis(6);
+
+///
+
+const
+
+ { General keyboard/mouse state definitions }
+ SDL_RELEASED = 0;
+ SDL_PRESSED = 1;
+
+ SDL_FIRSTEVENT = TSDL_EventType(0); // Unused (do not remove) (needed in pascal?)
+
+ SDL_COMMONEVENT = TSDL_EventType(1); //added for pascal-compatibility
+
+ { Application events }
+ SDL_QUITEV = TSDL_EventType($100); // User-requested quit (originally SDL_QUIT, but changed, cause theres a method called SDL_QUIT)
+
+
+ { These application events have special meaning on iOS, see README.iOS for details *}
+
+ {* The application is being terminated by the OS. *
+ * Called on iOS in applicationWillTerminate() *
+ * Called on Android in onDestroy() *}
+ SDL_APP_TERMINATING = TSDL_EventType($101);
+
+ {* The application is low on memory, free memory if possible. *
+ * Called on iOS in applicationDidReceiveMemoryWarning() *
+ * Called on Android in onLowMemory() *}
+ SDL_APP_LOWMEMORY = TSDL_EventType($102);
+
+ {* The application is about to enter the background. *
+ * Called on iOS in applicationWillResignActive() *
+ * Called on Android in onPause() *}
+ SDL_APP_WILLENTERBACKGROUND = TSDL_EventType($103);
+
+ {* The application did enter the background and may not get CPU for some time. *
+ * Called on iOS in applicationDidEnterBackground() *
+ * Called on Android in onPause() *}
+ SDL_APP_DIDENTERBACKGROUND = TSDL_EventType($104);
+
+ {* The application is about to enter the foreground. *
+ * Called on iOS in applicationWillEnterForeground() *
+ * Called on Android in onResume() *}
+ SDL_APP_WILLENTERFOREGROUND = TSDL_EventType($105);
+
+ {* The application is now interactive. *
+ * Called on iOS in applicationDidBecomeActive() *
+ * Called on Android in onResume() *}
+ SDL_APP_DIDENTERFOREGROUND = TSDL_EventType($106);
+
+ {* The user's locale preferences have changed. *}
+ SDL_LOCALECHANGED = TSDL_EventType($107);
+
+ { Display events }
+ SDL_DISPLAYEVENT = TSDL_EventType($150); // Display state change
+
+ { Window events }
+ SDL_WINDOWEVENT = TSDL_EventType($200); // Window state change
+ SDL_SYSWMEVENT = TSDL_EventType($201); // System specific event
+
+ { Keyboard events }
+ SDL_KEYDOWN = TSDL_EventType($300); // Key pressed
+ SDL_KEYUP = TSDL_EventType($301); // Key released
+ SDL_TEXTEDITING = TSDL_EventType($302); // Keyboard text editing (composition)
+ SDL_TEXTINPUT = TSDL_EventType($303); // Keyboard text input
+ SDL_KEYMAPCHANGED = TSDL_EventType($304); // Keymap changed due to a system event such as an input language or keyboard layout change.
+ SDL_TEXTEDITING_EXT = TSDL_EventType($305); // Extended keyboard text editing (composition)
+
+ { Mouse events }
+ SDL_MOUSEMOTION = TSDL_EventType($400); // Mouse moved
+ SDL_MOUSEBUTTONDOWN = TSDL_EventType($401); // Mouse button pressed
+ SDL_MOUSEBUTTONUP = TSDL_EventType($402); // Mouse button released
+ SDL_MOUSEWHEEL = TSDL_EventType($403); // Mouse wheel motion
+
+ { Joystick events }
+ SDL_JOYAXISMOTION = TSDL_EventType($600); // Joystick axis motion
+ SDL_JOYBALLMOTION = TSDL_EventType($601); // Joystick trackball motion
+ SDL_JOYHATMOTION = TSDL_EventType($602); // Joystick hat position change
+ SDL_JOYBUTTONDOWN = TSDL_EventType($603); // Joystick button pressed
+ SDL_JOYBUTTONUP = TSDL_EventType($604); // Joystick button released
+ SDL_JOYDEVICEADDED = TSDL_EventType($605); // A new joystick has been inserted into the system
+ SDL_JOYDEVICEREMOVED = TSDL_EventType($606); // An opened joystick has been removed
+ SDL_JOYBATTERYUPDATED = TSDL_EventType($607); // Joystick battery level change
+
+ { Game controller events }
+ SDL_CONTROLLERAXISMOTION = TSDL_EventType($650); // Game controller axis motion
+ SDL_CONTROLLERBUTTONDOWN = TSDL_EventType($651); // Game controller button pressed
+ SDL_CONTROLLERBUTTONUP = TSDL_EventType($652); // Game controller button released
+ SDL_CONTROLLERDEVICEADDED = TSDL_EventType($653); // A new Game controller has been inserted into the system
+ SDL_CONTROLLERDEVICEREMOVED = TSDL_EventType($654); // An opened Game controller has been removed
+ SDL_CONTROLLERDEVICEREMAPPED = TSDL_EventType($655); // The controller mapping was updated
+ SDL_CONTROLLERTOUCHPADDOWN = TSDL_EventType($666); // Game controller touchpad was touched
+ SDL_CONTROLLERTOUCHPADMOTION = TSDL_EventType($667); // Game controller touchpad finger was moved
+ SDL_CONTROLLERTOUCHPADUP = TSDL_EventType($668); // Game controller touchpad finger was lifted
+ SDL_CONTROLLERSENSORUPDATE = TSDL_EventType($669); // Game controller sensor was updated
+
+ { Touch events }
+ SDL_FINGERDOWN = TSDL_EventType($700);
+ SDL_FINGERUP = TSDL_EventType($701);
+ SDL_FINGERMOTION = TSDL_EventType($702);
+
+ { Gesture events }
+ SDL_DOLLARGESTURE = TSDL_EventType($800);
+ SDL_DOLLARRECORD = TSDL_EventType($801);
+ SDL_MULTIGESTURE = TSDL_EventType($802);
+
+ { Clipboard events }
+ SDL_CLIPBOARDUPDATE = TSDL_EventType($900); // The clipboard changed
+
+ { Drag and drop events }
+ SDL_DROPFILE = TSDL_EventType($1000); // The system requests a file open
+ SDL_DROPTEXT = TSDL_EventType($1001); // text/plain drag-and-drop event
+ SDL_DROPBEGIN = TSDL_EventType($1002); // A new set of drops is beginning (NULL filename)
+ SDL_DROPCOMPLETE = TSDL_EventType($1003); // Current set of drops is now complete (NULL filename)
+
+ { Audio hotplug events }
+ SDL_AUDIODEVICEADDED = TSDL_EventType($1100); // A new audio device is available
+ SDL_AUDIODEVICEREMOVED = TSDL_EventType($1101); // An audio device has been removed.
+
+ { Sensor events }
+ SDL_SENSORUPDATED = TSDL_EventType($1200); // A sensor was updated
+
+ { Render events }
+ SDL_RENDER_TARGETS_RESET = TSDL_EventType($2000); // The render targets have been reset
+ SDL_RENDER_DEVICE_RESET = TSDL_EventType($2001); // The device has been reset and all textures need to be recreated
+
+ { Internal events }
+ SDL_POLLSENTINEL = TSDL_EventType($7F00); // Signals the end of an event poll cycle
+
+ {** Events SDL_USEREVENT through SDL_LASTEVENT are for your use,
+ * and should be allocated with SDL_RegisterEvents()
+ *}
+ SDL_USEREVENT = TSDL_EventType($8000);
+
+ {**
+ * This last event is only for bounding internal arrays (needed in pascal ??)
+ *}
+ SDL_LASTEVENT = TSDL_EventType($FFFF);
+
+type
+ {**
+ * Fields shared by every event
+ *}
+ PPSDL_CommonEvent = ^PSDL_CommonEvent;
+ PSDL_CommonEvent = ^TSDL_CommonEvent;
+ TSDL_CommonEvent = record
+ type_: cuint32;
+ timestamp: cuint32;
+ end;
+
+ {**
+ * Display state change event data (event.display.*)
+ *}
+ PPSDL_DisplayEvent = ^PSDL_DisplayEvent;
+ PSDL_DisplayEvent = ^TSDL_DisplayEvent;
+ TSDL_DisplayEvent = record
+ type_: cuint32; // SDL_DISPLAYEVENT
+ timestamp: cuint32; // In milliseconds, populated using SDL_GetTicks()
+ display: cuint32; // The associated display index
+ event: cuint8; // SDL_DisplayEventID
+ padding1: cuint8;
+ padding2: cuint8;
+ padding3: cuint8;
+ data1: cint32; // event dependent data
+ end;
+
+ {**
+ * Window state change event data (event.window.*)
+ *}
+ PPSDL_WindowEvent = ^PSDL_WindowEvent;
+ PSDL_WindowEvent = ^TSDL_WindowEvent;
+ TSDL_WindowEvent = record
+ type_: cuint32; // SDL_WINDOWEVENT
+ timestamp: cuint32;
+ windowID: cuint32; // The associated window
+ event: cuint8; // SDL_WindowEventID
+ padding1: cuint8;
+ padding2: cuint8;
+ padding3: cuint8;
+ data1: cint32; // event dependent data
+ data2: cint32; // event dependent data
+ end;
+
+ {**
+ * Keyboard button event structure (event.key.*)
+ *}
+ PPSDL_KeyboardEvent = ^PSDL_KeyboardEvent;
+ PSDL_KeyboardEvent = ^TSDL_KeyboardEvent;
+ TSDL_KeyboardEvent = record
+ type_: cuint32; // SDL_KEYDOWN or SDL_KEYUP
+ timestamp: cuint32;
+ windowID: cuint32; // The window with keyboard focus, if any
+ state: cuint8; // SDL_PRESSED or SDL_RELEASED
+ repeat_: cuint8; // Non-zero if this is a key repeat
+ padding2: cuint8;
+ padding3: cuint8;
+ keysym: TSDL_KeySym; // The key that was pressed or released
+ end;
+
+const
+ SDL_TEXTEDITINGEVENT_TEXT_SIZE = 32;
+
+type
+ {**
+ * Keyboard text editing event structure (event.edit.*)
+ *}
+ PPSDL_TextEditingEvent = ^PSDL_TextEditingEvent;
+ PSDL_TextEditingEvent = ^TSDL_TextEditingEvent;
+ TSDL_TextEditingEvent = record
+ type_: cuint32; // SDL_TEXTEDITING
+ timestamp: cuint32;
+ windowID: cuint32; // The window with keyboard focus, if any
+ text: array[0..SDL_TEXTEDITINGEVENT_TEXT_SIZE] of Char; // The editing text
+ start: cint32; // The start cursor of selected editing text
+ length: cint32; // The length of selected editing text
+ end;
+
+ {**
+ * Extended keyboard text editing event structure (event.editExt.*) when text would be
+ * truncated if stored in the text buffer SDL_TextEditingEvent
+ *}
+ PPSDL_TextEditingExtEvent = ^PSDL_TextEditingExtEvent;
+ PSDL_TextEditingExtEvent = ^TSDL_TextEditingExtEvent;
+ TSDL_TextEditingExtEvent = record
+ type_: cuint32; // SDL_TEXTEDITING_EXT
+ timestamp: cuint32; // In milliseconds, populated using SDL_GetTicks()
+ windowID: cuint32; // The window with keyboard focus, if any
+ text: PAnsiChar; // The editing text, which should be freed with SDL_free(), and will not be NIL
+ start: cint32; // The start cursor of selected editing text
+ length: cint32; // The length of selected editing text
+ end;
+
+const
+ SDL_TEXTINPUTEVENT_TEXT_SIZE = 32;
+
+type
+
+ {**
+ * Keyboard text input event structure (event.text.*)
+ *}
+ PPSDL_TextInputEvent = ^PSDL_TextInputEvent;
+ PSDL_TextInputEvent = ^TSDL_TextInputEvent;
+ TSDL_TextInputEvent = record
+ type_: cuint32; // SDL_TEXTINPUT
+ timestamp: cuint32;
+ windowID: cuint32; // The window with keyboard focus, if any
+ text: array[0..SDL_TEXTINPUTEVENT_TEXT_SIZE] of Char; // The input text
+ end;
+
+ {**
+ * Mouse motion event structure (event.motion.*)
+ *}
+ PPSDL_MouseMotionEvent = ^PSDL_MouseMotionEvent;
+ PSDL_MouseMotionEvent = ^TSDL_MouseMotionEvent;
+ TSDL_MouseMotionEvent = record
+ type_: cuint32; // SDL_MOUSEMOTION
+ timestamp: cuint32; // In milliseconds, populated using SDL_GetTicks()
+ windowID: cuint32; // The window with mouse focus, if any
+ which: cuint32; // The mouse instance id, or SDL_TOUCH_MOUSEID
+ state: cuint32; // The current button state
+ x: cint32; // X coordinate, relative to window
+ y: cint32; // Y coordinate, relative to window
+ xrel: cint32; // The relative motion in the X direction
+ yrel: cint32; // The relative motion in the Y direction
+ end;
+
+ {**
+ * Mouse button event structure (event.button.*)
+ *}
+ PPSDL_MouseButtonEvent = ^PSDL_MouseButtonEvent;
+ PSDL_MouseButtonEvent = ^TSDL_MouseButtonEvent;
+ TSDL_MouseButtonEvent = record
+ type_: cuint32; // SDL_MOUSEBUTTONDOWN or SDL_MOUSEBUTTONUP
+ timestamp: cuint32;
+ windowID: cuint32; // The window with mouse focus, if any
+ which: cuint32; // The mouse instance id, or SDL_TOUCH_MOUSEID
+ button: cuint8; // The mouse button index
+ state: cuint8; // SDL_PRESSED or SDL_RELEASED
+ clicks: cuint8; // 1 for single-click, 2 for double-click, etc.
+ padding1: cuint8;
+ x: cint32; // X coordinate, relative to window
+ y: cint32; // Y coordinate, relative to window
+ end;
+
+ {**
+ * Mouse wheel event structure (event.wheel.*)
+ *}
+ PPSDL_MouseWheelEvent = ^PSDL_MouseWheelEvent;
+ PSDL_MouseWheelEvent = ^TSDL_MouseWheelEvent;
+ TSDL_MouseWheelEvent = record
+ type_: cuint32; // SDL_MOUSEWHEEL
+ timestamp: cuint32;
+ windowID: cuint32; // The window with mouse focus, if any
+ which: cuint32; // The mouse instance id, or SDL_TOUCH_MOUSEID
+ x: cint32; // The amount scrolled horizontally
+ y: cint32; // The amount scrolled vertically
+ direction: cuint32; // Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back
+ preciseX: cfloat; // The amount scrolled horizontally, positive to the right and negative to the left, with float precision (added in 2.0.18)
+ preciseY: cfloat; // The amount scrolled vertically, positive away from the user and negative toward the user, with float precision (added in 2.0.18)
+ mouseX: cint32; // X coordinate, relative to window (added in 2.26.0)
+ mouseY: cint32; // Y coordinate, relative to window (added in 2.26.0)
+ end;
+
+ {**
+ * Joystick axis motion event structure (event.jaxis.*)
+ *}
+ PPSDL_JoyAxisEvent = ^PSDL_JoyAxisEvent;
+ PSDL_JoyAxisEvent = ^TSDL_JoyAxisEvent;
+ TSDL_JoyAxisEvent = record
+ type_: cuint32; // SDL_JOYAXISMOTION
+ timestamp: cuint32;
+ which: TSDL_JoystickID; // The joystick instance id
+ axis: cuint8; // The joystick axis index
+ padding1: cuint8;
+ padding2: cuint8;
+ padding3: cuint8;
+ value: cint16; // The axis value (range: -32768 to 32767)
+ padding4: cuint16;
+ end;
+
+ {**
+ * Joystick trackball motion event structure (event.jball.*)
+ *}
+ PPSDL_JoyBallEvent = ^PSDL_JoyBallEvent;
+ PSDL_JoyBallEvent = ^TSDL_JoyBallEvent;
+ TSDL_JoyBallEvent = record
+ type_: cuint32; // SDL_JOYBALLMOTION
+ timestamp: cuint32;
+ which: TSDL_JoystickID; // The joystick instance id
+ ball: cuint8; // The joystick trackball index
+ padding1: cuint8;
+ padding2: cuint8;
+ padding3: cuint8;
+ xrel: cint16; // The relative motion in the X direction
+ yrel: cint16; // The relative motion in the Y direction
+ end;
+
+ {**
+ * Joystick hat position change event structure (event.jhat.*)
+ *}
+ PPSDL_JoyHatEvent = ^PSDL_JoyHatEvent;
+ PSDL_JoyHatEvent = ^TSDL_JoyHatEvent;
+ TSDL_JoyHatEvent = record
+ type_: cuint32; // SDL_JOYHATMOTION
+ timestamp: cuint32;
+ which: TSDL_JoystickID; // The joystick instance id
+ hat: cuint8; // The joystick hat index
+ value: cuint8; {* The hat position value.
+ * SDL_HAT_LEFTUP SDL_HAT_UP SDL_HAT_RIGHTUP
+ * SDL_HAT_LEFT SDL_HAT_CENTERED SDL_HAT_RIGHT
+ * SDL_HAT_LEFTDOWN SDL_HAT_DOWN SDL_HAT_RIGHTDOWN
+ *
+ * Note that zero means the POV is centered.
+ *}
+ padding1: cuint8;
+ padding2: cuint8;
+ end;
+
+ {**
+ * Joystick button event structure (event.jbutton.*)
+ *}
+ PPSDL_JoyButtonEvent = ^PSDL_JoyButtonEvent;
+ PSDL_JoyButtonEvent = ^TSDL_JoyButtonEvent;
+ TSDL_JoyButtonEvent = record
+ type_: cuint32; // SDL_JOYBUTTONDOWN or SDL_JOYBUTTONUP
+ timestamp: cuint32;
+ which: TSDL_JoystickID; // The joystick instance id
+ button: cuint8; // The joystick button index
+ state: cuint8; // SDL_PRESSED or SDL_RELEASED
+ padding1: cuint8;
+ padding2: cuint8;
+ end;
+
+ {**
+ * Joystick device event structure (event.jdevice.*)
+ *}
+ PPSDL_JoyDeviceEvent = ^PSDL_JoyDeviceEvent;
+ PSDL_JoyDeviceEvent = ^TSDL_JoyDeviceEvent;
+ TSDL_JoyDeviceEvent = record
+ type_: cuint32; // SDL_JOYDEVICEADDED or SDL_JOYDEVICEREMOVED
+ timestamp: cuint32;
+ which: cint32; // The joystick device index for the ADDED event, instance id for the REMOVED event
+ end;
+
+ {**
+ * Joysick battery level change event structure (event.jbattery.*)
+ *}
+ PPSDL_JoyBatteryEvent = ^PSDL_JoyBatteryEvent;
+ PSDL_JoyBatteryEvent = ^TSDL_JoyBatteryEvent;
+ TSDL_JoyBatteryEvent = record
+ type_: cuint32; // SDL_JOYBATTERYUPDATED
+ timestamp: cuint32; // In milliseconds, populated using SDL_GetTicks()
+ which: TSDL_JoystickID; // The joystick instance id
+ level: TSDL_JoystickPowerLevel; // The joystick battery level
+ end;
+
+ {**
+ * Game controller axis motion event structure (event.caxis.*)
+ *}
+ PPSDL_ControllerAxisEvent = ^PSDL_ControllerAxisEvent;
+ PSDL_ControllerAxisEvent = ^TSDL_ControllerAxisEvent;
+ TSDL_ControllerAxisEvent = record
+ type_: cuint32; // SDL_CONTROLLERAXISMOTION
+ timestamp: cuint32;
+ which: TSDL_JoystickID; // The joystick instance id
+ axis: cuint8; // The controller axis (SDL_GameControllerAxis)
+ padding1: cuint8;
+ padding2: cuint8;
+ padding3: cuint8;
+ value: cint16; // The axis value (range: -32768 to 32767)
+ padding4: cuint16;
+ end;
+
+ {**
+ * Game controller button event structure (event.cbutton.*)
+ *}
+ PPSDL_ControllerButtonEvent = ^PSDL_ControllerButtonEvent;
+ PSDL_ControllerButtonEvent = ^TSDL_ControllerButtonEvent;
+ TSDL_ControllerButtonEvent = record
+ type_: cuint32; // SDL_CONTROLLERBUTTONDOWN or SDL_CONTROLLERBUTTONUP
+ timestamp: cuint32;
+ which: TSDL_JoystickID; // The joystick instance id
+ button: cuint8; // The controller button (SDL_GameControllerButton)
+ state: cuint8; // SDL_PRESSED or SDL_RELEASED
+ padding1: cuint8;
+ padding2: cuint8;
+ end;
+
+
+ {**
+ * Controller device event structure (event.cdevice.*)
+ *}
+ PPSDL_ControllerDeviceEvent = ^PSDL_ControllerDeviceEvent;
+ PSDL_ControllerDeviceEvent = ^TSDL_ControllerDeviceEvent;
+ TSDL_ControllerDeviceEvent = record
+ type_: cuint32; // SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, or SDL_CONTROLLERDEVICEREMAPPED
+ timestamp: cuint32;
+ which: cint32; // The joystick device index for the ADDED event, instance id for the REMOVED or REMAPPED event
+ end;
+
+ {**
+ * Game controller touchpad event structure (event.ctouchpad.*)
+ *}
+ PPSDL_ControllerTouchpadEvent = ^PSDL_ControllerTouchpadEvent;
+ PSDL_ControllerTouchpadEvent = ^TSDL_ControllerTouchpadEvent;
+ TSDL_ControllerTouchpadEvent = record
+ type_: cuint32; // SDL_CONTROLLERTOUCHPADDOWN or SDL_CONTROLLERTOUCHPADMOTION or SDL_CONTROLLERTOUCHPADUP
+ timestamp: cuint32; // In milliseconds, populated using SDL_GetTicks()
+ which: TSDL_JoystickID; // The joystick instance id
+ touchpad: cint32; // The index of the touchpad
+ finger: cint32; // The index of the finger on the touchpad
+ x: cfloat; // Normalized in the range 0...1 with 0 being on the left
+ y: cfloat; // Normalized in the range 0...1 with 0 being at the top
+ pressure: cfloat; // Normalized in the range 0...1
+ end;
+
+ {**
+ * Game controller sensor event structure (event.csensor.*)
+ *}
+ PPSDL_ControllerSensorEvent = ^PSDL_ControllerSensorEvent;
+ PSDL_ControllerSensorEvent = ^TSDL_ControllerSensorEvent;
+ TSDL_ControllerSensorEvent = record
+ type_: cuint32; // SDL_CONTROLLERSENSORUPDATE
+ timestamp: cuint32; // In milliseconds, populated using SDL_GetTicks()
+ which: TSDL_JoystickID; // The joystick instance id
+ sensor: cint32; // The type of the sensor, one of the values of SDL_SensorType
+ data: array[0..2] of cfloat; // Up to 3 values from the sensor, as defined in SDL_sensor.h
+ end;
+
+ {**
+ * Audio device event structure (event.adevice.*)
+ *}
+ PPSDL_AudioDeviceEvent = ^PSDL_AudioDeviceEvent;
+ PSDL_AudioDeviceEvent = ^TSDL_AudioDeviceEvent;
+ TSDL_AudioDeviceEvent = record
+ type_: cuint32; // ::SDL_AUDIODEVICEADDED, or ::SDL_AUDIODEVICEREMOVED
+ timestamp: cuint32;
+ which: cuint32; // The audio device index for the ADDED event (valid until next SDL_GetNumAudioDevices() call), SDL_AudioDeviceID for the REMOVED event
+ iscapture: cuint8; // zero if an output device, non-zero if a capture device.
+ padding1: cuint8;
+ padding2: cuint8;
+ padding3: cuint8;
+ end;
+
+
+ {**
+ * Touch finger event structure (event.tfinger.*)
+ *}
+ PPSDL_TouchFingerEvent = ^PSDL_TouchFingerEvent;
+ PSDL_TouchFingerEvent = ^TSDL_TouchFingerEvent;
+ TSDL_TouchFingerEvent = record
+ type_: cuint32; // SDL_FINGERMOTION or SDL_FINGERDOWN or SDL_FINGERUP
+ timestamp: cuint32;
+ touchId: TSDL_TouchID; // The touch device id
+ fingerId: TSDL_FingerID;
+ x: cfloat; // Normalized in the range 0...1
+ y: cfloat; // Normalized in the range 0...1
+ dx: cfloat; // Normalized in the range 0...1
+ dy: cfloat; // Normalized in the range 0...1
+ pressure: cfloat; // Normalized in the range 0...1
+ window: cuint32; // The window underneath the finger, if any
+ end;
+
+ {**
+ * Multiple Finger Gesture Event (event.mgesture.*)
+ *}
+ PPSDL_MultiGestureEvent = ^PSDL_MultiGestureEvent;
+ PSDL_MultiGestureEvent = ^TSDL_MultiGestureEvent;
+ TSDL_MultiGestureEvent = record
+ type_: cuint32; // SDL_MULTIGESTURE
+ timestamp: cuint32;
+ touchId: TSDL_TouchID; // The touch device index
+ dTheta: cfloat;
+ dDist: cfloat;
+ x: cfloat;
+ y: cfloat;
+ numFingers: cuint16;
+ padding: cuint16;
+ end;
+
+
+ {* (event.dgesture.*) *}
+ PPSDL_DollarGestureEvent = ^PSDL_DollarGestureEvent;
+ PSDL_DollarGestureEvent = ^TSDL_DollarGestureEvent;
+ TSDL_DollarGestureEvent = record
+ type_: cuint32; // SDL_DOLLARGESTURE
+ timestamp: cuint32;
+ touchId: TSDL_TouchID; // The touch device id
+ gestureId: TSDL_GestureID;
+ numFingers: cuint32;
+ error: cfloat;
+ x: cfloat; // Normalized center of gesture
+ y: cfloat; // Normalized center of gesture
+ end;
+
+
+ {**
+ * An event used to request a file open by the system (event.drop.*)
+ * This event is disabled by default, you can enable it with SDL_EventState()
+ * If you enable this event, you must free the filename in the event.
+ *}
+ PPSDL_DropEvent = ^PSDL_DropEvent;
+ PSDL_DropEvent = ^TSDL_DropEvent;
+ TSDL_DropEvent = record
+ type_: cuint32; // SDL_DROPBEGIN or SDL_DROPFILE or SDL_DROPTEXT or SDL_DROPCOMPLETE
+ timestamp: cuint32;
+ file_: PAnsiChar; // The file name, which should be freed with SDL_free(), is NIL on begin/complete
+ windowID: cuint32; // The window that was dropped on, if any
+ end;
+
+ {**
+ * Sensor event structure (event.sensor.*)
+ *}
+ PPSDL_SensorEvent = ^PSDL_SensorEvent;
+ PSDL_SensorEvent = ^TSDL_SensorEvent;
+ TSDL_SensorEvent = record
+ type_: cuint32; // SDL_SENSORUPDATED
+ timestamp: cuint32; // In milliseconds, populated using SDL_GetTicks()
+ which: cint32; // The instance ID of the sensor
+ data: array[0..5] of cfloat; // Up to 6 values from the sensor - additional values can be queried using SDL_SensorGetData()
+ end;
+
+ {**
+ * The "quit requested" event
+ *}
+ PPSDL_QuitEvent = ^PSDL_QuitEvent;
+ PSDL_QuitEvent = ^TSDL_QuitEvent;
+ TSDL_QuitEvent = record
+ type_: cuint32; // SDL_QUIT
+ timestamp: cuint32;
+ end;
+
+ {**
+ * A user-defined event type (event.user.*)
+ *}
+ PPSDL_UserEvent = ^PSDL_UserEvent;
+ PSDL_UserEvent = ^TSDL_UserEvent;
+ TSDL_UserEvent = record
+ type_: cuint32; // SDL_USEREVENT through SDL_NUMEVENTS-1
+ timestamp: cuint32;
+ windowID: cuint32; // The associated window if any
+ code: cint32; // User defined event code
+ data1: Pointer; // User defined data pointer
+ data2: Pointer; // User defined data pointer
+ end;
+
+ PSDL_SysWMmsg=Pointer;
+
+ {**
+ * A video driver dependent system event (event.syswm.*)
+ * This event is disabled by default, you can enable it with SDL_EventState()
+ *
+ * If you want to use this event, you should include SDL_syswm.h.
+ *}
+ PPSDL_SysWMEvent = ^PSDL_SysWMEvent;
+ PSDL_SysWMEvent = ^TSDL_SysWMEvent;
+ TSDL_SysWMEvent = record
+ type_: cuint32; // SDL_SYSWMEVENT
+ timestamp: cuint32;
+ msg: PSDL_SysWMmsg; // driver dependent data (defined in SDL_syswm.h)
+ end;
+
+ {**
+ * General event structure
+ *}
+ PPSDL_Event = ^PSDL_Event;
+ PSDL_Event = ^TSDL_Event;
+ TSDL_Event = record
+ case cint of
+ 0: (type_: cuint32);
+
+ SDL_COMMONEVENT: (common: TSDL_CommonEvent);
+ SDL_DISPLAYEVENT: (display: TSDL_DisplayEvent);
+ SDL_WINDOWEVENT: (window: TSDL_WindowEvent);
+
+ SDL_KEYUP,
+ SDL_KEYDOWN: (key: TSDL_KeyboardEvent);
+ SDL_TEXTEDITING: (edit: TSDL_TextEditingEvent);
+ SDL_TEXTEDITING_EXT: (exitExt: TSDL_TextEditingExtEvent);
+ SDL_TEXTINPUT: (text: TSDL_TextInputEvent);
+
+ SDL_MOUSEMOTION: (motion: TSDL_MouseMotionEvent);
+ SDL_MOUSEBUTTONUP,
+ SDL_MOUSEBUTTONDOWN: (button: TSDL_MouseButtonEvent);
+ SDL_MOUSEWHEEL: (wheel: TSDL_MouseWheelEvent);
+
+ SDL_JOYAXISMOTION: (jaxis: TSDL_JoyAxisEvent);
+ SDL_JOYBALLMOTION: (jball: TSDL_JoyBallEvent);
+ SDL_JOYHATMOTION: (jhat: TSDL_JoyHatEvent);
+ SDL_JOYBUTTONDOWN,
+ SDL_JOYBUTTONUP: (jbutton: TSDL_JoyButtonEvent);
+ SDL_JOYDEVICEADDED,
+ SDL_JOYDEVICEREMOVED: (jdevice: TSDL_JoyDeviceEvent);
+ SDL_JOYBATTERYUPDATED: (jbattery: TSDL_JoyBatteryEvent);
+
+ SDL_CONTROLLERAXISMOTION: (caxis: TSDL_ControllerAxisEvent);
+ SDL_CONTROLLERBUTTONUP,
+ SDL_CONTROLLERBUTTONDOWN: (cbutton: TSDL_ControllerButtonEvent);
+ SDL_CONTROLLERDEVICEADDED,
+ SDL_CONTROLLERDEVICEREMOVED,
+ SDL_CONTROLLERDEVICEREMAPPED: (cdevice: TSDL_ControllerDeviceEvent);
+ SDL_CONTROLLERTOUCHPADDOWN,
+ SDL_CONTROLLERTOUCHPADMOTION,
+ SDL_CONTROLLERTOUCHPADUP: (ctouchpad: TSDL_ControllerTouchpadEvent);
+ SDL_CONTROLLERSENSORUPDATE: (csensor: TSDL_ControllerSensorEvent);
+
+ SDL_AUDIODEVICEADDED,
+ SDL_AUDIODEVICEREMOVED: (adevice: TSDL_AudioDeviceEvent);
+
+ SDL_SENSORUPDATED: (sensor: TSDL_SensorEvent);
+
+ SDL_QUITEV: (quit: TSDL_QuitEvent);
+
+ SDL_USEREVENT: (user: TSDL_UserEvent);
+ SDL_SYSWMEVENT: (syswm: TSDL_SysWMEvent);
+
+ SDL_FINGERDOWN,
+ SDL_FINGERUP,
+ SDL_FINGERMOTION: (tfinger: TSDL_TouchFingerEvent);
+ SDL_MULTIGESTURE: (mgesture: TSDL_MultiGestureEvent);
+ SDL_DOLLARGESTURE,SDL_DOLLARRECORD: (dgesture: TSDL_DollarGestureEvent);
+
+ SDL_DROPFILE: (drop: TSDL_DropEvent);
+ end;
+
+///
+
+function SDL_InitSubSystem(flags: TSDL_Init): cint; cdecl;
+procedure SDL_QuitSubSystem(flags: TSDL_Init); cdecl;
+
+var
+ SDL_PollEvent:function(event: PSDL_Event): cint32 cdecl;
+
+ SDL_LockJoysticks :procedure(); cdecl;
+ SDL_UnlockJoysticks:procedure(); cdecl;
+ SDL_NumJoysticks :function(): cint; cdecl;
+
+ SDL_JoystickGetDeviceGUID:function(device_index: cint): TSDL_JoystickGUID; cdecl;
+ SDL_JoystickGetGUID :function(joystick: PSDL_Joystick): TSDL_JoystickGUID; cdecl;
+
+////
+ SDL_IsGameController :function(joystick_index: cint): Boolean cdecl;
+ SDL_GameControllerOpen :function(joystick_index: cint): PSDL_GameController cdecl;
+ SDL_GameControllerClose:procedure(gamecontroller: PSDL_GameController) cdecl;
+
+ SDL_GameControllerGetJoystick:function(gamecontroller: PSDL_GameController): PSDL_Joystick cdecl;
+ SDL_GameControllerGetAttached:function(gamecontroller: PSDL_GameController): Boolean cdecl;
+//
+ SDL_GameControllerNumMappings:function():cint; cdecl;
+ SDL_GameControllerName:function(gamecontroller: PSDL_GameController): PAnsiChar cdecl;
+ SDL_GameControllerGetVendor:function(gamecontroller: PSDL_GameController): cuint16; cdecl;
+ SDL_GameControllerGetProduct:function(gamecontroller: PSDL_GameController): cuint16; cdecl;
+ SDL_GameControllerGetProductVersion:function(gamecontroller: PSDL_GameController): cuint16; cdecl;
+ SDL_GameControllerGetFirmwareVersion:function(gamecontroller: PSDL_GameController): cuint16; cdecl;
+ SDL_GameControllerGetSerial:function(gamecontroller: PSDL_GameController): PAnsiChar; cdecl;
+ SDL_GameControllerPath:function(gamecontroller: PSDL_GameController): PAnsiChar; cdecl;
+ SDL_GameControllerHasRumble:function(gamecontroller: PSDL_GameController): Boolean; cdecl;
+ SDL_GameControllerGetButton:function(gamecontroller: PSDL_GameController; button: TSDL_GameControllerButton): cuint8 cdecl;
+ SDL_GameControllerGetNumTouchpads:function(gamecontroller: PSDL_GameController): cint; cdecl;
+ SDL_GameControllerGetNumTouchpadFingers:function(gamecontroller: PSDL_GameController; touchpad: cint): cint; cdecl;
+
+ SDL_GameControllerGetTouchpadFinger:function(
+ gamecontroller: PSDL_GameController;
+ touchpad, finger: cint;
+ state: pcuint8;
+ x, y, pressure: pcfloat
+ ): cint; cdecl;
+
+ SDL_GameControllerGetAxis:function(gamecontroller: PSDL_GameController; axis: TSDL_GameControllerAxis): cint16 cdecl;
+
+ SDL_GameControllerRumble:function(
+ gamecontroller: PSDL_GameController;
+ low_frequency_rumble, high_frequency_rumble: cuint16;
+ duration_ms: cuint32
+ ): cint; cdecl;
+
+ SDL_GameControllerHasRumbleTriggers:function(gamecontroller: PSDL_GameController): Boolean; cdecl;
+
+ SDL_GameControllerRumbleTriggers:function(
+ gamecontroller: PSDL_GameController;
+ left_rumble, right_rumble: cuint16;
+ duration_ms: cuint32
+ ): cint; cdecl;
+
+ SDL_GameControllerHasLED:function(gamecontroller: PSDL_GameController): Boolean; cdecl;
+ SDL_GameControllerSetLED:function(gamecontroller: PSDL_GameController; red, green, blue: cuint8): cint; cdecl;
+
+implementation
+
+var
+ init_flags:TSDL_Init=0;
+ lib_handle:TLibHandle=NilHandle;
+
+ ///
+ _SDL_InitSubSystem:function (flags: TSDL_Init): cint; cdecl;
+ _SDL_QuitSubSystem:procedure(flags: TSDL_Init); cdecl;
+ ///
+
+function SDL_InitSubSystem(flags: TSDL_Init): cint; cdecl;
+begin
+ if (lib_handle=NilHandle) then
+ begin
+ lib_handle:=SafeLoadLibrary(SDL_LibName);
+ if (lib_handle=NilHandle) then Exit(-1);
+ end;
+
+ Pointer(_SDL_InitSubSystem):=GetProcedureAddress(lib_handle,'SDL_InitSubSystem');
+ Pointer(_SDL_QuitSubSystem):=GetProcedureAddress(lib_handle,'SDL_QuitSubSystem');
+ Pointer(SDL_PollEvent) :=GetProcedureAddress(lib_handle,'SDL_PollEvent');
+
+ if (_SDL_InitSubSystem=nil) then
+ begin
+ UnloadLibrary(lib_handle);
+ lib_handle:=NilHandle;
+ init_flags:=0;
+ Exit(-1);
+ end;
+
+ Result:=_SDL_InitSubSystem(flags);
+ if (Result<>0) then Exit;
+
+ init_flags:=init_flags or flags;
+
+ if ((flags and SDL_INIT_JOYSTICK)<>0) then
+ begin
+ Pointer(SDL_LockJoysticks ):=GetProcedureAddress(lib_handle,'SDL_LockJoysticks');
+ Pointer(SDL_UnlockJoysticks ):=GetProcedureAddress(lib_handle,'SDL_UnlockJoysticks');
+ Pointer(SDL_NumJoysticks ):=GetProcedureAddress(lib_handle,'SDL_NumJoysticks');
+ Pointer(SDL_JoystickGetDeviceGUID):=GetProcedureAddress(lib_handle,'SDL_JoystickGetDeviceGUID');
+ Pointer(SDL_JoystickGetGUID ):=GetProcedureAddress(lib_handle,'SDL_JoystickGetGUID');
+ end;
+
+ if ((flags and SDL_INIT_GAMECONTROLLER)<>0) then
+ begin
+ Pointer(SDL_IsGameController ):=GetProcedureAddress(lib_handle,'SDL_IsGameController');
+ Pointer(SDL_GameControllerOpen ):=GetProcedureAddress(lib_handle,'SDL_GameControllerOpen');
+ Pointer(SDL_GameControllerClose ):=GetProcedureAddress(lib_handle,'SDL_GameControllerClose');
+ Pointer(SDL_GameControllerGetJoystick ):=GetProcedureAddress(lib_handle,'SDL_GameControllerGetJoystick');
+ Pointer(SDL_GameControllerGetAttached ):=GetProcedureAddress(lib_handle,'SDL_GameControllerGetAttached');
+ Pointer(SDL_GameControllerNumMappings ):=GetProcedureAddress(lib_handle,'SDL_GameControllerNumMappings');
+ Pointer(SDL_GameControllerName ):=GetProcedureAddress(lib_handle,'SDL_GameControllerName');
+ Pointer(SDL_GameControllerGetVendor ):=GetProcedureAddress(lib_handle,'SDL_GameControllerGetVendor');
+ Pointer(SDL_GameControllerGetProduct ):=GetProcedureAddress(lib_handle,'SDL_GameControllerGetProduct');
+ Pointer(SDL_GameControllerGetProductVersion ):=GetProcedureAddress(lib_handle,'SDL_GameControllerGetProductVersion');
+ Pointer(SDL_GameControllerGetFirmwareVersion ):=GetProcedureAddress(lib_handle,'SDL_GameControllerGetFirmwareVersion');
+ Pointer(SDL_GameControllerGetSerial ):=GetProcedureAddress(lib_handle,'SDL_GameControllerGetSerial');
+ Pointer(SDL_GameControllerPath ):=GetProcedureAddress(lib_handle,'SDL_GameControllerPath');
+ Pointer(SDL_GameControllerHasRumble ):=GetProcedureAddress(lib_handle,'SDL_GameControllerHasRumble');
+ Pointer(SDL_GameControllerGetButton ):=GetProcedureAddress(lib_handle,'SDL_GameControllerGetButton');
+ Pointer(SDL_GameControllerGetNumTouchpads ):=GetProcedureAddress(lib_handle,'SDL_GameControllerGetNumTouchpads');
+ Pointer(SDL_GameControllerGetNumTouchpadFingers):=GetProcedureAddress(lib_handle,'SDL_GameControllerGetNumTouchpadFingers');
+ Pointer(SDL_GameControllerGetTouchpadFinger ):=GetProcedureAddress(lib_handle,'SDL_GameControllerGetTouchpadFinger');
+ Pointer(SDL_GameControllerGetAxis ):=GetProcedureAddress(lib_handle,'SDL_GameControllerGetAxis');
+ Pointer(SDL_GameControllerRumble ):=GetProcedureAddress(lib_handle,'SDL_GameControllerRumble');
+ Pointer(SDL_GameControllerHasRumbleTriggers ):=GetProcedureAddress(lib_handle,'SDL_GameControllerHasRumbleTriggers');
+ Pointer(SDL_GameControllerRumbleTriggers ):=GetProcedureAddress(lib_handle,'SDL_GameControllerRumbleTriggers');
+ Pointer(SDL_GameControllerHasLED ):=GetProcedureAddress(lib_handle,'SDL_GameControllerHasLED');
+ Pointer(SDL_GameControllerSetLED ):=GetProcedureAddress(lib_handle,'SDL_GameControllerSetLED');
+ end;
+end;
+
+procedure SDL_QuitSubSystem(flags: TSDL_Init); cdecl;
+begin
+ if (lib_handle=NilHandle) then Exit;
+
+ init_flags:=init_flags and (not flags);
+
+ if (_SDL_QuitSubSystem<>nil) then
+ begin
+ _SDL_QuitSubSystem(flags);
+ end;
+
+ if (init_flags=0) then
+ begin
+ UnloadLibrary(lib_handle);
+ lib_handle:=NilHandle;
+
+ Pointer(_SDL_InitSubSystem):=nil;
+ Pointer(_SDL_QuitSubSystem):=nil;
+ Pointer(SDL_PollEvent) :=nil;
+ end;
+
+ if ((flags and SDL_INIT_JOYSTICK)<>0) then
+ begin
+ Pointer(SDL_LockJoysticks ):=nil;
+ Pointer(SDL_UnlockJoysticks ):=nil;
+ Pointer(SDL_NumJoysticks ):=nil;
+ Pointer(SDL_JoystickGetDeviceGUID):=nil;
+ Pointer(SDL_JoystickGetGUID ):=nil;
+ end;
+
+ if ((flags and SDL_INIT_GAMECONTROLLER)<>0) then
+ begin
+ Pointer(SDL_IsGameController ):=nil;
+ Pointer(SDL_GameControllerOpen ):=nil;
+ Pointer(SDL_GameControllerClose ):=nil;
+ Pointer(SDL_GameControllerGetJoystick ):=nil;
+ Pointer(SDL_GameControllerGetAttached ):=nil;
+ Pointer(SDL_GameControllerNumMappings ):=nil;
+ Pointer(SDL_GameControllerName ):=nil;
+ Pointer(SDL_GameControllerGetVendor ):=nil;
+ Pointer(SDL_GameControllerGetProduct ):=nil;
+ Pointer(SDL_GameControllerGetProductVersion ):=nil;
+ Pointer(SDL_GameControllerGetFirmwareVersion ):=nil;
+ Pointer(SDL_GameControllerGetSerial ):=nil;
+ Pointer(SDL_GameControllerPath ):=nil;
+ Pointer(SDL_GameControllerHasRumble ):=nil;
+ Pointer(SDL_GameControllerGetButton ):=nil;
+ Pointer(SDL_GameControllerGetNumTouchpads ):=nil;
+ Pointer(SDL_GameControllerGetNumTouchpadFingers):=nil;
+ Pointer(SDL_GameControllerGetTouchpadFinger ):=nil;
+ Pointer(SDL_GameControllerGetAxis ):=nil;
+ Pointer(SDL_GameControllerRumble ):=nil;
+ Pointer(SDL_GameControllerHasRumbleTriggers ):=nil;
+ Pointer(SDL_GameControllerRumbleTriggers ):=nil;
+ Pointer(SDL_GameControllerHasLED ):=nil;
+ Pointer(SDL_GameControllerSetLED ):=nil;
+ end;
+end;
+
+
+
+end.
+
diff --git a/src/inputs/sdl2_pad_interface.pas b/src/inputs/sdl2_pad_interface.pas
new file mode 100644
index 00000000..183a2190
--- /dev/null
+++ b/src/inputs/sdl2_pad_interface.pas
@@ -0,0 +1,395 @@
+unit sdl2_pad_interface;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+ sysutils,
+ sdl2,
+ sce_pad_types,
+ sce_pad_interface,
+ kbm_pad_interface;
+
+type
+ TSdl2PadHandle=class(TScePadHandle)
+ var
+ connectedCount:Integer;
+ game_controller:PSDL_GameController;
+ LED:ScePadLightBarParam;
+ function SetLightBar(data:pScePadLightBarParam):Integer; override;
+ function ResetLightBar():Integer; override;
+ function ReadState(data:PScePadData):Integer; override;
+ end;
+
+ TSdl2PadInterface=class(TScePadInterface)
+ class var
+ sdl2_init:Boolean;
+ class function Load:Boolean; override;
+ class procedure Unload; override;
+ class function Init:Integer; override;
+ class function Done:Integer; override;
+ class function Open(index:Integer;var handle:TScePadHandle):Integer; override;
+ class function FindOpened(device_index:Integer;prev:PSDL_GameController):Boolean;
+ class function FindDevice(prev:PSDL_GameController):PSDL_GameController;
+ end;
+
+implementation
+
+class function TSdl2PadInterface.Load:Boolean;
+var
+ i:Integer;
+begin
+ i:=SDL_InitSubSystem(SDL_INIT_JOYSTICK or SDL_INIT_GAMECONTROLLER);
+ sdl2_init:=(i=0);
+
+ if sdl2_init then
+ begin
+ Writeln('SDL2 Game-Controller subsystem initialized!');
+ end else
+ begin
+ Writeln('SDL2 Game-Controller not initialized!');
+ end;
+
+ Result:=sdl2_init;
+end;
+
+class procedure TSdl2PadInterface.Unload;
+begin
+ if not sdl2_init then Exit;
+ SDL_QuitSubSystem(SDL_INIT_JOYSTICK or SDL_INIT_GAMECONTROLLER);
+ sdl2_init:=False;
+ Writeln('SDL2 Game-Controller subsystem quit!');
+end;
+
+class function TSdl2PadInterface.Init:Integer;
+begin
+ if (sdl2_init) then
+ begin
+ Result:=0;
+ end else
+ begin
+ Result:=SCE_PAD_ERROR_NOT_INITIALIZED;
+ end;
+end;
+
+class function TSdl2PadInterface.Done:Integer;
+begin
+ Result:=0;
+end;
+
+function Compare(g1,g2:TSDL_JoystickGUID):Boolean; inline;
+begin
+ Result:=CompareByte(g1,g2,SizeOf(TSDL_JoystickGUID))=0;
+end;
+
+function Compare(g1,g2:PSDL_GameController):Boolean;
+begin
+ Result:=Compare(SDL_JoystickGetGUID(SDL_GameControllerGetJoystick(g1)),
+ SDL_JoystickGetGUID(SDL_GameControllerGetJoystick(g2))
+ );
+end;
+
+function Compare(device_index:Integer;g2:PSDL_GameController):Boolean;
+begin
+ Result:=Compare(SDL_JoystickGetDeviceGUID(device_index),
+ SDL_JoystickGetGUID(SDL_GameControllerGetJoystick(g2))
+ );
+end;
+
+class function TSdl2PadInterface.FindOpened(device_index:Integer;prev:PSDL_GameController):Boolean;
+var
+ i:Integer;
+ h:TSdl2PadHandle;
+begin
+ Result:=False;
+ For i:=0 to 15 do
+ if (pad_opened[i]<>nil) then
+ if (pad_opened[i].InheritsFrom(TSdl2PadHandle)) then
+ begin
+ h:=TSdl2PadHandle(pad_opened[i]);
+ if (h.game_controller<>nil) then
+ if (h.game_controller<>prev) then
+ begin
+ Result:=Compare(device_index,h.game_controller);
+ if Result then Break;
+ end;
+ end;
+end;
+
+class function TSdl2PadInterface.FindDevice(prev:PSDL_GameController):PSDL_GameController;
+var
+ i,c:Integer;
+ first,compared:Integer;
+begin
+ Result:=nil;
+ first:=-1;
+ compared:=-1;
+ SDL_LockJoysticks;
+ c:=SDL_NumJoysticks();
+ if (c<>0) then
+ For i:=0 to c-1 do
+ if SDL_IsGameController(i) then
+ if not FindOpened(i,prev) then
+ begin
+ if (first=-1) then first:=i;
+ if (prev=nil) then
+ begin
+ compared:=i;
+ Break;
+ end else
+ if Compare(i,prev) then
+ begin
+ compared:=i;
+ Break;
+ end;
+ end;
+ //
+ if (compared=-1) then compared:=first;
+ if (compared<>-1) then
+ begin
+ Result:=SDL_GameControllerOpen(compared);
+ end;
+ SDL_UnlockJoysticks;
+end;
+
+class function TSdl2PadInterface.Open(index:Integer;var handle:TScePadHandle):Integer;
+var
+ game_controller:PSDL_GameController;
+begin
+ Result:=0;
+ if not sdl2_init then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
+ if (index<0) or (index>15) then Exit(SCE_PAD_ERROR_INVALID_ARG);
+ if (pad_opened[index]<>nil) then Exit(SCE_PAD_ERROR_ALREADY_OPENED);
+
+ game_controller:=FindDevice(nil);
+
+ handle:=TSdl2PadHandle.Create;
+ TSdl2PadHandle(handle).index:=index;
+ TSdl2PadHandle(handle).game_controller:=game_controller;
+
+ pad_opened[index]:=handle;
+
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('SDL2: Game Controller loaded!');
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('Controller Name: ', SDL_GameControllerName(game_controller));
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('USB Vendor ID: ', SDL_GameControllerGetVendor(game_controller));
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('USB Product ID: ', SDL_GameControllerGetProduct(game_controller));
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('Product Version: ', SDL_GameControllerGetProductVersion(game_controller));
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('Firmware Version: ', SDL_GameControllerGetFirmwareVersion(game_controller));
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('Serial Number: ', SDL_GameControllerGetSerial(game_controller));
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('Controller Path: ', SDL_GameControllerPath(game_controller));
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('----------------------------------------------------------------------------------------');
+
+
+ Writeln('Controller GUID: ', GUIDToString(TGUID(SDL_JoystickGetGUID(SDL_GameControllerGetJoystick(game_controller)))));
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('----------------------------------------------------------------------------------------');
+
+
+ Writeln('Modifiable LED: ', SDL_GameControllerHasLED(game_controller));
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('Modifiable Rumble: ', SDL_GameControllerHasRumble(game_controller));
+ Writeln('----------------------------------------------------------------------------------------');
+ Writeln('----------------------------------------------------------------------------------------');
+end;
+
+function AxisToAnalog(i:Integer):Byte;
+begin
+ if (i>0) then
+ begin
+ i:=(i*127) div 32767;
+ end else
+ begin
+ i:=(i*128) div 32768;
+ end;
+ Result:=Byte(i+128);
+end;
+
+function AxisToTrigger(i:Integer):Byte;
+begin
+ Result:=Byte((abs(i)*255) div 32767);
+end;
+
+function TSdl2PadHandle.SetLightBar(data:pScePadLightBarParam):Integer;
+begin
+ LED:=data^;
+ if (game_controller<>nil) then
+ begin
+ SDL_GameControllerSetLED(game_controller, LED.r, LED.g, LED.b);
+ end;
+end;
+
+function TSdl2PadHandle.ResetLightBar():Integer;
+begin
+ LED:=Default(ScePadLightBarParam);
+ if (game_controller<>nil) then
+ begin
+ SDL_GameControllerSetLED(game_controller, LED.r, LED.g, LED.b);
+ end;
+end;
+
+function TSdl2PadHandle.ReadState(data:PScePadData):Integer;
+var
+ i,f,t,n:Integer;
+ x,y,pressure:Single;
+ state:Byte;
+ new:PSDL_GameController;
+ event:TSDL_Event;
+begin
+ Result:=0;
+
+ //loop events
+ while (SDL_PollEvent(@event)<>0) do;
+
+ if not SDL_GameControllerGetAttached(game_controller) then
+ begin
+ new:=TSdl2PadInterface.FindDevice(game_controller);
+ if (new=nil) then
+ begin
+ data^.connected:=False;
+ data^.connectedCount:=Byte(connectedCount);
+ Exit(0);
+ end else
+ begin
+ Writeln('Reconnect:',index);
+ SDL_GameControllerClose(game_controller);
+ game_controller:=new;
+ Inc(connectedCount);
+ //
+ SDL_GameControllerSetLED(game_controller, LED.r, LED.g, LED.b);
+ end;
+ end;
+
+ data^.connected:=True;
+ data^.connectedCount:=Byte(connectedCount);
+
+ t:=SDL_GameControllerGetNumTouchpads(game_controller);
+
+ if (t=0) then
+ begin
+ //no touchpad? use mouse
+ TMouseAsTouchpad.ReadState(data);
+ end else
+ begin
+ //use ony first touchpad
+ f:=SDL_GameControllerGetNumTouchpadFingers(game_controller,0);
+
+ n:=0;
+ data^.touchData.touchNum:=0;
+
+ if (f<>0) then
+ For i:=0 to f-1 do
+ begin
+
+ if SDL_GameControllerGetTouchpadFinger(
+ game_controller,
+ 0,i,
+ @state,
+ @x,@y,@pressure)=0 then
+ begin
+
+ if (x>1919) then x:=1919;
+ if (y>941) then y:=941;
+
+ data^.touchData.touch[n].id:=n;
+ data^.touchData.touch[n].x :=Word(Trunc(x));
+ data^.touchData.touch[n].y :=Word(Trunc(y));
+
+ Inc(n);
+ data^.touchData.touchNum:=n;
+
+ if (n=SCE_PAD_MAX_TOUCH_NUM) then Break;
+ end;
+ end;
+ end;
+
+
+ //Options and Touchpad
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_START) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_OPTIONS;
+
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_TOUCHPAD) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_TOUCH_PAD;
+
+ //Hats(D-PAD)
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_DPAD_UP) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_UP;
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_DOWN;
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_LEFT;
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_RIGHT;
+
+ //Cross, Circle, Square and Triangle
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_A) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CROSS;
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_B) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CIRCLE;
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_X) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_SQUARE;
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_Y) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_TRIANGLE;
+
+ //L1, R1 and L3, R3
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L1;
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R1;
+
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_LEFTSTICK) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L3;
+ if SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_RIGHTSTICK) = 1 then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R3;
+
+ //Left and Right Axes
+ data^.leftStick.x:=AxisToAnalog(SDL_GameControllerGetAxis(game_controller, SDL_CONTROLLER_AXIS_LEFTX));
+ data^.leftStick.y:=AxisToAnalog(SDL_GameControllerGetAxis(game_controller, SDL_CONTROLLER_AXIS_LEFTY));
+
+ data^.rightStick.x:=AxisToAnalog(SDL_GameControllerGetAxis(game_controller, SDL_CONTROLLER_AXIS_RIGHTX));
+ data^.rightStick.y:=AxisToAnalog(SDL_GameControllerGetAxis(game_controller, SDL_CONTROLLER_AXIS_RIGHTY));
+
+ //Left and Right Triggers (L2 and R2)
+ data^.analogButtons.l2:=AxisToTrigger(SDL_GameControllerGetAxis(game_controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT ));
+ data^.analogButtons.r2:=AxisToTrigger(SDL_GameControllerGetAxis(game_controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT));
+
+ //Approx L2
+ if (data^.analogButtons.l2>1) then
+ begin
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L2;
+ end;
+
+ //Approx R2
+ if (data^.analogButtons.r2>1) then
+ begin
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R2;
+ end;
+end;
+
+initialization
+ //sdl2 needs to be initialized on the main thread, otherwise it just doesn't work. :(
+ TSdl2PadInterface.Load;
+
+finalization
+ TSdl2PadInterface.Unload;
+
+end.
+
diff --git a/src/inputs/umappableinputs.pas b/src/inputs/umappableinputs.pas
index 2b244701..d4513239 100644
--- a/src/inputs/umappableinputs.pas
+++ b/src/inputs/umappableinputs.pas
@@ -202,9 +202,9 @@ begin
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.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
@@ -225,9 +225,9 @@ 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.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
@@ -242,14 +242,14 @@ 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;
+ 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;
+ 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;
@@ -257,14 +257,14 @@ begin
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;
+ 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;
- xiGuide: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_GUIDE) <> 0;
- xiStart: Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_START) <> 0;
+ xiGuide : Result := (state.Gamepad.wButtons and XINPUT_GAMEPAD_GUIDE) <> 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;
@@ -280,20 +280,20 @@ 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(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(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(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';
@@ -302,8 +302,8 @@ initialization
MappableInputs.XInputButtonsNames[Ord(xiY)] := 'Y';
MappableInputs.XInputButtonsNames[Ord(xiSelect)] := 'SELECT';
- MappableInputs.XInputButtonsNames[Ord(xiGuide)] := 'GUIDE';
- MappableInputs.XInputButtonsNames[Ord(xiStart)] := 'START';
+ MappableInputs.XInputButtonsNames[Ord(xiGuide )] := 'GUIDE';
+ MappableInputs.XInputButtonsNames[Ord(xiStart )] := 'START';
MappableInputs.XInputButtonsNames[Ord(xiL1)] := 'L1';
MappableInputs.XInputButtonsNames[Ord(xiL2)] := 'L2';
@@ -315,35 +315,37 @@ initialization
// Default mapping
MappableInputs.XInputEnabled := True;
- MappableInputs.XInputDeadzoneLeft := XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;
- MappableInputs.XInputDeadzoneRight := XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;
+ 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(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(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(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.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/inputs/xinput.pas b/src/inputs/xinput.pas
index 799742cf..27d8de68 100644
--- a/src/inputs/xinput.pas
+++ b/src/inputs/xinput.pas
@@ -2,11 +2,18 @@ unit XInput;
interface
+uses
+ dynlibs;
+
type
BOOL = longbool;
const
- XINPUT_DLL = 'xinput1_3.dll';
+ XINPUT_DLL:array[0..2] of PChar=(
+ 'XInput1_4.dll',
+ 'XInput1_3.dll',
+ 'XInput9_1_0.dll'
+ );
// Device types available in XINPUT_CAPABILITIES
XINPUT_DEVTYPE_GAMEPAD = $01;
@@ -162,44 +169,106 @@ type
HidCode: Byte;
end;
-function XInputGetState(
+function XInput_Init: Integer; stdcall;
+procedure XInput_Quit; stdcall;
+
+var
+ XInputGetState:function(
dwUserIndex: DWORD; // [in] Index of the gamer associated with the device
out pState: TXInputState // [out] Receives the current state
- ): DWORD; stdcall; external XINPUT_DLL;
+ ): DWORD; stdcall;
-function XInputSetState(
+ XInputSetState:function(
dwUserIndex: DWORD; // [in] Index of the gamer associated with the device
const pVibration: TXInputVibration // [in, out] The vibration information to send to the controller
- ): DWORD; stdcall; external XINPUT_DLL;
+ ): DWORD; stdcall;
-function XInputGetCapabilities(
+ XInputGetCapabilities:function(
dwUserIndex: DWORD; // [in] Index of the gamer associated with the device
dwFlags: DWORD; // [in] Input flags that identify the device type
out pCapabilities: TXInputCapabilities // [out] Receives the capabilities
- ): DWORD; stdcall; external XINPUT_DLL;
+ ): DWORD; stdcall;
-procedure XInputEnable(
+ XInputEnable:procedure(
enable: BOOL // [in] Indicates whether xinput is enabled or disabled.
-); stdcall; external XINPUT_DLL;
+ ); stdcall;
-function XInputGetDSoundAudioDeviceGuids(
+ XInputGetDSoundAudioDeviceGuids:function(
dwUserIndex: DWORD; // [in] Index of the gamer associated with the device
out pDSoundRenderGuid: TGUID; // [out] DSound device ID for render
out pDSoundCaptureGuid: TGUID // [out] DSound device ID for capture
- ): DWORD; stdcall; external XINPUT_DLL;
+ ): DWORD; stdcall;
-function XInputGetBatteryInformation(
+ XInputGetBatteryInformation:function(
dwUserIndex: DWORD; // [in] Index of the gamer associated with the device
devType: Byte; // [in] Which device on this user index
out pBatteryInformation: TXInputBatteryInformation // [out] Contains the level and types of batteries
- ): DWORD; stdcall; external XINPUT_DLL;
+ ): DWORD; stdcall;
-function XInputGetKeystroke(
+ XInputGetKeystroke:function(
dwUserIndex: DWORD; // [in] Index of the gamer associated with the device
dwReserved: DWORD; // [in] Reserved for future use
var pKeystroke: TXInputKeystroke // [out] Pointer to an XINPUT_KEYSTROKE structure that receives an input event.
- ): DWORD; stdcall; external XINPUT_DLL;
+ ): DWORD; stdcall;
implementation
+var
+ lib_handle:TLibHandle=NilHandle;
+
+function XInput_Init:Integer; stdcall;
+var
+ i:Integer;
+begin
+ if (lib_handle<>NilHandle) then Exit(0);
+
+ For i:=0 to High(XINPUT_DLL) do
+ begin
+ lib_handle:=SafeLoadLibrary(XINPUT_DLL[i]);
+ if (lib_handle<>NilHandle) then Break;
+ end;
+
+ if (lib_handle=NilHandle) then Exit(-1);
+
+ Pointer(XInputGetState):=GetProcedureAddress(lib_handle,100);
+
+ if (XInputGetState=nil) then
+ begin
+ Pointer(XInputGetState):=GetProcedureAddress(lib_handle,'XInputGetState');
+ end;
+
+ if (XInputGetState=nil) then
+ begin
+ UnloadLibrary(lib_handle);
+ lib_handle:=NilHandle;
+ Exit(-1);
+ end;
+
+ Pointer(XInputSetState ):=GetProcedureAddress(lib_handle,'XInputSetState');
+ Pointer(XInputGetCapabilities ):=GetProcedureAddress(lib_handle,'XInputGetCapabilities');
+ Pointer(XInputEnable ):=GetProcedureAddress(lib_handle,'XInputEnable');
+ Pointer(XInputGetDSoundAudioDeviceGuids):=GetProcedureAddress(lib_handle,'XInputGetDSoundAudioDeviceGuids');
+ Pointer(XInputGetBatteryInformation ):=GetProcedureAddress(lib_handle,'XInputGetBatteryInformation');
+ Pointer(XInputGetKeystroke ):=GetProcedureAddress(lib_handle,'XInputGetKeystroke');
+end;
+
+procedure XInput_Quit; stdcall;
+begin
+ if (lib_handle=NilHandle) then Exit;
+
+ UnloadLibrary(lib_handle);
+ lib_handle:=NilHandle;
+
+ Pointer(XInputGetState ):=nil;
+ Pointer(XInputSetState ):=nil;
+ Pointer(XInputGetCapabilities ):=nil;
+ Pointer(XInputEnable ):=nil;
+ Pointer(XInputGetDSoundAudioDeviceGuids):=nil;
+ Pointer(XInputGetBatteryInformation ):=nil;
+ Pointer(XInputGetKeystroke ):=nil;
+end;
+
+
end.
+
+
diff --git a/src/inputs/xinput_pad_interface.pas b/src/inputs/xinput_pad_interface.pas
new file mode 100644
index 00000000..293ba023
--- /dev/null
+++ b/src/inputs/xinput_pad_interface.pas
@@ -0,0 +1,185 @@
+unit xinput_pad_interface;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+ sysutils,
+ XInput,
+ sce_pad_types,
+ sce_pad_interface,
+ kbm_pad_interface;
+
+type
+ TXInputPadHandle=class(TScePadHandle)
+ var
+ connected :Boolean;
+ connectedCount:Byte;
+ function ReadState(data:PScePadData):Integer; override;
+ end;
+
+ TXInputPadInterface=class(TScePadInterface)
+ class var
+ xinput_init:Boolean;
+ class function Load:Boolean; override;
+ class procedure Unload; override;
+ class function Init:Integer; override;
+ class function Done:Integer; override;
+ class function Open(index:Integer;var handle:TScePadHandle):Integer; override;
+ end;
+
+implementation
+
+uses
+ formController,
+ uMappableInputs;
+
+class function TXInputPadInterface.Load:Boolean;
+var
+ i:Integer;
+begin
+ i:=XInput.XInput_Init();
+ xinput_init:=(i=0);
+
+ if xinput_init then
+ begin
+ Writeln('XInput initialized!');
+ end else
+ begin
+ Writeln('XInput not initialized!');
+ end;
+
+ Result:=xinput_init;
+end;
+
+class procedure TXInputPadInterface.Unload;
+begin
+ if not xinput_init then Exit;
+ XInput_Quit;
+ xinput_init:=False;
+ Writeln('XInput quit!');
+end;
+
+class function TXInputPadInterface.Init:Integer;
+begin
+ if (xinput_init) then
+ begin
+ Result:=0;
+ end else
+ begin
+ Result:=SCE_PAD_ERROR_NOT_INITIALIZED;
+ end;
+end;
+
+class function TXInputPadInterface.Done:Integer;
+begin
+ Result:=0;
+end;
+
+class function TXInputPadInterface.Open(index:Integer;var handle:TScePadHandle):Integer;
+begin
+ Result:=0;
+ if (index<0) or (index>15) then Exit(SCE_PAD_ERROR_INVALID_ARG);
+ if (pad_opened[index]<>nil) then Exit(SCE_PAD_ERROR_ALREADY_OPENED);
+
+ handle:=TXInputPadHandle.Create;
+ TXInputPadHandle(handle).index:=index;
+
+ pad_opened[index]:=handle;
+end;
+
+function TXInputPadHandle.ReadState(data:PScePadData):Integer;
+var
+ cs:TXInputState;
+ controllerIndex:DWORD;
+ stateResult:DWORD;
+begin
+ Result:=0;
+
+ if (index>=XUSER_MAX_COUNT) then
+ begin
+ data^.connected :=False;
+ data^.connectedCount:=0;
+ Exit;
+ end;
+
+ cs:=Default(TXInputState);
+ stateResult:=XInputGetState(index, cs);
+
+ if (stateResult=ERROR_DEVICE_NOT_CONNECTED) then
+ begin
+ //disconnect
+ connected:=False;
+ //
+ data^.connected :=connected;
+ data^.connectedCount:=connectedCount;
+ Exit;
+ end else
+ begin
+ //connect
+ if not connected then
+ begin
+ connected:=True;
+ Inc(connectedCount);
+ end;
+ end;
+
+ data^.connected :=connected;
+ data^.connectedCount:=connectedCount;
+
+ TMouseAsTouchpad.ReadState(data);
+
+ //if not MappableInputs.XInputEnabled then break; ?????
+
+ if MappableInputs.PS4IsPressed(miCross, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CROSS;
+ if MappableInputs.PS4IsPressed(miCircle, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CIRCLE;
+ if MappableInputs.PS4IsPressed(miSquare, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_SQUARE;
+ if MappableInputs.PS4IsPressed(miTriangle, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_TRIANGLE;
+
+ if MappableInputs.PS4IsPressed(miOptions, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_OPTIONS;
+ if MappableInputs.PS4IsPressed(miTouchPad, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_TOUCH_PAD;
+
+ if MappableInputs.PS4IsPressed(miL1, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L1;
+ if MappableInputs.PS4IsPressed(miR1, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R1;
+ if MappableInputs.PS4IsPressed(miL3, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L3;
+ if MappableInputs.PS4IsPressed(miR3, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R3;
+
+ if MappableInputs.PS4IsPressed(miDPadUp, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_UP;
+ if MappableInputs.PS4IsPressed(miDPadDown, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_DOWN;
+ if MappableInputs.PS4IsPressed(miDPadLeft, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_LEFT;
+ if MappableInputs.PS4IsPressed(miDPadRight, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_RIGHT;
+
+ 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);
+
+ data^.rightStick.x:=Trunc(128+(MappableInputs.GetAnalog(miRJoyRight, cs)-MappableInputs.GetAnalog(miRJoyLeft, cs))*127);
+ data^.rightStick.y:=Trunc(128+(MappableInputs.GetAnalog(miRJoyDown , cs)-MappableInputs.GetAnalog(miRJoyUp , cs))*127);
+
+ data^.analogButtons.l2:=Trunc(MappableInputs.GetAnalog(miL2, cs)*255);
+ data^.analogButtons.r2:=Trunc(MappableInputs.GetAnalog(miR2, cs)*255);
+
+ if MappableInputs.PS4IsPressed(miL2, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L2;
+ if MappableInputs.PS4IsPressed(miR2, cs) then
+ data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R2;
+end;
+
+end.
+
+
+
diff --git a/src/ps4_libscepad.pas b/src/ps4_libscepad.pas
index 6f90aa62..c0bdc763 100644
--- a/src/ps4_libscepad.pas
+++ b/src/ps4_libscepad.pas
@@ -7,529 +7,175 @@ interface
uses
windows,
ps4_program,
- spinlock,
sys_signal,
Classes,
SysUtils,
- xinput,
- formController;
+
+ sce_pad_interface,
+ sdl2_pad_interface,
+ xinput_pad_interface,
+ kbm_pad_interface;
+
+Procedure select_pad_interface(const name:RawByteString);
+Procedure select_led_color (const name:RawByteString);
implementation
uses
- ps4_libSceVideoOut, uMappableInputs, sys_kernel;
+ sce_pad_types,
+ ps4_libSceVideoOut,
+ sys_kernel;
-const
- SCE_PAD_ERROR_INVALID_ARG =-2137915391; // 0x80920001
- SCE_PAD_ERROR_INVALID_PORT =-2137915390; // 0x80920002
- SCE_PAD_ERROR_INVALID_HANDLE =-2137915389; // 0x80920003
- SCE_PAD_ERROR_ALREADY_OPENED =-2137915388; // 0x80920004
- SCE_PAD_ERROR_NOT_INITIALIZED =-2137915387; // 0x80920005
- SCE_PAD_ERROR_INVALID_LIGHTBAR_SETTING=-2137915386; // 0x80920006
- SCE_PAD_ERROR_DEVICE_NOT_CONNECTED =-2137915385; // 0x80920007
- SCE_PAD_ERROR_NO_HANDLE =-2137915384; // 0x80920008
- SCE_PAD_ERROR_FATAL =-2137915137; // 0x809200FF
-
- SCE_PAD_BUTTON_L3 = $00000002;
- SCE_PAD_BUTTON_R3 = $00000004;
- SCE_PAD_BUTTON_OPTIONS = $00000008;
- SCE_PAD_BUTTON_UP = $00000010;
- SCE_PAD_BUTTON_RIGHT = $00000020;
- SCE_PAD_BUTTON_DOWN = $00000040;
- SCE_PAD_BUTTON_LEFT = $00000080;
- SCE_PAD_BUTTON_L2 = $00000100;
- SCE_PAD_BUTTON_R2 = $00000200;
- SCE_PAD_BUTTON_L1 = $00000400;
- SCE_PAD_BUTTON_R1 = $00000800;
- SCE_PAD_BUTTON_TRIANGLE = $00001000;
- SCE_PAD_BUTTON_CIRCLE = $00002000;
- SCE_PAD_BUTTON_CROSS = $00004000;
- SCE_PAD_BUTTON_SQUARE = $00008000;
- SCE_PAD_BUTTON_TOUCH_PAD = $00100000;
- SCE_PAD_BUTTON_INTERCEPTED = $80000000;
-
- SCE_PAD_MAX_TOUCH_NUM=2;
- SCE_PAD_MAX_DEVICE_UNIQUE_DATA_SIZE=12;
-
- SCE_PAD_CONNECTION_TYPE_LOCAL=0;
- SCE_PAD_CONNECTION_TYPE_REMOTE=1;
- SCE_PAD_CONNECTION_TYPE_REMOTE_VITA=SCE_PAD_CONNECTION_TYPE_REMOTE;
- SCE_PAD_CONNECTION_TYPE_REMOTE_DUALSHOCK4=2;
-
- //ScePadDeviceClass
- SCE_PAD_DEVICE_CLASS_INVALID = -1;
- SCE_PAD_DEVICE_CLASS_STANDARD = 0;
- SCE_PAD_DEVICE_CLASS_GUITAR = 1;
- SCE_PAD_DEVICE_CLASS_DRUM = 2;
- SCE_PAD_DEVICE_CLASS_DJ_TURNTABLE = 3;
- SCE_PAD_DEVICE_CLASS_DANCEMAT = 4;
- SCE_PAD_DEVICE_CLASS_NAVIGATION = 5;
- SCE_PAD_DEVICE_CLASS_STEERING_WHEEL = 6;
- SCE_PAD_DEVICE_CLASS_STICK = 7;
- SCE_PAD_DEVICE_CLASS_FLIGHT_STICK = 8;
- SCE_PAD_DEVICE_CLASS_GUN = 9;
-
-type
- Tvec_float3=packed record
- x,y,z:Single;
- end;
-
- Tvec_float4=packed record
- x,y,z,w:Single;
- end;
-
- ScePadAnalogStick=packed record
- x,y:Byte;
- end;
-
- ScePadAnalogButtons=packed record
- l2,r2:Byte;
- padding:Word;
- end;
-
- ScePadTouch=packed record
- x:Word;
- y:Word;
- id:Byte;
- reserve:array[0..2] of Byte;
- end;
-
- ScePadTouchData=packed record
- touchNum:Byte;
- reserve:array[0..2] of Byte;
- reserve1:DWORD;
- touch:array[0..SCE_PAD_MAX_TOUCH_NUM-1] of ScePadTouch;
- end;
-
- ScePadExtensionUnitData=packed record
- extensionUnitId:DWORD;
- reserve:Byte;
- dataLength:Byte;
- data:array[0..9] of Byte;
- end;
-
- PScePadData=^ScePadData;
- ScePadData=packed record
- buttons :DWORD;
- leftStick :ScePadAnalogStick;
- rightStick :ScePadAnalogStick;
- analogButtons :ScePadAnalogButtons;
- orientation :Tvec_float4;
- acceleration :Tvec_float3;
- angularVelocity :Tvec_float3;
- touchData :ScePadTouchData;
- connected :Boolean;
- _align:array[0..2] of Byte;
- timestamp :QWORD;
- extensionUnitData:ScePadExtensionUnitData;
- connectedCount :Byte;
- reserve:array[0..1] of Byte;
- deviceUniqueDataLen:Byte;
- deviceUniqueData:array[0..SCE_PAD_MAX_DEVICE_UNIQUE_DATA_SIZE-1] of Byte;
- end;
-
- TPadColor=packed record
- r,g,b,a:Byte;
- end;
-
- PScePadVibrationParam=^ScePadVibrationParam;
- ScePadVibrationParam=packed record
- largeMotor:Byte;
- smallMotor:Byte;
- end;
-
- ScePadColor=packed record
- r:Byte;
- g:Byte;
- b:Byte;
- reserve:Byte;
- end;
-
- ScePadLightBarParam=ScePadColor;
- PScePadLightBarParam=^ScePadLightBarParam;
-
- ScePadTouchPadInformation=packed record
- pixelDensity:Single;
- resolution:packed record
- x,y:Word;
- end;
- end;
-
- ScePadStickInformation=packed record
- deadZoneLeft:Byte;
- deadZoneRight:Byte;
- end;
-
- PScePadControllerInformation=^ScePadControllerInformation;
- ScePadControllerInformation=packed record
- touchPadInfo:ScePadTouchPadInformation;
- stickInfo:ScePadStickInformation;
- connectionType:Byte;
- connectedCount:Byte;
- connected:Boolean;
- _align:array[0..2] of Byte;
- deviceClass:DWORD; //ScePadDeviceClass
- reserve:array[0..7] of Byte;
- end;
-
- pScePadDeviceClassExtendedInformation=^ScePadDeviceClassExtendedInformation;
- ScePadDeviceClassExtendedInformation=packed record
- deviceClass:DWORD; //ScePadDeviceClass
- reserved:DWORD;
- classData:packed record
- Case Byte of
-
- 0:(steeringWheel:packed record
- capability:Byte;
- reserved1:Byte;
- maxPhysicalWheelAngle:Word;
- reserved2:QWORD;
- end);
-
- 1:(guitar:packed record
- capability:Byte;
- quantityOfSelectorSwitch:Byte;
- reserved1:Word;
- reserved2:QWORD;
- end);
-
- 2:(drum:packed record
- capability:Byte;
- reserved1:Byte;
- reserved2:Word;
- reserved3:QWORD;
- end);
-
- 3:(flightStick:packed record
- capability:Byte;
- reserved1:Byte;
- reserved2:Word;
- reserved3:QWORD;
- end);
-
- 4:(data:array[0..11] of Byte);
-
- end;
- end;
-
- pScePadDeviceClassData=^ScePadDeviceClassData;
- ScePadDeviceClassData=packed record
- deviceClass:DWORD; //ScePadDeviceClass
- bDataValid :Boolean;
- _align:array[0..2] of Byte;
- classData:packed record
- Case Byte of
-
- 0:(steeringWheel:packed record
- steeringWheelAngle:Single;
- steeringWheel :Word;
- acceleratorPedal :Word;
- brakePedal :Word;
- clutchPedal :Word;
- handBlake :Word;
- gear :Byte;
- reserved :Byte;
- end); //SCE_PAD_DEVICE_CLASS_STEERING_WHEEL
-
- 1:(guitar:packed record
- toneNumber:Byte;
- whammyBar :Byte;
- tilt :Byte;
- fret :Byte;
- fretSolo :Byte;
- reserved:array[0..10] of Byte;
- end); //SCE_PAD_DEVICE_CLASS_GUITAR
-
- 2:(drum:packed record
- snare :Byte;
- tom1 :Byte;
- tom2 :Byte;
- floorTom :Byte;
- hihatCymbal:Byte;
- rideCymbal :Byte;
- crashCymbal:Byte;
- reserved:array[0..8] of Byte;
- end); //SCE_PAD_DEVICE_CLASS_DRUM
-
- 3:(flightStick:packed record
- stickAxisX :Word;
- stickAxisY :Word;
- stickTwist :Byte;
- throttle :Byte;
- trigger :Byte;
- rudderPedal :Byte;
- brakePedalLeft :Byte;
- brakePedalRight:Byte;
- antennaKnob :Byte;
- rangeKnob :Byte;
- reserved:array[0..3] of Byte;
- end); //SCE_PAD_DEVICE_CLASS_FLIGHT_STICK
-
- 4:(others:packed record
- dataLen:Byte;
- reserved:array[0..2] of Byte;
- data:array[0..SCE_PAD_MAX_DEVICE_UNIQUE_DATA_SIZE-1] of Byte;
- end); //Not Supported device
-
- end;
- end;
+Const
+ DefaultPadInterface:TAbstractScePadInterface=TXInputPadInterface;
var
- last_mouse_lock:Pointer;
- last_mouse_point:TPoint;
- last_mouse_init:Integer=0;
- xinput_last_poll:Long=0;
- xinput_controllers_connected:Array[0..XUSER_MAX_COUNT-1] of Boolean;
+ ScePadInterface:TAbstractScePadInterface=nil;
+
+ DefaultPadLightBar:ScePadLightBarParam;
+
+Procedure select_pad_interface(const name:RawByteString);
+begin
+ case lowercase(name) of
+ 'xinput' :ScePadInterface:=TXInputPadInterface;
+ 'sdl2' :ScePadInterface:=TSdl2PadInterface;
+ 'keyboard':ScePadInterface:=TKbmPadInterface;
+ else
+ ScePadInterface:=DefaultPadInterface; //default
+ end;
+
+ if not ScePadInterface.Load then
+ begin
+ ScePadInterface:=TKbmPadInterface; //reset to kbm
+ end;
+end;
+
+Procedure select_led_color(const name:RawByteString);
+var
+ clr:DWord;
+begin
+ if TryStrToDWord(name,clr) then
+ begin
+ DefaultPadLightBar.r:=(clr shr 16) and $FF;
+ DefaultPadLightBar.g:=(clr shr 8) and $FF;
+ DefaultPadLightBar.b:=(clr shr 0) and $FF;
+ end;
+end;
function ps4_scePadInit():Integer; SysV_ABI_CDecl;
-var
- controllerIndex:Integer;
begin
Writeln(SysLogPrefix,'scePadInit');
- // init xinput
- for controllerIndex := 0 to XUSER_MAX_COUNT - 1 do
- xinput_controllers_connected[controllerIndex] := false;
+ if (ScePadInterface=nil) then
+ begin
+ ScePadInterface:=DefaultPadInterface; //default
+ if not ScePadInterface.Load then
+ begin
+ ScePadInterface:=TKbmPadInterface; //reset to kbm
+ end;
+ end;
- Result:=0;
+ Result:=ScePadInterface.Init;
end;
function ps4_scePadOpen(userID,_type,index:Integer;param:Pointer):Integer; SysV_ABI_CDecl;
+var
+ sce_handle:TScePadHandle;
+ key:Integer;
begin
- //Writeln('scePadOpen:',userID);
- Result:=222;
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
+
+ if (_type<>SCE_PAD_PORT_TYPE_STANDARD) then Exit(SCE_PAD_ERROR_INVALID_ARG);
+ if (index<0) or (index>15) then Exit(SCE_PAD_ERROR_INVALID_ARG);
+
+ sce_handle:=nil;
+ Result:=ScePadInterface.Open(index,sce_handle);
+ if (Result<>0) then Exit;
+
+ sce_handle.SetLightBar(@DefaultPadLightBar);
+
+ key:=0;
+ if pad_handles.New(sce_handle,key) then
+ begin
+ sce_handle.handle:=key;
+ sce_handle.Release;
+ Result:=key;
+ end else
+ begin
+ Result:=SCE_PAD_ERROR_FATAL;
+ end;
end;
function ps4_scePadGetHandle(userID,_type,index:Integer):Integer; SysV_ABI_CDecl;
begin
- Result:=222;
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
+
+ if (_type<>SCE_PAD_PORT_TYPE_STANDARD) then Exit(SCE_PAD_ERROR_INVALID_ARG);
+
+ if (index<0) or (index>15) then Exit(SCE_PAD_ERROR_INVALID_ARG);
+
+ if (pad_opened[index]=nil) then Exit(SCE_PAD_ERROR_NO_HANDLE);
+
+ Result:=pad_opened[index].handle;
end;
function ps4_scePadClose(handle:Integer):Integer; SysV_ABI_CDecl;
begin
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
+
+ if not pad_handles.Delete(handle) then Exit(SCE_PAD_ERROR_INVALID_HANDLE);
+
Result:=0;
end;
function ps4_scePadReadState(handle:Integer;data:PScePadData):Integer; SysV_ABI_CDecl;
var
- mPoint,delta:TPoint;
- cs:TXInputState;
- controllerIndex,stateResult:DWORD;
-
- function GetAsyncKeyState(vKey:longint):Boolean; inline;
- begin
- Result:=(Windows.GetKeyState(vKey) and $8000)<>0;
- end;
-
+ sce_handle:TScePadHandle;
begin
- Result:=SCE_PAD_ERROR_INVALID_ARG;
- if (data=nil) then Exit;
- //Writeln(SizeOf(TPadData)); //184
+ Result:=0;
+ if (data=nil) then Exit(SCE_PAD_ERROR_INVALID_ARG);
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
+
data^:=Default(ScePadData);
_sig_lock;
+ sce_handle:=TScePadHandle(pad_handles.Acqure(handle));
+
+ if (sce_handle=nil) then
+ begin
+ _sig_unlock;
+ Exit(SCE_PAD_ERROR_INVALID_HANDLE);
+ end;
+
//connect data
data^.timestamp:=Sysutils.GetTickCount64;
- data^.connected:=True;
+ data^.connected :=True;
data^.connectedCount:=1;
- data^.leftStick.x :=$80;
- data^.leftStick.y :=$80;
- data^.rightStick.x:=$80;
- data^.rightStick.y:=$80;
+ data^.leftStick.x :=$80;
+ data^.leftStick.y :=$80;
+ data^.rightStick.x :=$80;
+ data^.rightStick.y :=$80;
+ data^.orientation.w :=1;
+ data^.acceleration.y:=1;
//only in active windows
if (MainWindows<>GetForegroundWindow) then
begin
+ sce_handle.Release;
_sig_unlock;
Result:=0;
Exit;
end;
- // xinput - Check connected controllers every couple of seconds
- if GetTickCount64 > xinput_last_poll + 10000 then
- begin
- for controllerIndex := 0 to XUSER_MAX_COUNT - 1 do
- xinput_controllers_connected[controllerIndex] := XInputGetState(controllerIndex, cs) <> ERROR_DEVICE_NOT_CONNECTED;
-
- xinput_last_poll := GetTickCount64;
- end;
-
- // 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(@cs, SizeOf(cs));
- stateResult := XInputGetState(controllerIndex, cs);
-
- if stateResult = ERROR_SUCCESS then
- begin
- if MappableInputs.PS4IsPressed(miCross, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CROSS;
- if MappableInputs.PS4IsPressed(miCircle, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CIRCLE;
- if MappableInputs.PS4IsPressed(miSquare, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_SQUARE;
- if MappableInputs.PS4IsPressed(miTriangle, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_TRIANGLE;
-
- if MappableInputs.PS4IsPressed(miOptions, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_OPTIONS;
- if MappableInputs.PS4IsPressed(miTouchPad, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_TOUCH_PAD;
-
- if MappableInputs.PS4IsPressed(miL1, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L1;
- if MappableInputs.PS4IsPressed(miR1, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R1;
- if MappableInputs.PS4IsPressed(miL3, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L3;
- if MappableInputs.PS4IsPressed(miR3, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R3;
-
- if MappableInputs.PS4IsPressed(miDPadUp, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_UP;
- if MappableInputs.PS4IsPressed(miDPadDown, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_DOWN;
- if MappableInputs.PS4IsPressed(miDPadLeft, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_LEFT;
- if MappableInputs.PS4IsPressed(miDPadRight, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_RIGHT;
-
- 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);
-
- data^.rightStick.x:=Trunc(128+(MappableInputs.GetAnalog(miRJoyRight, cs)-MappableInputs.GetAnalog(miRJoyLeft, cs))*127);
- data^.rightStick.y:=Trunc(128+(MappableInputs.GetAnalog(miRJoyDown, cs)-MappableInputs.GetAnalog(miRJoyUp, cs))*127);
-
- data^.analogButtons.l2:=Trunc(MappableInputs.GetAnalog(miL2, cs)*255);
- data^.analogButtons.r2:=Trunc(MappableInputs.GetAnalog(miR2, cs)*255);
-
- if MappableInputs.PS4IsPressed(miL2, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L2;
- if MappableInputs.PS4IsPressed(miR2, cs) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R2;
- end;
- end;
-
- //mouse as touch pad
-
- spin_lock(last_mouse_lock);
-
- GetCursorPos(mPoint);
-
- if (last_mouse_init=0) then
- begin
- last_mouse_init :=1;
- last_mouse_point:=mPoint;
- end else
- if QWORD(mPoint)<>QWORD(last_mouse_point) then
- begin
- data^.touchData.touchNum:=1;
- data^.touchData.touch[0].id:=0;
-
- delta:=mPoint;
-
- if (delta.X<0) then delta.X:=0;
- if (delta.Y<0) then delta.Y:=0;
-
- if (delta.X>1919) then delta.X:=1919;
- if (delta.Y>941) then delta.Y:=941;
-
- data^.touchData.touch[0].x:=delta.X;
- data^.touchData.touch[0].y:=delta.Y;
-
- last_mouse_point:=mPoint;
- end;
-
- spin_unlock(last_mouse_lock);
-
- //keymapping
-
- if GetAsyncKeyState(VK_W) then
- data^.leftStick.y:=0;
-
- if GetAsyncKeyState(VK_S) then
- data^.leftStick.y:=$FF;
-
- if GetAsyncKeyState(VK_A) then
- data^.leftStick.x:=0;
-
- if GetAsyncKeyState(VK_D) then
- data^.leftStick.x:=$FF;
-
- //
-
- if GetAsyncKeyState(VK_I) then
- data^.rightStick.y:=0;
-
- if GetAsyncKeyState(VK_K) then
- data^.rightStick.y:=$FF;
-
- if GetAsyncKeyState(VK_J) then
- data^.rightStick.x:=0;
-
- if GetAsyncKeyState(VK_L) then
- data^.rightStick.x:=$FF;
-
- //
-
- if GetAsyncKeyState(VK_LBUTTON) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_TOUCH_PAD;
-
- if GetAsyncKeyState(VK_RETURN) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_OPTIONS;
-
- if GetAsyncKeyState(VK_UP) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_UP;
-
- if GetAsyncKeyState(VK_RIGHT) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_RIGHT;
-
- if GetAsyncKeyState(VK_DOWN) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_DOWN;
-
- if GetAsyncKeyState(VK_LEFT) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_LEFT;
-
- if GetAsyncKeyState(VK_NUMPAD8) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_TRIANGLE;
-
- if GetAsyncKeyState(VK_NUMPAD6) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CIRCLE;
-
- if GetAsyncKeyState(VK_NUMPAD2) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CROSS;
-
- if GetAsyncKeyState(VK_NUMPAD4) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_SQUARE;
-
- if GetAsyncKeyState(VK_Q) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L1;
-
- if GetAsyncKeyState(VK_1) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L2;
-
- if GetAsyncKeyState(VK_Z) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_L3;
-
-
- if GetAsyncKeyState(VK_E) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R1;
-
- if GetAsyncKeyState(VK_4) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R2;
-
- if GetAsyncKeyState(VK_C) then
- data^.buttons:=data^.buttons or SCE_PAD_BUTTON_R3;
+ sce_handle.ReadState(data);
+ sce_handle.Release;
_sig_unlock;
Result:=0;
end;
@@ -537,6 +183,9 @@ end;
function ps4_scePadRead(handle:Integer;data:PScePadData;num:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=0;
+ if (data=nil) then Exit(SCE_PAD_ERROR_INVALID_ARG);
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
+
if (num<>0) then
begin
ps4_scePadReadState(handle,data);
@@ -546,23 +195,66 @@ end;
function ps4_scePadSetVibration(handle:Integer;pParam:PScePadVibrationParam):Integer; SysV_ABI_CDecl;
begin
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
Result:=0;
end;
-function ps4_scePadResetLightBar(handle:Integer):Integer; assembler; nostackframe;
-asm
- xor %rax,%rax
+function ps4_scePadSetLightBar(handle:Integer;pParam:PScePadLightBarParam):Integer; SysV_ABI_CDecl;
+var
+ sce_handle:TScePadHandle;
+begin
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
+
+ if (pParam=nil) then Exit(SCE_PAD_ERROR_INVALID_ARG);
+
+ _sig_lock;
+
+ sce_handle:=TScePadHandle(pad_handles.Acqure(handle));
+
+ if (sce_handle=nil) then
+ begin
+ _sig_unlock;
+ Exit(SCE_PAD_ERROR_INVALID_HANDLE);
+ end;
+
+ Result:=sce_handle.SetLightBar(pParam);
+
+ sce_handle.Release;
+ _sig_unlock;
+end;
+
+function ps4_scePadResetLightBar(handle:Integer):Integer; SysV_ABI_CDecl;
+var
+ sce_handle:TScePadHandle;
+begin
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
+
+ _sig_lock;
+
+ sce_handle:=TScePadHandle(pad_handles.Acqure(handle));
+
+ if (sce_handle=nil) then
+ begin
+ _sig_unlock;
+ Exit(SCE_PAD_ERROR_INVALID_HANDLE);
+ end;
+
+ Result:=sce_handle.ResetLightBar();
+
+ sce_handle.Release;
+ _sig_unlock;
end;
function ps4_scePadGetControllerInformation(handle:Integer;
pInfo:PScePadControllerInformation
):Integer; SysV_ABI_CDecl;
begin
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
if (pInfo=nil) then Exit(SCE_PAD_ERROR_INVALID_ARG);
pInfo^:=Default(ScePadControllerInformation);
pInfo^.touchPadInfo.pixelDensity := 1;
- pInfo^.touchPadInfo.resolution.x := 256;
- pInfo^.touchPadInfo.resolution.y := 256;
+ pInfo^.touchPadInfo.resolution.x := 1920;
+ pInfo^.touchPadInfo.resolution.y := 950;
pInfo^.stickInfo.deadZoneLeft := 2;
pInfo^.stickInfo.deadZoneRight := 2;
pInfo^.connectionType := SCE_PAD_CONNECTION_TYPE_LOCAL;
@@ -576,6 +268,7 @@ function ps4_scePadDeviceClassGetExtendedInformation(handle:Integer;
pExtInfo:pScePadDeviceClassExtendedInformation
):Integer; SysV_ABI_CDecl;
begin
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
if (pExtInfo=nil) then Exit(SCE_PAD_ERROR_INVALID_ARG);
pExtInfo^:=Default(ScePadDeviceClassExtendedInformation);
pExtInfo^.deviceClass:=SCE_PAD_DEVICE_CLASS_STANDARD;
@@ -587,6 +280,7 @@ function ps4_scePadDeviceClassParseData(handle:Integer;
pDeviceClassData:pScePadDeviceClassData
):Integer; SysV_ABI_CDecl;
begin
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
if (pData=nil) then Exit(SCE_PAD_ERROR_INVALID_ARG);
if (pDeviceClassData=nil) then Exit(SCE_PAD_ERROR_INVALID_ARG);
pDeviceClassData^:=Default(ScePadDeviceClassData);
@@ -597,26 +291,25 @@ end;
function ps4_scePadSetMotionSensorState(handle:Integer;bEnable:Boolean):Integer; SysV_ABI_CDecl;
begin
- Result:=0;
-end;
-
-function ps4_scePadSetLightBar(handle:Integer;pParam:PScePadLightBarParam):Integer; SysV_ABI_CDecl;
-begin
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
Result:=0;
end;
function ps4_scePadResetOrientation(handle:Integer):Integer; SysV_ABI_CDecl;
begin
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
Result:=0;
end;
function ps4_scePadSetTiltCorrectionState(handle:Integer;bEnable:BOOL):Integer; SysV_ABI_CDecl;
begin
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
Result:=0;
end;
function ps4_scePadSetAngularVelocityDeadbandState(handle:Integer;bEnable:BOOL):Integer; SysV_ABI_CDecl;
begin
+ if (ScePadInterface=nil) then Exit(SCE_PAD_ERROR_NOT_INITIALIZED);
Result:=0;
end;
@@ -636,12 +329,12 @@ begin
lib^.set_proc($6277605EA41557B7,@ps4_scePadReadState);
lib^.set_proc($AB570735F1B270B2,@ps4_scePadRead);
lib^.set_proc($C8556739D1B1BD96,@ps4_scePadSetVibration);
+ lib^.set_proc($451E27A2F50410D6,@ps4_scePadSetLightBar);
lib^.set_proc($0EC703D62F475F5C,@ps4_scePadResetLightBar);
lib^.set_proc($8233FDFCA433A149,@ps4_scePadGetControllerInformation);
lib^.set_proc($01CB25A4DD631D1F,@ps4_scePadDeviceClassGetExtendedInformation);
lib^.set_proc($2073EA71B734CC20,@ps4_scePadDeviceClassParseData);
lib^.set_proc($72556F2F86439EDC,@ps4_scePadSetMotionSensorState);
- lib^.set_proc($451E27A2F50410D6,@ps4_scePadSetLightBar);
lib^.set_proc($AC866747A792A6F9,@ps4_scePadResetOrientation);
lib^.set_proc($BC32CCA092DD7BC2,@ps4_scePadSetTiltCorrectionState);
lib^.set_proc($AF8E260317521BE5,@ps4_scePadSetAngularVelocityDeadbandState);