mirror of https://github.com/red-prig/fpPS4.git
SDL2 Input Implementation (#131)
* initial SDL2 input stub restored only light button presses, bumpers, d-pad works axis, triggers, haptics and long presses haven't been implemented yet * fixed bumpers, buttons and hats cross, circle, square, triangle, L1, R1, L3, R3 and D-PAD should now work well * axes and triggers support added Left and Right stick should now work along with L2 and R2 * minor oopsie daisy fixed dpad down button * + controller info console output added + led set to pink (for goofy reasons) * Clipped headers from "SDL2-for-Pascal" * sdl2 made dynamically loadable * xinput made dynamically loadable * Detached headers * sce_pad_interface prototype * + * keyboard/mouse interface * touchpad * + * xinput interface * add LightBar interface * SDL_PollEvent * select_pad_interface * select_led_color * + --------- Co-authored-by: red-prig <vdpasha@mail.ru>
This commit is contained in:
parent
d39bc5d685
commit
929e72b83a
22
fpPS4.lpi
22
fpPS4.lpi
|
@ -31,7 +31,7 @@
|
|||
<PackageName Value="LCL"/>
|
||||
</Item1>
|
||||
</RequiredPackages>
|
||||
<Units Count="139">
|
||||
<Units Count="144">
|
||||
<Unit0>
|
||||
<Filename Value="fpPS4.lpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
|
@ -640,6 +640,26 @@
|
|||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="ps4_libSceNpAuth"/>
|
||||
</Unit138>
|
||||
<Unit139>
|
||||
<Filename Value="src\inputs\sce_pad_types.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit139>
|
||||
<Unit140>
|
||||
<Filename Value="src\inputs\sce_pad_interface.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit140>
|
||||
<Unit141>
|
||||
<Filename Value="src\inputs\sdl2_pad_interface.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit141>
|
||||
<Unit142>
|
||||
<Filename Value="src\inputs\kbm_pad_interface.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit142>
|
||||
<Unit143>
|
||||
<Filename Value="src\inputs\xinput_pad_interface.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit143>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
|
|
35
fpPS4.lpr
35
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 <name> //Decrypted ELF or SELF file name');
|
||||
Writeln(' -f <name> //Folder of app (/app0)');
|
||||
Writeln(' -p <name> //Folder of patch (/app1)');
|
||||
Writeln(' -s <name> //Savedata path');
|
||||
Writeln(' -w //Fullscreen mode');
|
||||
Writeln(' -e <name> //Decrypted ELF or SELF file name');
|
||||
Writeln(' -f <name> //Folder of app (/app0)');
|
||||
Writeln(' -p <name> //Folder of patch (/app1)');
|
||||
Writeln(' -s <name> //Savedata path');
|
||||
Writeln(' -w //Fullscreen mode');
|
||||
Writeln(' -pad <name> //Gamepad interface selection (xinput,sdl2,keyboard) default:xinput');
|
||||
Writeln(' -led <clr> //Initial LED color of Gamepad ($rrggbb)');
|
||||
|
||||
Writeln(' -h <name> //enable hack');
|
||||
Writeln(' -h <name> //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.
|
||||
|
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
||||
|
|
@ -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.
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue