Updated SDL3 to 3.4.16, and disabled Wayland for now
This commit is contained in:
parent
56aada6cc6
commit
5729057e32
14 changed files with 457 additions and 104 deletions
|
|
@ -402,7 +402,7 @@ elseif(LINUX)
|
||||||
set(SDL_TESTS OFF CACHE BOOL "Compile SDL tests")
|
set(SDL_TESTS OFF CACHE BOOL "Compile SDL tests")
|
||||||
set(SDL_INSTALL_DOCS OFF CACHE BOOL "Install docs")
|
set(SDL_INSTALL_DOCS OFF CACHE BOOL "Install docs")
|
||||||
set(SDL_INSTALL_TESTS OFF CACHE BOOL "Install tests")
|
set(SDL_INSTALL_TESTS OFF CACHE BOOL "Install tests")
|
||||||
set(SDL_WAYLAND ON CACHE BOOL "Compile SDL for Wayland")
|
set(SDL_WAYLAND OFF CACHE BOOL "Compile SDL for Wayland")
|
||||||
set(SDL_X11 ON CACHE BOOL "Compile SDL for X11")
|
set(SDL_X11 ON CACHE BOOL "Compile SDL for X11")
|
||||||
set(SDL_AUDIO OFF CACHE BOOL "Compile SDL Audio")
|
set(SDL_AUDIO OFF CACHE BOOL "Compile SDL Audio")
|
||||||
set(SDL_STATIC ON CACHE BOOL "Compile SDL statically")
|
set(SDL_STATIC ON CACHE BOOL "Compile SDL statically")
|
||||||
|
|
|
||||||
4
android-project/app/proguard-rules.pro
vendored
4
android-project/app/proguard-rules.pro
vendored
|
|
@ -56,10 +56,11 @@
|
||||||
boolean setSystemCursor(int);
|
boolean setSystemCursor(int);
|
||||||
void setWindowStyle(boolean);
|
void setWindowStyle(boolean);
|
||||||
boolean shouldMinimizeOnFocusLoss();
|
boolean shouldMinimizeOnFocusLoss();
|
||||||
|
boolean showFileDialog(java.lang.String[], boolean, boolean, int);
|
||||||
boolean showTextInput(int, int, int, int, int);
|
boolean showTextInput(int, int, int, int, int);
|
||||||
boolean supportsRelativeMouse();
|
boolean supportsRelativeMouse();
|
||||||
int openFileDescriptor(java.lang.String, java.lang.String);
|
int openFileDescriptor(java.lang.String, java.lang.String);
|
||||||
boolean showFileDialog(java.lang.String[], boolean, boolean, int);
|
boolean showFileDialog(java.lang.String[], boolean, int, java.lang.String, int);
|
||||||
java.lang.String getPreferredLocales();
|
java.lang.String getPreferredLocales();
|
||||||
java.lang.String formatLocale(java.util.Locale);
|
java.lang.String formatLocale(java.util.Locale);
|
||||||
}
|
}
|
||||||
|
|
@ -79,6 +80,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLControllerManager {
|
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLControllerManager {
|
||||||
|
void joystickSetSensorsEnabled(int, boolean);
|
||||||
void pollInputDevices();
|
void pollInputDevices();
|
||||||
void joystickSetLED(int, int, int, int);
|
void joystickSetLED(int, int, int, int);
|
||||||
void pollHapticDevices();
|
void pollHapticDevices();
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,13 @@ import android.os.*;
|
||||||
|
|
||||||
import java.lang.Runnable;
|
import java.lang.Runnable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDevice {
|
class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDevice {
|
||||||
|
|
||||||
private static final String TAG = "hidapi";
|
private static final String TAG = "hidapi";
|
||||||
|
|
@ -33,10 +37,19 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
private boolean mIsConnected = false;
|
private boolean mIsConnected = false;
|
||||||
private boolean mIsChromebook = false;
|
private boolean mIsChromebook = false;
|
||||||
private boolean mIsReconnecting = false;
|
private boolean mIsReconnecting = false;
|
||||||
|
private boolean mHasEnabledNotifications = false;
|
||||||
|
private boolean mHasSeenInputUpdate = false;
|
||||||
private boolean mFrozen = false;
|
private boolean mFrozen = false;
|
||||||
private LinkedList<GattOperation> mOperations;
|
private LinkedList<GattOperation> mOperations;
|
||||||
GattOperation mCurrentOperation = null;
|
GattOperation mCurrentOperation = null;
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
|
private int mProductId = -1;
|
||||||
|
private int mReportId = 0;
|
||||||
|
private UUID mInputCharacteristic;
|
||||||
|
|
||||||
|
private static final int D0G_BLE2_PID = 0x1106;
|
||||||
|
private static final int TRITON_BLE_PID = 0x1303;
|
||||||
|
|
||||||
|
|
||||||
private static final int TRANSPORT_AUTO = 0;
|
private static final int TRANSPORT_AUTO = 0;
|
||||||
private static final int TRANSPORT_BREDR = 1;
|
private static final int TRANSPORT_BREDR = 1;
|
||||||
|
|
@ -45,10 +58,14 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
private static final int CHROMEBOOK_CONNECTION_CHECK_INTERVAL = 10000;
|
private static final int CHROMEBOOK_CONNECTION_CHECK_INTERVAL = 10000;
|
||||||
|
|
||||||
static final UUID steamControllerService = UUID.fromString("100F6C32-1735-4313-B402-38567131E5F3");
|
static final UUID steamControllerService = UUID.fromString("100F6C32-1735-4313-B402-38567131E5F3");
|
||||||
static final UUID inputCharacteristic = UUID.fromString("100F6C33-1735-4313-B402-38567131E5F3");
|
static final UUID inputCharacteristicD0G = UUID.fromString("100F6C33-1735-4313-B402-38567131E5F3");
|
||||||
|
static final UUID inputCharacteristicTriton_0x45 = UUID.fromString("100F6C7A-1735-4313-B402-38567131E5F3");
|
||||||
|
static final UUID inputCharacteristicTriton_0x47 = UUID.fromString("100F6C7C-1735-4313-B402-38567131E5F3");
|
||||||
static final UUID reportCharacteristic = UUID.fromString("100F6C34-1735-4313-B402-38567131E5F3");
|
static final UUID reportCharacteristic = UUID.fromString("100F6C34-1735-4313-B402-38567131E5F3");
|
||||||
static private final byte[] enterValveMode = new byte[] { (byte)0xC0, (byte)0x87, 0x03, 0x08, 0x07, 0x00 };
|
static private final byte[] enterValveMode = new byte[] { (byte)0xC0, (byte)0x87, 0x03, 0x08, 0x07, 0x00 };
|
||||||
|
|
||||||
|
private HashMap<Integer, BluetoothGattCharacteristic> mOutputReportChars = new HashMap<Integer, BluetoothGattCharacteristic>();
|
||||||
|
|
||||||
static class GattOperation {
|
static class GattOperation {
|
||||||
private enum Operation {
|
private enum Operation {
|
||||||
CHR_READ,
|
CHR_READ,
|
||||||
|
|
@ -61,6 +78,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
byte[] mValue;
|
byte[] mValue;
|
||||||
BluetoothGatt mGatt;
|
BluetoothGatt mGatt;
|
||||||
boolean mResult = true;
|
boolean mResult = true;
|
||||||
|
int mDelayMs = 0;
|
||||||
|
|
||||||
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid) {
|
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid) {
|
||||||
mGatt = gatt;
|
mGatt = gatt;
|
||||||
|
|
@ -68,6 +86,13 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
mUuid = uuid;
|
mUuid = uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, int delayMs) {
|
||||||
|
mGatt = gatt;
|
||||||
|
mOp = operation;
|
||||||
|
mUuid = uuid;
|
||||||
|
mDelayMs = delayMs;
|
||||||
|
}
|
||||||
|
|
||||||
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, byte[] value) {
|
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, byte[] value) {
|
||||||
mGatt = gatt;
|
mGatt = gatt;
|
||||||
mOp = operation;
|
mOp = operation;
|
||||||
|
|
@ -75,6 +100,14 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
mValue = value;
|
mValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, byte[] value, int delayMs) {
|
||||||
|
mGatt = gatt;
|
||||||
|
mOp = operation;
|
||||||
|
mUuid = uuid;
|
||||||
|
mValue = value;
|
||||||
|
mDelayMs = delayMs;
|
||||||
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
// This is executed in main thread
|
// This is executed in main thread
|
||||||
BluetoothGattCharacteristic chr;
|
BluetoothGattCharacteristic chr;
|
||||||
|
|
@ -136,6 +169,8 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
return mResult;
|
return mResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getDelayMs() { return mDelayMs; }
|
||||||
|
|
||||||
private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
|
private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
|
||||||
BluetoothGattService valveService = mGatt.getService(steamControllerService);
|
BluetoothGattService valveService = mGatt.getService(steamControllerService);
|
||||||
if (valveService == null)
|
if (valveService == null)
|
||||||
|
|
@ -154,6 +189,10 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
static public GattOperation enableNotification(BluetoothGatt gatt, UUID uuid) {
|
static public GattOperation enableNotification(BluetoothGatt gatt, UUID uuid) {
|
||||||
return new GattOperation(gatt, Operation.ENABLE_NOTIFICATION, uuid);
|
return new GattOperation(gatt, Operation.ENABLE_NOTIFICATION, uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public GattOperation enableNotification(BluetoothGatt gatt, UUID uuid, int delayMs) {
|
||||||
|
return new GattOperation(gatt, Operation.ENABLE_NOTIFICATION, uuid, delayMs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HIDDeviceBLESteamController(HIDDeviceManager manager, BluetoothDevice device) {
|
HIDDeviceBLESteamController(HIDDeviceManager manager, BluetoothDevice device) {
|
||||||
|
|
@ -166,6 +205,8 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
mHandler = new Handler(Looper.getMainLooper());
|
mHandler = new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
mGatt = connectGatt();
|
mGatt = connectGatt();
|
||||||
|
mHasEnabledNotifications = false;
|
||||||
|
mHasSeenInputUpdate = false;
|
||||||
// final HIDDeviceBLESteamController finalThis = this;
|
// final HIDDeviceBLESteamController finalThis = this;
|
||||||
// mHandler.postDelayed(new Runnable() {
|
// mHandler.postDelayed(new Runnable() {
|
||||||
// @Override
|
// @Override
|
||||||
|
|
@ -314,8 +355,45 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
Log.v(TAG, "Found Valve steam controller service " + service.getUuid());
|
Log.v(TAG, "Found Valve steam controller service " + service.getUuid());
|
||||||
|
|
||||||
for (BluetoothGattCharacteristic chr : service.getCharacteristics()) {
|
for (BluetoothGattCharacteristic chr : service.getCharacteristics()) {
|
||||||
if (chr.getUuid().equals(inputCharacteristic)) {
|
if (chr.getUuid().equals(inputCharacteristicTriton_0x45)) {
|
||||||
Log.v(TAG, "Found input characteristic");
|
Log.v(TAG, "Found Triton input characteristic 0x45");
|
||||||
|
mProductId = TRITON_BLE_PID;
|
||||||
|
mReportId = 0x45;
|
||||||
|
mInputCharacteristic = chr.getUuid();
|
||||||
|
} else if (chr.getUuid().equals(inputCharacteristicTriton_0x47)) {
|
||||||
|
Log.v(TAG, "Found Triton input characteristic 0x47");
|
||||||
|
mProductId = TRITON_BLE_PID;
|
||||||
|
mReportId = 0x47;
|
||||||
|
mInputCharacteristic = chr.getUuid();
|
||||||
|
} else if (chr.getUuid().equals(inputCharacteristicD0G)) {
|
||||||
|
Log.v(TAG, "Found D0G input characteristic");
|
||||||
|
mProductId = D0G_BLE2_PID;
|
||||||
|
mReportId = 0x03;
|
||||||
|
mInputCharacteristic = chr.getUuid();
|
||||||
|
} else {
|
||||||
|
Pattern reportPattern = Pattern.compile("100F6C([0-9A-Z]{2})", Pattern.CASE_INSENSITIVE);
|
||||||
|
Matcher matcher = reportPattern.matcher(chr.getUuid().toString());
|
||||||
|
|
||||||
|
if (matcher.find()) {
|
||||||
|
try {
|
||||||
|
int reportId = Integer.parseInt(matcher.group(1), 16);
|
||||||
|
|
||||||
|
reportId -= 0x35;
|
||||||
|
if (reportId >= 0x80) {
|
||||||
|
// This is a Triton output report characteristic that we need to care about.
|
||||||
|
Log.v(TAG, "Found Triton output report 0x" + Integer.toString(reportId, 16));
|
||||||
|
mOutputReportChars.put(reportId, chr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NumberFormatException nfe) {
|
||||||
|
Log.w(TAG, "Could not parse report characteristic " + chr.getUuid().toString() + ": " + nfe.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BluetoothGattCharacteristic chr : service.getCharacteristics()) {
|
||||||
|
if (chr.getUuid().equals(mInputCharacteristic)) {
|
||||||
// Start notifications
|
// Start notifications
|
||||||
BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
|
BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
|
||||||
if (cccd != null) {
|
if (cccd != null) {
|
||||||
|
|
@ -372,8 +450,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
mCurrentOperation = mOperations.removeFirst();
|
mCurrentOperation = mOperations.removeFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run in main thread
|
Runnable gattOperationRunnable = new Runnable() {
|
||||||
mHandler.post(new Runnable() {
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (mOperations) {
|
synchronized (mOperations) {
|
||||||
|
|
@ -386,7 +463,17 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
// now wait for the GATT callback and when it comes, finish this operation
|
// now wait for the GATT callback and when it comes, finish this operation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (mCurrentOperation.getDelayMs() == 0) {
|
||||||
|
// Run in main thread
|
||||||
|
mHandler.post(gattOperationRunnable);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If we have a delay on this operation, wait before we post it.
|
||||||
|
mHandler.postDelayed(gattOperationRunnable, mCurrentOperation.getDelayMs());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void queueGattOperation(GattOperation op) {
|
private void queueGattOperation(GattOperation op) {
|
||||||
|
|
@ -397,8 +484,39 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableNotification(UUID chrUuid) {
|
private void enableNotification(UUID chrUuid) {
|
||||||
GattOperation op = HIDDeviceBLESteamController.GattOperation.enableNotification(mGatt, chrUuid);
|
// Add a 500ms delay to notification write for Amazon Fire TV devices, as otherwise if we do this too quickly after connecting
|
||||||
|
// it will return success and then silently drop the operation on the floor.
|
||||||
|
GattOperation op = HIDDeviceBLESteamController.GattOperation.enableNotification(mGatt, chrUuid, 500);
|
||||||
queueGattOperation(op);
|
queueGattOperation(op);
|
||||||
|
|
||||||
|
// Amazon Fire devices can also silently timeout on writeDescriptor, so
|
||||||
|
// set up a little delayed check that will attempt to write a second time.
|
||||||
|
//
|
||||||
|
// While this only seems to be needed on Amazon Fire TV devices at present, it
|
||||||
|
// doesn't hurt to have a retry on other devices as well.
|
||||||
|
//
|
||||||
|
final HIDDeviceBLESteamController finalThis = this;
|
||||||
|
final UUID finalUuid = chrUuid;
|
||||||
|
mHandler.postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!finalThis.mHasEnabledNotifications) {
|
||||||
|
|
||||||
|
if (finalThis.mHasSeenInputUpdate) {
|
||||||
|
// Amazon Five devices may have enabled notifications on the input characteristic and not given us a callback. If we've seen
|
||||||
|
// input reports, though, somewhat by definition notifications are enabled.
|
||||||
|
Log.w(TAG, "WriteDescriptor has never returned, but we've seen input reports. Moving on with controller initialization.");
|
||||||
|
finalThis.mHasEnabledNotifications = true;
|
||||||
|
finalThis.enableValveMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give one more try.
|
||||||
|
GattOperation retry = HIDDeviceBLESteamController.GattOperation.enableNotification(finalThis.mGatt, finalUuid, 500);
|
||||||
|
finalThis.queueGattOperation(retry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeCharacteristic(UUID uuid, byte[] value) {
|
void writeCharacteristic(UUID uuid, byte[] value) {
|
||||||
|
|
@ -448,8 +566,16 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
mIsConnected = false;
|
mIsConnected = false;
|
||||||
gatt.disconnect();
|
gatt.disconnect();
|
||||||
mGatt = connectGatt(false);
|
mGatt = connectGatt(false);
|
||||||
|
} else {
|
||||||
|
if (getProductId() == TRITON_BLE_PID) {
|
||||||
|
// Android will not properly play well with Data Length Extensions without manually requesting a large MTU,
|
||||||
|
// and Triton controllers require DLE support.
|
||||||
|
//
|
||||||
|
// 517 is basically a "magic number" as far as Android's bluetooth code is concerned, so do not change
|
||||||
|
// this value. It is functionally "please enable data length extensions" on some Android builds.
|
||||||
|
mGatt.requestMtu(517);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
probeService(this);
|
probeService(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -474,7 +600,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
// Only register controller with the native side once it has been fully configured
|
// Only register controller with the native side once it has been fully configured
|
||||||
if (!isRegistered()) {
|
if (!isRegistered()) {
|
||||||
Log.v(TAG, "Registering Steam Controller with ID: " + getId());
|
Log.v(TAG, "Registering Steam Controller with ID: " + getId());
|
||||||
mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0, 0, 0, 0, true);
|
mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0, 0, 0, 0, true, mReportId);
|
||||||
setRegistered();
|
setRegistered();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -487,7 +613,8 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
// Enable this for verbose logging of controller input reports
|
// Enable this for verbose logging of controller input reports
|
||||||
//Log.v(TAG, "onCharacteristicChanged uuid=" + characteristic.getUuid() + " data=" + HexDump.dumpHexString(characteristic.getValue()));
|
//Log.v(TAG, "onCharacteristicChanged uuid=" + characteristic.getUuid() + " data=" + HexDump.dumpHexString(characteristic.getValue()));
|
||||||
|
|
||||||
if (characteristic.getUuid().equals(inputCharacteristic) && !mFrozen) {
|
if (characteristic.getUuid().equals(mInputCharacteristic) && !mFrozen) {
|
||||||
|
mHasSeenInputUpdate = true;
|
||||||
mManager.HIDDeviceInputReport(getId(), characteristic.getValue());
|
mManager.HIDDeviceInputReport(getId(), characteristic.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -497,19 +624,36 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
//Log.v(TAG, "onDescriptorRead status=" + status);
|
//Log.v(TAG, "onDescriptorRead status=" + status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enableValveMode()
|
||||||
|
{
|
||||||
|
BluetoothGattService valveService = mGatt.getService(steamControllerService);
|
||||||
|
if (valveService == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BluetoothGattCharacteristic reportChr = valveService.getCharacteristic(reportCharacteristic);
|
||||||
|
if (reportChr != null) {
|
||||||
|
if (getProductId() == TRITON_BLE_PID) {
|
||||||
|
// For Triton we just mark things registered.
|
||||||
|
Log.v(TAG, "Registering Triton Steam Controller with ID: " + getId());
|
||||||
|
mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0, 0, 0, 0, true, mReportId);
|
||||||
|
setRegistered();
|
||||||
|
} else {
|
||||||
|
// For the original controller, we need to manually enter Valve mode.
|
||||||
|
Log.v(TAG, "Writing report characteristic to enter valve mode");
|
||||||
|
reportChr.setValue(enterValveMode);
|
||||||
|
mGatt.writeCharacteristic(reportChr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
|
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
|
||||||
BluetoothGattCharacteristic chr = descriptor.getCharacteristic();
|
BluetoothGattCharacteristic chr = descriptor.getCharacteristic();
|
||||||
//Log.v(TAG, "onDescriptorWrite status=" + status + " uuid=" + chr.getUuid() + " descriptor=" + descriptor.getUuid());
|
//Log.v(TAG, "onDescriptorWrite status=" + status + " uuid=" + chr.getUuid() + " descriptor=" + descriptor.getUuid());
|
||||||
|
|
||||||
if (chr.getUuid().equals(inputCharacteristic)) {
|
if (chr.getUuid().equals(mInputCharacteristic)) {
|
||||||
boolean hasWrittenInputDescriptor = true;
|
mHasEnabledNotifications = true;
|
||||||
BluetoothGattCharacteristic reportChr = chr.getService().getCharacteristic(reportCharacteristic);
|
enableValveMode();
|
||||||
if (reportChr != null) {
|
|
||||||
Log.v(TAG, "Writing report characteristic to enter valve mode");
|
|
||||||
reportChr.setValue(enterValveMode);
|
|
||||||
gatt.writeCharacteristic(reportChr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finishCurrentGattOperation();
|
finishCurrentGattOperation();
|
||||||
|
|
@ -548,9 +692,20 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getProductId() {
|
public int getProductId() {
|
||||||
// We don't have an easy way to query from the Bluetooth device, but we know what it is
|
if (mProductId > 0) {
|
||||||
final int D0G_BLE2_PID = 0x1106;
|
// We've already set a product ID.
|
||||||
return D0G_BLE2_PID;
|
return mProductId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mDevice.getName().startsWith("Steam Ctrl")) {
|
||||||
|
// We're a newer Triton device
|
||||||
|
mProductId = TRITON_BLE_PID;
|
||||||
|
} else {
|
||||||
|
// We're an OG Steam Controller
|
||||||
|
mProductId = D0G_BLE2_PID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mProductId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -601,10 +756,29 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||||
writeCharacteristic(reportCharacteristic, actual_report);
|
writeCharacteristic(reportCharacteristic, actual_report);
|
||||||
return report.length;
|
return report.length;
|
||||||
} else {
|
} else {
|
||||||
|
// If we're an original-recipe Steam Controller we just write to the characteristic directly.
|
||||||
|
if (getProductId() == D0G_BLE2_PID) {
|
||||||
//Log.v(TAG, "writeOutputReport " + HexDump.dumpHexString(report));
|
//Log.v(TAG, "writeOutputReport " + HexDump.dumpHexString(report));
|
||||||
writeCharacteristic(reportCharacteristic, report);
|
writeCharacteristic(reportCharacteristic, report);
|
||||||
return report.length;
|
return report.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we're a Triton, we need to find the correct report characteristic.
|
||||||
|
if (report.length > 0) {
|
||||||
|
int reportId = report[0] & 0xFF;
|
||||||
|
BluetoothGattCharacteristic targetedReportCharacteristic = mOutputReportChars.get(reportId);
|
||||||
|
if (targetedReportCharacteristic != null) {
|
||||||
|
byte[] actual_report = Arrays.copyOfRange(report, 1, report.length - 1);
|
||||||
|
//Log.v(TAG, "writeOutputReport 0x" + Integer.toString(reportId, 16) + " " + HexDump.dumpHexString(report));
|
||||||
|
writeCharacteristic(targetedReportCharacteristic.getUuid(), actual_report);
|
||||||
|
return report.length;
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Got report write request for unknown report type 0x" + Integer.toString(reportId, 16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,7 @@ public class HIDDeviceManager {
|
||||||
final int XB360W_IFACE_PROTOCOL = 129; // Wireless
|
final int XB360W_IFACE_PROTOCOL = 129; // Wireless
|
||||||
final int[] SUPPORTED_VENDORS = {
|
final int[] SUPPORTED_VENDORS = {
|
||||||
0x0079, // GPD Win 2
|
0x0079, // GPD Win 2
|
||||||
|
0x0351, // CRKD
|
||||||
0x044f, // Thrustmaster
|
0x044f, // Thrustmaster
|
||||||
0x045e, // Microsoft
|
0x045e, // Microsoft
|
||||||
0x046d, // Logitech
|
0x046d, // Logitech
|
||||||
|
|
@ -242,7 +243,9 @@ public class HIDDeviceManager {
|
||||||
0x0e6f, // PDP
|
0x0e6f, // PDP
|
||||||
0x0f0d, // Hori
|
0x0f0d, // Hori
|
||||||
0x1038, // SteelSeries
|
0x1038, // SteelSeries
|
||||||
|
0x10f5, // Turtle Beach
|
||||||
0x11c9, // Nacon
|
0x11c9, // Nacon
|
||||||
|
0x1209, // Generic
|
||||||
0x12ab, // Unknown
|
0x12ab, // Unknown
|
||||||
0x1430, // RedOctane
|
0x1430, // RedOctane
|
||||||
0x146b, // BigBen
|
0x146b, // BigBen
|
||||||
|
|
@ -256,7 +259,10 @@ public class HIDDeviceManager {
|
||||||
0x24c6, // PowerA
|
0x24c6, // PowerA
|
||||||
0x2c22, // Qanba
|
0x2c22, // Qanba
|
||||||
0x2dc8, // 8BitDo
|
0x2dc8, // 8BitDo
|
||||||
|
0x3537, // GameSir
|
||||||
|
0x3651, // CRKD
|
||||||
0x37d7, // Flydigi
|
0x37d7, // Flydigi
|
||||||
|
0x3958, // Red Octane Games
|
||||||
0x9886, // ASTRO Gaming
|
0x9886, // ASTRO Gaming
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -278,6 +284,7 @@ public class HIDDeviceManager {
|
||||||
final int XB1_IFACE_SUBCLASS = 71;
|
final int XB1_IFACE_SUBCLASS = 71;
|
||||||
final int XB1_IFACE_PROTOCOL = 208;
|
final int XB1_IFACE_PROTOCOL = 208;
|
||||||
final int[] SUPPORTED_VENDORS = {
|
final int[] SUPPORTED_VENDORS = {
|
||||||
|
0x0351, // CRKD
|
||||||
0x03f0, // HP
|
0x03f0, // HP
|
||||||
0x044f, // Thrustmaster
|
0x044f, // Thrustmaster
|
||||||
0x045e, // Microsoft
|
0x045e, // Microsoft
|
||||||
|
|
@ -286,6 +293,7 @@ public class HIDDeviceManager {
|
||||||
0x0e6f, // PDP
|
0x0e6f, // PDP
|
||||||
0x0f0d, // Hori
|
0x0f0d, // Hori
|
||||||
0x10f5, // Turtle Beach
|
0x10f5, // Turtle Beach
|
||||||
|
0x1209, // Generic
|
||||||
0x1532, // Razer Wildcat
|
0x1532, // Razer Wildcat
|
||||||
0x20d6, // PowerA
|
0x20d6, // PowerA
|
||||||
0x24c6, // PowerA
|
0x24c6, // PowerA
|
||||||
|
|
@ -295,7 +303,9 @@ public class HIDDeviceManager {
|
||||||
0x2e95, // SCUF
|
0x2e95, // SCUF
|
||||||
0x3285, // Nacon
|
0x3285, // Nacon
|
||||||
0x3537, // GameSir
|
0x3537, // GameSir
|
||||||
|
0x3651, // CRKD
|
||||||
0x366c, // ByoWave
|
0x366c, // ByoWave
|
||||||
|
0x3958, // Red Octane Games
|
||||||
};
|
};
|
||||||
|
|
||||||
if (usbInterface.getId() == 0 &&
|
if (usbInterface.getId() == 0 &&
|
||||||
|
|
@ -360,7 +370,7 @@ public class HIDDeviceManager {
|
||||||
HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_index);
|
HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_index);
|
||||||
int id = device.getId();
|
int id = device.getId();
|
||||||
mDevicesById.put(id, device);
|
mDevicesById.put(id, device);
|
||||||
HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), usbInterface.getId(), usbInterface.getInterfaceClass(), usbInterface.getInterfaceSubclass(), usbInterface.getInterfaceProtocol(), false);
|
HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), usbInterface.getId(), usbInterface.getInterfaceClass(), usbInterface.getInterfaceSubclass(), usbInterface.getInterfaceProtocol(), false, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -529,7 +539,13 @@ public class HIDDeviceManager {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bluetoothDevice.getName().equals("SteamController") && ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) != 0);
|
// Steam Controllers will always support Bluetooth Low Energy
|
||||||
|
if ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match on the name either the original Steam Controller or the new second-generation one advertise with.
|
||||||
|
return bluetoothDevice.getName().equals("SteamController") || bluetoothDevice.getName().startsWith("Steam Ctrl");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void close() {
|
private void close() {
|
||||||
|
|
@ -681,7 +697,7 @@ public class HIDDeviceManager {
|
||||||
private native void HIDDeviceRegisterCallback();
|
private native void HIDDeviceRegisterCallback();
|
||||||
private native void HIDDeviceReleaseCallback();
|
private native void HIDDeviceReleaseCallback();
|
||||||
|
|
||||||
native void HIDDeviceConnected(int deviceID, String identifier, int vendorId, int productId, String serial_number, int release_number, String manufacturer_string, String product_string, int interface_number, int interface_class, int interface_subclass, int interface_protocol, boolean bBluetooth);
|
native void HIDDeviceConnected(int deviceID, String identifier, int vendorId, int productId, String serial_number, int release_number, String manufacturer_string, String product_string, int interface_number, int interface_class, int interface_subclass, int interface_protocol, boolean bBluetooth, int reportID);
|
||||||
native void HIDDeviceOpenPending(int deviceID);
|
native void HIDDeviceOpenPending(int deviceID);
|
||||||
native void HIDDeviceOpenResult(int deviceID, boolean opened);
|
native void HIDDeviceOpenResult(int deviceID, boolean opened);
|
||||||
native void HIDDeviceDisconnected(int deviceID);
|
native void HIDDeviceDisconnected(int deviceID);
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ class HIDDeviceUSB implements HIDDevice {
|
||||||
protected InputThread mInputThread;
|
protected InputThread mInputThread;
|
||||||
protected boolean mRunning;
|
protected boolean mRunning;
|
||||||
protected boolean mFrozen;
|
protected boolean mFrozen;
|
||||||
|
protected boolean mClaimed;
|
||||||
|
|
||||||
public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_index) {
|
public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_index) {
|
||||||
mManager = manager;
|
mManager = manager;
|
||||||
|
|
@ -29,6 +30,7 @@ class HIDDeviceUSB implements HIDDevice {
|
||||||
mInterface = mDevice.getInterface(mInterfaceIndex).getId();
|
mInterface = mDevice.getInterface(mInterfaceIndex).getId();
|
||||||
mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier());
|
mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier());
|
||||||
mRunning = false;
|
mRunning = false;
|
||||||
|
mClaimed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getIdentifier() {
|
String getIdentifier() {
|
||||||
|
|
@ -56,7 +58,7 @@ class HIDDeviceUSB implements HIDDevice {
|
||||||
try {
|
try {
|
||||||
result = mDevice.getSerialNumber();
|
result = mDevice.getSerialNumber();
|
||||||
}
|
}
|
||||||
catch (SecurityException exception) {
|
catch (Exception exception) {
|
||||||
//Log.w(TAG, "App permissions mean we cannot get serial number for device " + getDeviceName() + " message: " + exception.getMessage());
|
//Log.w(TAG, "App permissions mean we cannot get serial number for device " + getDeviceName() + " message: " + exception.getMessage());
|
||||||
}
|
}
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
|
|
@ -114,6 +116,7 @@ class HIDDeviceUSB implements HIDDevice {
|
||||||
close();
|
close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
mClaimed = true;
|
||||||
|
|
||||||
// Find the endpoints
|
// Find the endpoints
|
||||||
for (int j = 0; j < iface.getEndpointCount(); j++) {
|
for (int j = 0; j < iface.getEndpointCount(); j++) {
|
||||||
|
|
@ -132,9 +135,12 @@ class HIDDeviceUSB implements HIDDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the required endpoints were present
|
// Make sure the required endpoints were present. The original Steam Controller and the wireless dongle for it do NOT
|
||||||
if (mInputEndpoint == null || mOutputEndpoint == null) {
|
// actually have -- or require -- output endpoints, so we need to accept only an input one for them or else we'll fall
|
||||||
|
// back to the Android system gamepad functionality (and lose our paddles et al).
|
||||||
|
if (mInputEndpoint == null) {
|
||||||
Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName());
|
Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName());
|
||||||
|
mConnection.releaseInterface(iface);
|
||||||
close();
|
close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -154,6 +160,11 @@ class HIDDeviceUSB implements HIDDevice {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mClaimed) {
|
||||||
|
Log.w(TAG, "writeReport() called but some other process currently owns the USB device");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (feature) {
|
if (feature) {
|
||||||
int res = -1;
|
int res = -1;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
@ -185,6 +196,11 @@ class HIDDeviceUSB implements HIDDevice {
|
||||||
}
|
}
|
||||||
return length;
|
return length;
|
||||||
} else {
|
} else {
|
||||||
|
if (mOutputEndpoint == null)
|
||||||
|
{
|
||||||
|
Log.e(TAG, "Tried to write an output report to an interface with no output endpoint!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
int res = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000);
|
int res = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000);
|
||||||
if (res != report.length) {
|
if (res != report.length) {
|
||||||
Log.w(TAG, "writeOutputReport() returned " + res + " on device " + getDeviceName());
|
Log.w(TAG, "writeOutputReport() returned " + res + " on device " + getDeviceName());
|
||||||
|
|
@ -205,6 +221,12 @@ class HIDDeviceUSB implements HIDDevice {
|
||||||
Log.w(TAG, "readReport() called with no device connection");
|
Log.w(TAG, "readReport() called with no device connection");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!mClaimed) {
|
||||||
|
if (feature) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (report_number == 0x0) {
|
if (report_number == 0x0) {
|
||||||
/* Offset the return buffer by 1, so that the report ID
|
/* Offset the return buffer by 1, so that the report ID
|
||||||
|
|
@ -258,10 +280,13 @@ class HIDDeviceUSB implements HIDDevice {
|
||||||
mInputThread = null;
|
mInputThread = null;
|
||||||
}
|
}
|
||||||
if (mConnection != null) {
|
if (mConnection != null) {
|
||||||
|
if (mClaimed) {
|
||||||
UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
|
UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
|
||||||
mConnection.releaseInterface(iface);
|
mConnection.releaseInterface(iface);
|
||||||
|
}
|
||||||
mConnection.close();
|
mConnection.close();
|
||||||
mConnection = null;
|
mConnection = null;
|
||||||
|
mClaimed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -274,6 +299,22 @@ class HIDDeviceUSB implements HIDDevice {
|
||||||
@Override
|
@Override
|
||||||
public void setFrozen(boolean frozen) {
|
public void setFrozen(boolean frozen) {
|
||||||
mFrozen = frozen;
|
mFrozen = frozen;
|
||||||
|
|
||||||
|
/* If we have a valid device connection and the claim state doesn't match what we want, try to correct that. */
|
||||||
|
if (mConnection != null && mClaimed == mFrozen) {
|
||||||
|
UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
|
||||||
|
if (frozen) {
|
||||||
|
mClaimed = !mConnection.releaseInterface(iface);
|
||||||
|
if (mClaimed) {
|
||||||
|
Log.e(TAG, "Tried to release claim on USB device, but failed!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mClaimed = mConnection.claimInterface(iface, true);
|
||||||
|
if (!mClaimed) {
|
||||||
|
Log.e(TAG, "Tried to regain claim on USB device, but failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class InputThread extends Thread {
|
protected class InputThread extends Thread {
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ public abstract class SDLActivity extends Activity implements View.OnSystemUiVis
|
||||||
private static final String TAG = "SDL";
|
private static final String TAG = "SDL";
|
||||||
private static final int SDL_MAJOR_VERSION = 3;
|
private static final int SDL_MAJOR_VERSION = 3;
|
||||||
private static final int SDL_MINOR_VERSION = 4;
|
private static final int SDL_MINOR_VERSION = 4;
|
||||||
private static final int SDL_MICRO_VERSION = 8;
|
private static final int SDL_MICRO_VERSION = 16;
|
||||||
/*
|
/*
|
||||||
// Display InputType.SOURCE/CLASS of events and devices
|
// Display InputType.SOURCE/CLASS of events and devices
|
||||||
//
|
//
|
||||||
|
|
@ -535,6 +535,7 @@ public abstract class SDLActivity extends Activity implements View.OnSystemUiVis
|
||||||
if (mHIDDeviceManager != null) {
|
if (mHIDDeviceManager != null) {
|
||||||
mHIDDeviceManager.setFrozen(true);
|
mHIDDeviceManager.setFrozen(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mHasMultiWindow) {
|
if (!mHasMultiWindow) {
|
||||||
pauseNativeThread();
|
pauseNativeThread();
|
||||||
}
|
}
|
||||||
|
|
@ -548,6 +549,7 @@ public abstract class SDLActivity extends Activity implements View.OnSystemUiVis
|
||||||
if (mHIDDeviceManager != null) {
|
if (mHIDDeviceManager != null) {
|
||||||
mHIDDeviceManager.setFrozen(false);
|
mHIDDeviceManager.setFrozen(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mHasMultiWindow) {
|
if (!mHasMultiWindow) {
|
||||||
resumeNativeThread();
|
resumeNativeThread();
|
||||||
}
|
}
|
||||||
|
|
@ -620,6 +622,14 @@ public abstract class SDLActivity extends Activity implements View.OnSystemUiVis
|
||||||
super.onWindowFocusChanged(hasFocus);
|
super.onWindowFocusChanged(hasFocus);
|
||||||
Log.v(TAG, "onWindowFocusChanged(): " + hasFocus);
|
Log.v(TAG, "onWindowFocusChanged(): " + hasFocus);
|
||||||
|
|
||||||
|
// If we are gaining focus, we can always try to restore our USB devices. If we are losing focus,
|
||||||
|
// only try to relinquish them if we don't have background events allowed (for multi-window Android setups).
|
||||||
|
if (hasFocus || !SDLActivity.nativeGetHintBoolean("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS", false)) {
|
||||||
|
if (mHIDDeviceManager != null) {
|
||||||
|
mHIDDeviceManager.setFrozen(!hasFocus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (SDLActivity.mBrokenLibraries) {
|
if (SDLActivity.mBrokenLibraries) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1485,11 +1495,11 @@ public abstract class SDLActivity extends Activity implements View.OnSystemUiVis
|
||||||
if (SDLControllerManager.isDeviceSDLJoystick(deviceId)) {
|
if (SDLControllerManager.isDeviceSDLJoystick(deviceId)) {
|
||||||
// Note that we process events with specific key codes here
|
// Note that we process events with specific key codes here
|
||||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
if (SDLControllerManager.onNativePadDown(deviceId, keyCode)) {
|
if (SDLControllerManager.onNativePadDown(deviceId, keyCode, event.getScanCode())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||||
if (SDLControllerManager.onNativePadUp(deviceId, keyCode)) {
|
if (SDLControllerManager.onNativePadUp(deviceId, keyCode, event.getScanCode())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,10 @@ import android.hardware.lights.Light;
|
||||||
import android.hardware.lights.LightsRequest;
|
import android.hardware.lights.LightsRequest;
|
||||||
import android.hardware.lights.LightsManager;
|
import android.hardware.lights.LightsManager;
|
||||||
import android.hardware.lights.LightState;
|
import android.hardware.lights.LightState;
|
||||||
|
import android.hardware.Sensor;
|
||||||
|
import android.hardware.SensorEvent;
|
||||||
|
import android.hardware.SensorEventListener;
|
||||||
|
import android.hardware.SensorManager;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.VibrationEffect;
|
import android.os.VibrationEffect;
|
||||||
|
|
@ -30,16 +34,18 @@ public class SDLControllerManager
|
||||||
static native void nativeAddJoystick(int device_id, String name, String desc,
|
static native void nativeAddJoystick(int device_id, String name, String desc,
|
||||||
int vendor_id, int product_id,
|
int vendor_id, int product_id,
|
||||||
int button_mask,
|
int button_mask,
|
||||||
int naxes, int axis_mask, int nhats, boolean can_rumble, boolean has_rgb_led);
|
int naxes, int axis_mask, int nhats, boolean can_rumble, boolean has_rgb_led,
|
||||||
|
boolean has_accelerometer, boolean has_gyroscope);
|
||||||
static native void nativeRemoveJoystick(int device_id);
|
static native void nativeRemoveJoystick(int device_id);
|
||||||
static native void nativeAddHaptic(int device_id, String name);
|
static native void nativeAddHaptic(int device_id, String name);
|
||||||
static native void nativeRemoveHaptic(int device_id);
|
static native void nativeRemoveHaptic(int device_id);
|
||||||
static public native boolean onNativePadDown(int device_id, int keycode);
|
static public native boolean onNativePadDown(int device_id, int keycode, int scancode);
|
||||||
static public native boolean onNativePadUp(int device_id, int keycode);
|
static public native boolean onNativePadUp(int device_id, int keycode, int scancode);
|
||||||
static native void onNativeJoy(int device_id, int axis,
|
static native void onNativeJoy(int device_id, int axis,
|
||||||
float value);
|
float value);
|
||||||
static native void onNativeHat(int device_id, int hat_id,
|
static native void onNativeHat(int device_id, int hat_id,
|
||||||
int x, int y);
|
int x, int y);
|
||||||
|
static native void onNativeJoySensor(int device_id, int sensor_type, long sensor_timestamp, float x, float y, float z);
|
||||||
|
|
||||||
protected static SDLJoystickHandler mJoystickHandler;
|
protected static SDLJoystickHandler mJoystickHandler;
|
||||||
protected static SDLHapticHandler mHapticHandler;
|
protected static SDLHapticHandler mHapticHandler;
|
||||||
|
|
@ -81,6 +87,13 @@ public class SDLControllerManager
|
||||||
mJoystickHandler.setLED(device_id, red, green, blue);
|
mJoystickHandler.setLED(device_id, red, green, blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called by SDL using JNI.
|
||||||
|
*/
|
||||||
|
static void joystickSetSensorsEnabled(int device_id, boolean enabled) {
|
||||||
|
mJoystickHandler.setSensorsEnabled(device_id, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called by SDL using JNI.
|
* This method is called by SDL using JNI.
|
||||||
*/
|
*/
|
||||||
|
|
@ -153,6 +166,10 @@ class SDLJoystickHandler {
|
||||||
ArrayList<InputDevice.MotionRange> hats;
|
ArrayList<InputDevice.MotionRange> hats;
|
||||||
ArrayList<Light> lights;
|
ArrayList<Light> lights;
|
||||||
LightsManager.LightsSession lightsSession;
|
LightsManager.LightsSession lightsSession;
|
||||||
|
SensorManager sensorManager;
|
||||||
|
SDLJoySensorListener sensorListener;
|
||||||
|
Sensor accelerometerSensor;
|
||||||
|
Sensor gyroscopeSensor;
|
||||||
}
|
}
|
||||||
static class RangeComparator implements Comparator<InputDevice.MotionRange> {
|
static class RangeComparator implements Comparator<InputDevice.MotionRange> {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -225,12 +242,13 @@ class SDLJoystickHandler {
|
||||||
joystick.desc = getJoystickDescriptor(joystickDevice);
|
joystick.desc = getJoystickDescriptor(joystickDevice);
|
||||||
joystick.axes = new ArrayList<InputDevice.MotionRange>();
|
joystick.axes = new ArrayList<InputDevice.MotionRange>();
|
||||||
joystick.hats = new ArrayList<InputDevice.MotionRange>();
|
joystick.hats = new ArrayList<InputDevice.MotionRange>();
|
||||||
|
java.util.Set<Integer> axisStrsSet = new java.util.HashSet<Integer>();
|
||||||
joystick.lights = new ArrayList<Light>();
|
joystick.lights = new ArrayList<Light>();
|
||||||
|
|
||||||
List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
|
List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
|
||||||
Collections.sort(ranges, new RangeComparator());
|
Collections.sort(ranges, new RangeComparator());
|
||||||
for (InputDevice.MotionRange range : ranges) {
|
for (InputDevice.MotionRange range : ranges) {
|
||||||
if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
|
if (((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) && axisStrsSet.add(range.getAxis())) {
|
||||||
if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) {
|
if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) {
|
||||||
joystick.hats.add(range);
|
joystick.hats.add(range);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -241,6 +259,8 @@ class SDLJoystickHandler {
|
||||||
|
|
||||||
boolean can_rumble = false;
|
boolean can_rumble = false;
|
||||||
boolean has_rgb_led = false;
|
boolean has_rgb_led = false;
|
||||||
|
boolean has_accelerometer = false;
|
||||||
|
boolean has_gyroscope = false;
|
||||||
if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
|
if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
|
||||||
VibratorManager vibratorManager = joystickDevice.getVibratorManager();
|
VibratorManager vibratorManager = joystickDevice.getVibratorManager();
|
||||||
int[] vibrators = vibratorManager.getVibratorIds();
|
int[] vibrators = vibratorManager.getVibratorIds();
|
||||||
|
|
@ -258,12 +278,26 @@ class SDLJoystickHandler {
|
||||||
joystick.lightsSession = lightsManager.openSession();
|
joystick.lightsSession = lightsManager.openSession();
|
||||||
has_rgb_led = true;
|
has_rgb_led = true;
|
||||||
}
|
}
|
||||||
|
SensorManager sensorManager = joystickDevice.getSensorManager();
|
||||||
|
if (sensorManager != null) {
|
||||||
|
joystick.sensorManager = sensorManager;
|
||||||
|
joystick.sensorListener = new SDLJoySensorListener(joystick.device_id);
|
||||||
|
joystick.accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||||
|
if (joystick.accelerometerSensor != null) {
|
||||||
|
has_accelerometer = true;
|
||||||
|
}
|
||||||
|
joystick.gyroscopeSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
|
||||||
|
if (joystick.gyroscopeSensor != null) {
|
||||||
|
has_gyroscope = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mJoysticks.add(joystick);
|
mJoysticks.add(joystick);
|
||||||
SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc,
|
SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc,
|
||||||
getVendorId(joystickDevice), getProductId(joystickDevice),
|
getVendorId(joystickDevice), getProductId(joystickDevice),
|
||||||
getButtonMask(joystickDevice), joystick.axes.size(), getAxisMask(joystick.axes), joystick.hats.size()/2, can_rumble, has_rgb_led);
|
getButtonMask(joystickDevice), joystick.axes.size(), getAxisMask(joystick.axes), joystick.hats.size()/2, can_rumble, has_rgb_led,
|
||||||
|
has_accelerometer, has_gyroscope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -508,6 +542,31 @@ class SDLJoystickHandler {
|
||||||
}
|
}
|
||||||
joystick.lightsSession.requestLights(lightsRequest.build());
|
joystick.lightsSession.requestLights(lightsRequest.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setSensorsEnabled(int device_id, boolean enabled) {
|
||||||
|
if (Build.VERSION.SDK_INT < 31 /* Android 12.0 (S) */) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SDLJoystick joystick = getJoystick(device_id);
|
||||||
|
if (joystick == null || joystick.sensorManager == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (enabled) {
|
||||||
|
if (joystick.accelerometerSensor != null) {
|
||||||
|
SDLSensorManager.registerListener(joystick.sensorManager, joystick.sensorListener, joystick.accelerometerSensor, SensorManager.SENSOR_DELAY_GAME);
|
||||||
|
}
|
||||||
|
if (joystick.gyroscopeSensor != null) {
|
||||||
|
SDLSensorManager.registerListener(joystick.sensorManager, joystick.sensorListener, joystick.gyroscopeSensor, SensorManager.SENSOR_DELAY_GAME);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (joystick.accelerometerSensor != null) {
|
||||||
|
SDLSensorManager.unregisterListener(joystick.sensorManager, joystick.sensorListener, joystick.accelerometerSensor);
|
||||||
|
}
|
||||||
|
if (joystick.gyroscopeSensor != null) {
|
||||||
|
SDLSensorManager.unregisterListener(joystick.sensorManager, joystick.sensorListener, joystick.gyroscopeSensor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SDLHapticHandler_API31 extends SDLHapticHandler {
|
class SDLHapticHandler_API31 extends SDLHapticHandler {
|
||||||
|
|
@ -933,3 +992,19 @@ class SDLGenericMotionListener_API29 extends SDLGenericMotionListener_API26 {
|
||||||
return penDevice.isExternal() ? SDL_PEN_DEVICE_TYPE_INDIRECT : SDL_PEN_DEVICE_TYPE_DIRECT;
|
return penDevice.isExternal() ? SDL_PEN_DEVICE_TYPE_INDIRECT : SDL_PEN_DEVICE_TYPE_DIRECT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SDLJoySensorListener implements SensorEventListener {
|
||||||
|
int device_id;
|
||||||
|
|
||||||
|
public SDLJoySensorListener(int device_id) {
|
||||||
|
this.device_id = device_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSensorChanged(SensorEvent event) {
|
||||||
|
SDLControllerManager.onNativeJoySensor(device_id, event.sensor.getType(), event.timestamp, event.values[0], event.values[1], event.values[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
package org.libsdl.app;
|
||||||
|
|
||||||
|
import android.hardware.Sensor;
|
||||||
|
import android.hardware.SensorEventListener;
|
||||||
|
import android.hardware.SensorManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
// This class coordinates synchronized access to sensor manager registration
|
||||||
|
//
|
||||||
|
// This prevents a java.util.ConcurrentModificationException exception on
|
||||||
|
// Android 16, specifically on the Samsung Tab S9 Ultra.
|
||||||
|
|
||||||
|
class SDLSensorManager
|
||||||
|
{
|
||||||
|
static private SDLSensorManager mManager = new SDLSensorManager();
|
||||||
|
|
||||||
|
static final int RETRY_COUNT = 3;
|
||||||
|
|
||||||
|
public static void registerListener(SensorManager manager, SensorEventListener listener, Sensor sensor, int samplingPeriodUs) {
|
||||||
|
mManager.RegisterListener(manager, listener, sensor, samplingPeriodUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unregisterListener(SensorManager manager, SensorEventListener listener, Sensor sensor) {
|
||||||
|
mManager.UnregisterListener(manager, listener, sensor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void RegisterListener(SensorManager manager, SensorEventListener listener, Sensor sensor, int samplingPeriodUs) {
|
||||||
|
int retries = 0;
|
||||||
|
boolean complete = false;
|
||||||
|
while (!complete) {
|
||||||
|
try {
|
||||||
|
manager.registerListener(listener, sensor, samplingPeriodUs, null);
|
||||||
|
complete = true;
|
||||||
|
} catch (java.util.ConcurrentModificationException e) {
|
||||||
|
++retries;
|
||||||
|
if (retries <= RETRY_COUNT) {
|
||||||
|
// Sleep a bit and try again
|
||||||
|
try {
|
||||||
|
Thread.sleep(1);
|
||||||
|
} catch (Exception e2) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.v("SDL", "Multiple ConcurrentModificationException caught while registering sensor listener, canceling operation");
|
||||||
|
complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void UnregisterListener(SensorManager manager, SensorEventListener listener, Sensor sensor) {
|
||||||
|
int retries = 0;
|
||||||
|
boolean complete = false;
|
||||||
|
while (!complete) {
|
||||||
|
try {
|
||||||
|
manager.unregisterListener(listener, sensor);
|
||||||
|
complete = true;
|
||||||
|
} catch (java.util.ConcurrentModificationException e) {
|
||||||
|
++retries;
|
||||||
|
if (retries <= RETRY_COUNT) {
|
||||||
|
// Sleep a bit and try again
|
||||||
|
try {
|
||||||
|
Thread.sleep(1);
|
||||||
|
} catch (Exception e2) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.v("SDL", "Multiple ConcurrentModificationException caught while unregistering sensor listener, canceling operation");
|
||||||
|
complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -328,11 +328,11 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||||
protected void enableSensor(int sensortype, boolean enabled) {
|
protected void enableSensor(int sensortype, boolean enabled) {
|
||||||
// TODO: This uses getDefaultSensor - what if we have >1 accels?
|
// TODO: This uses getDefaultSensor - what if we have >1 accels?
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
mSensorManager.registerListener(this,
|
SDLSensorManager.registerListener(mSensorManager, this,
|
||||||
mSensorManager.getDefaultSensor(sensortype),
|
mSensorManager.getDefaultSensor(sensortype),
|
||||||
SensorManager.SENSOR_DELAY_GAME, null);
|
SensorManager.SENSOR_DELAY_GAME);
|
||||||
} else {
|
} else {
|
||||||
mSensorManager.unregisterListener(this,
|
SDLSensorManager.unregisterListener(mSensorManager, this,
|
||||||
mSensorManager.getDefaultSensor(sensortype));
|
mSensorManager.getDefaultSensor(sensortype));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -402,45 +402,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||||
@Override
|
@Override
|
||||||
public boolean onCapturedPointerEvent(MotionEvent event)
|
public boolean onCapturedPointerEvent(MotionEvent event)
|
||||||
{
|
{
|
||||||
int action = event.getActionMasked();
|
return SDLActivity.getMotionListener().onGenericMotion(this, event);
|
||||||
int pointerCount = event.getPointerCount();
|
|
||||||
|
|
||||||
for (int i = 0; i < pointerCount; i++) {
|
|
||||||
float x, y;
|
|
||||||
switch (action) {
|
|
||||||
case MotionEvent.ACTION_SCROLL:
|
|
||||||
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, i);
|
|
||||||
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, i);
|
|
||||||
SDLActivity.onNativeMouse(0, action, x, y, false);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MotionEvent.ACTION_HOVER_MOVE:
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
|
||||||
x = event.getX(i);
|
|
||||||
y = event.getY(i);
|
|
||||||
SDLActivity.onNativeMouse(0, action, x, y, true);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MotionEvent.ACTION_BUTTON_PRESS:
|
|
||||||
case MotionEvent.ACTION_BUTTON_RELEASE:
|
|
||||||
|
|
||||||
// Change our action value to what SDL's code expects.
|
|
||||||
if (action == MotionEvent.ACTION_BUTTON_PRESS) {
|
|
||||||
action = MotionEvent.ACTION_DOWN;
|
|
||||||
} else { /* MotionEvent.ACTION_BUTTON_RELEASE */
|
|
||||||
action = MotionEvent.ACTION_UP;
|
|
||||||
}
|
|
||||||
|
|
||||||
x = event.getX(i);
|
|
||||||
y = event.getY(i);
|
|
||||||
int button = event.getButtonState();
|
|
||||||
|
|
||||||
SDLActivity.onNativeMouse(button, action, x, y, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
conan export %0/../conan-skia/recipes/skia/all/conanfile.py --version=143.20251028.0
|
conan export %0/../conan-skia/recipes/skia/all/conanfile.py --version=143.20251028.0
|
||||||
conan export %0/../conan-skia/recipes/emsdk/all/conanfile.py --version=4.0.22
|
conan export %0/../conan-skia/recipes/emsdk/all/conanfile.py --version=4.0.22
|
||||||
conan export %0/../icu/all/conanfile.py --version=77.1
|
conan export %0/../icu/all/conanfile.py --version=77.1
|
||||||
conan export %0/../sdl/3.x/conanfile.py --version=3.4.8
|
conan export %0/../sdl/3.x/conanfile.py --version=3.4.16
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,6 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
conan export "$(dirname "$0")/conan-skia/recipes/skia/all/conanfile.py" --version=143.20251028.0
|
conan export "$(dirname "$0")/conan-skia/recipes/skia/all/conanfile.py" --version=143.20251028.0
|
||||||
conan export "$(dirname "$0")/emsdk/all/conanfile.py" --version=4.0.22
|
conan export "$(dirname "$0")/emsdk/all/conanfile.py" --version=4.0.22
|
||||||
conan export "$(dirname "$0")/icu/all/conanfile.py" --version=77.1
|
conan export "$(dirname "$0")/icu/all/conanfile.py" --version=77.1
|
||||||
conan export "$(dirname "$0")/sdl/3.x/conanfile.py" --version=3.4.8
|
conan export "$(dirname "$0")/sdl/3.x/conanfile.py" --version=3.4.16
|
||||||
#conan create . -o use_system_expat=False -o use_system_freetype=False -o use_system_harfbuzz=False -o use_system_icu=False -o use_system_libjpeg_turbo=False -o use_system_libpng=False -o use_system_libwebp=False -o use_system_zlib=False --build=missing --version=134.20250327.0
|
#conan create . -o use_system_expat=False -o use_system_freetype=False -o use_system_harfbuzz=False -o use_system_icu=False -o use_system_libjpeg_turbo=False -o use_system_libpng=False -o use_system_libwebp=False -o use_system_zlib=False --build=missing --version=134.20250327.0
|
||||||
#cd ../../../..
|
#cd ../../../..
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
sources:
|
sources:
|
||||||
"3.4.8":
|
"3.4.16":
|
||||||
url: "https://github.com/libsdl-org/SDL/releases/download/release-3.4.8/SDL3-3.4.8.tar.gz"
|
url: "https://github.com/libsdl-org/SDL/releases/download/release-3.4.16/SDL3-3.4.16.tar.gz"
|
||||||
sha256: "e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba"
|
sha256: "7322236cd12090c3eb40b9728be4d49c76f66ad17d04369584d4ecad5cf77c68"
|
||||||
|
|
|
||||||
|
|
@ -111,11 +111,11 @@ class CompressorRecipe(ConanFile):
|
||||||
self.requires("fontconfig/2.17.1")
|
self.requires("fontconfig/2.17.1")
|
||||||
self.requires("egl/system")
|
self.requires("egl/system")
|
||||||
elif self.settings.os == "Emscripten":
|
elif self.settings.os == "Emscripten":
|
||||||
self.requires("sdl-infinipaint/3.4.8", options = {
|
self.requires("sdl-infinipaint/3.4.16", options = {
|
||||||
"emscriptenPersistentPath": "/infinipaint"
|
"emscriptenPersistentPath": "/infinipaint"
|
||||||
})
|
})
|
||||||
elif self.settings.os != "Android":
|
elif self.settings.os != "Android":
|
||||||
self.requires("sdl-infinipaint/3.4.8")
|
self.requires("sdl-infinipaint/3.4.16")
|
||||||
|
|
||||||
if self.settings.os != "Emscripten" and self.settings.os != "Macos" and self.settings.os != "Android":
|
if self.settings.os != "Emscripten" and self.settings.os != "Macos" and self.settings.os != "Android":
|
||||||
self.requires("hwloc/2.12.2", options = {
|
self.requires("hwloc/2.12.2", options = {
|
||||||
|
|
|
||||||
2
deps/SDL
vendored
2
deps/SDL
vendored
|
|
@ -1 +1 @@
|
||||||
Subproject commit d9d5536704d585616d4db3c8ba3c4ff6fc2757e1
|
Subproject commit fa2c02bb6e21974a89ea9824bc53c9932abe5f9c
|
||||||
Loading…
Add table
Add a link
Reference in a new issue