#Region Project Attributes
#MainFormWidth: 600
#MainFormHeight: 600
' ### needed for java 19 ###
#VirtualMachineArgs: --enable-preview --enable-native-access=ALL-UNNAMED
#PackagerProperty: VMArgs = --enable-preview
' ##########################
#End Region
Sub Process_Globals
Private fx As JFX
Private MainForm As Form
Private xui As XUI
Private Button1 As B4XView
End Sub
Sub AppStart (Form1 As Form, Args() As String)
MainForm = Form1
MainForm.RootPane.LoadLayout("Layout1")
MainForm.Show
End Sub
Sub Button1_Click
'xui.MsgboxAsync("Hello World!", "B4X")
(Me).As(JavaObject).RunMethod("doIt",Null)
End Sub
#if java
import java.lang.foreign.*;
import java.lang.invoke.*;
import java.lang.foreign.ValueLayout.*;
// define the structure XINPUT_STATE
static GroupLayout XINPUT_STATE = MemoryLayout.structLayout(OfInt.JAVA_INT.withName("dwPacketNumber"),
OfShort.JAVA_SHORT.withName("wButtons"), OfByte.JAVA_BYTE.withName("bLeftTrigger"),
OfByte.JAVA_BYTE.withName("bRightTrigger"), OfShort.JAVA_SHORT.withName("sThumbLX"),
OfShort.JAVA_SHORT.withName("sThumbLY"), OfShort.JAVA_SHORT.withName("sThumbRX"),
OfShort.JAVA_SHORT.withName("sThumbRY")).withName("IState");
// define structure ena
static GroupLayout ena = MemoryLayout.structLayout(ValueLayout.OfBoolean.JAVA_BOOLEAN.withName("enabled"));
// define the variables we will access in the structures
static VarHandle buttons = XINPUT_STATE.varHandle(MemoryLayout.PathElement.groupElement("wButtons"));
static VarHandle LTrig = XINPUT_STATE.varHandle(MemoryLayout.PathElement.groupElement("bLeftTrigger"));
static VarHandle RTrig = XINPUT_STATE.varHandle(MemoryLayout.PathElement.groupElement("bRightTrigger"));
static VarHandle LThumbX = XINPUT_STATE.varHandle(MemoryLayout.PathElement.groupElement("sThumbLX"));
static VarHandle LThumbY = XINPUT_STATE.varHandle(MemoryLayout.PathElement.groupElement("sThumbLY"));
static VarHandle RThumbX = XINPUT_STATE.varHandle(MemoryLayout.PathElement.groupElement("sThumbRX"));
static VarHandle RThumbY = XINPUT_STATE.varHandle(MemoryLayout.PathElement.groupElement("sThumbRY"));
static VarHandle PackNo = XINPUT_STATE.varHandle(MemoryLayout.PathElement.groupElement("dwPacketNumber"));
static VarHandle enabledFlag = ena.varHandle(MemoryLayout.PathElement.groupElement("enabled"));
public static void doIt() {
try {
// set up memorySession - can be inside or outside the JVM
var memorySession = MemorySession.openConfined();
// allocate so memory for the structure
var xin = memorySession.allocate(XINPUT_STATE);
// set up linkers & loaders
Linker nativeLinker = Linker.nativeLinker();
SymbolLookup stdlibLookup = nativeLinker.defaultLookup();
SymbolLookup loaderLookup = SymbolLookup.loaderLookup();
// load System library XInput1_4
System.loadLibrary("XInput1_4");
//get method XInputEnable in XInput1_4.dll
MethodHandle enable = nativeLinker.downcallHandle(
stdlibLookup.lookup("XInputEnable").or(() -> loaderLookup.lookup("XInputEnable")).orElseThrow(),
FunctionDescriptor.of(OfInt.JAVA_INT,OfAddress.ADDRESS /*OfBoolean.JAVA_BOOLEAN*/));
//Enable readings on joystick/gamepad
// allocate some memory and invoke foreign function
var enab = memorySession.allocate(ena);
// format is VarHandleName .set (memorySessionName , theValueYouWantToSet)
enabledFlag.set(enab, true);
enable.invoke(enab);
//just a check
//System.out.println("en flag : " + enabledFlag.get(enab));
//get method XInputGetStae in XInput1_4.dll
// descriptor is returnType, Args in order
// so XInputGetState return an int (DWORD) , takes an int (DWORD) and takes a structure address (&XINPUT_STATE)
MethodHandle readem = nativeLinker.downcallHandle(
stdlibLookup.lookup("XInputGetState").or(() -> loaderLookup.lookup("XInputGetState")).orElseThrow(),
FunctionDescriptor.of(OfInt.JAVA_INT,OfInt.JAVA_INT,OfAddress.ADDRESS));
int res = (int) readem.invoke(0, xin.address());// pad number - address of struct
// 0 is good anything else is reason for failure like 1167 = no gamepads found
System.out.println("Res : " + res);
// get left trigger value
Integer LT = (int) LTrig.get(xin);
System.out.println("ltrig : " + (LT + 256)%256); // normalise to 0 - 255
// get buttons pressed
int b = (short) buttons.get(xin);
System.out.println("Buttons : " + b); // buttons is bitwise field for buttons pressed see below
} catch (Throwable t) {
System.out.println(t.getMessage()); //t.printStackTrace();
}
}
#End If
'XINPUT_GAMEPAD_DPAD_UP 0x0001
'XINPUT_GAMEPAD_DPAD_DOWN 0x0002
'XINPUT_GAMEPAD_DPAD_LEFT 0x0004
'XINPUT_GAMEPAD_DPAD_RIGHT 0x0008
'XINPUT_GAMEPAD_START 0x0010
'XINPUT_GAMEPAD_BACK 0x0020
'XINPUT_GAMEPAD_LEFT_THUMB 0x0040
'XINPUT_GAMEPAD_RIGHT_THUMB 0x0080
'XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100
'XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200
'XINPUT_GAMEPAD_A 0x1000
'XINPUT_GAMEPAD_B 0x2000
'XINPUT_GAMEPAD_X 0x4000
'XINPUT_GAMEPAD_Y 0x8000