Skip to content

Commit 7ecffcb

Browse files
committed
feat: Add support of Xbox Wireless Adapter
Driver codes mainly from https://github.com/medusalix/xow Signed-off-by: Hakusai Zhang <[email protected]>
1 parent f10085f commit 7ecffcb

File tree

25 files changed

+9269
-2
lines changed

25 files changed

+9269
-2
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "app/src/main/jni/moonlight-core/moonlight-common-c"]
22
path = app/src/main/jni/moonlight-core/moonlight-common-c
33
url = https://github.com/moonlight-stream/moonlight-common-c.git
4+
[submodule "app/src/main/jni/libusb"]
5+
path = app/src/main/jni/libusb
6+
url = https://github.com/libusb/libusb.git

app/proguard-rules.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
# Moonlight common
88
-keep class com.limelight.nvstream.jni.* {*;}
9+
-keep class com.limelight.binding.input.driver.* {*;}
910

1011
# Okio
1112
-keep class sun.misc.Unsafe {*;}

app/src/main/java/com/limelight/binding/input/driver/UsbDriverService.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public class UsbDriverService extends Service implements UsbDriverListener {
4242
private UsbDriverStateListener stateListener;
4343
private int nextDeviceId;
4444

45+
private final ArrayList<XboxWirelessDongle> xboxWirelessDongles = new ArrayList<>();
46+
4547
@Override
4648
public void reportControllerState(int controllerId, int buttonFlags, float leftStickX, float leftStickY,
4749
float rightStickX, float rightStickY, float leftTrigger, float rightTrigger) {
@@ -182,6 +184,15 @@ private void handleUsbDeviceState(UsbDevice device) {
182184
return;
183185
}
184186

187+
if (XboxWirelessDongle.canClaimDevice(device)) {
188+
var dongle = new XboxWirelessDongle(device, connection, this);
189+
if(!dongle.start()) {
190+
connection.close();
191+
return;
192+
}
193+
xboxWirelessDongles.add(dongle);
194+
return;
195+
}
185196

186197
AbstractController controller;
187198

@@ -278,7 +289,8 @@ public static boolean shouldClaimDevice(UsbDevice device, boolean claimAllAvaila
278289
return ((!kernelSupportsXboxOne() || !isRecognizedInputDevice(device) || claimAllAvailable) && XboxOneController.canClaimDevice(device)) ||
279290
((!isRecognizedInputDevice(device) || claimAllAvailable) && Xbox360Controller.canClaimDevice(device)) ||
280291
// We must not call isRecognizedInputDevice() because wireless controllers don't share the same product ID as the dongle
281-
((!kernelSupportsXbox360W() || claimAllAvailable) && Xbox360WirelessDongle.canClaimDevice(device));
292+
((!kernelSupportsXbox360W() || claimAllAvailable) && Xbox360WirelessDongle.canClaimDevice(device) ||
293+
XboxWirelessDongle.canClaimDevice(device));
282294
}
283295

284296
@SuppressLint("UnspecifiedRegisterReceiverFlag")
@@ -319,6 +331,12 @@ private void stop() {
319331
// Stop the attachment receiver
320332
unregisterReceiver(receiver);
321333

334+
// Stop all dongles
335+
while (xboxWirelessDongles.size() > 0) {
336+
// Stop and remove the dongle
337+
xboxWirelessDongles.remove(0).stop();
338+
}
339+
322340
// Stop all controllers
323341
while (controllers.size() > 0) {
324342
// Stop and remove the controller
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.limelight.binding.input.driver;
2+
3+
public class XboxWirelessController extends AbstractController{
4+
static {
5+
System.loadLibrary("xow-driver");
6+
}
7+
8+
private final long handle;
9+
10+
public XboxWirelessController(int deviceId, UsbDriverListener listener, int vendorId, int productId, long handle) {
11+
super(deviceId, listener, vendorId, productId);
12+
this.handle = handle;
13+
registerNative(this.handle);
14+
}
15+
16+
@Override
17+
public boolean start() {
18+
// do nothing since mt driver will handle it.
19+
return true;
20+
}
21+
22+
@Override
23+
public void stop() {
24+
// do nothing since mt driver will handle it.
25+
}
26+
27+
@Override
28+
public void rumble(short lowFreqMotor, short highFreqMotor) {
29+
sendRumble(handle, lowFreqMotor, highFreqMotor);
30+
}
31+
32+
@Override
33+
public void rumbleTriggers(short leftTrigger, short rightTrigger) {
34+
sendrumbleTriggers(handle, leftTrigger, rightTrigger);
35+
}
36+
37+
public void updateInput(int buttons,short triggerLeft, short triggerRight,
38+
short stickLeftX, short stickLeftY,
39+
short stickRightX, short stickRightY) {
40+
buttonFlags = buttons;
41+
leftTrigger = triggerLeft / 1023.0f;
42+
rightTrigger = triggerRight / 1023.0f;
43+
leftStickX = stickLeftX / 32767.0f;
44+
leftStickY = stickLeftY / -32767.0f;
45+
rightStickX = stickRightX / 32767.0f;
46+
rightStickY = stickRightY / -32767.0f;
47+
48+
reportInput();
49+
}
50+
51+
native void registerNative(long handle);
52+
native void sendRumble(long handle, short lowFreqMotor, short highFreqMotor);
53+
native void sendrumbleTriggers(long handle, short leftTrigger, short rightTrigger);
54+
55+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package com.limelight.binding.input.driver;
2+
3+
import android.hardware.usb.UsbConstants;
4+
import android.hardware.usb.UsbDevice;
5+
import android.hardware.usb.UsbDeviceConnection;
6+
import android.util.Pair;
7+
8+
import com.limelight.LimeLog;
9+
import com.limelight.binding.input.driver.UsbDriverListener;
10+
11+
import java.util.HashMap;
12+
import java.util.Map;
13+
14+
public class XboxWirelessDongle {
15+
private UsbDriverListener listener;
16+
protected final UsbDevice device;
17+
protected final UsbDeviceConnection connection;
18+
19+
private long driverHandle;
20+
21+
private Map<Integer, AbstractController> controllers = new HashMap<>();
22+
23+
static {
24+
System.loadLibrary("xow-driver");
25+
}
26+
27+
public XboxWirelessDongle(UsbDevice device, UsbDeviceConnection connection, UsbDriverListener listener) {
28+
this.device = device;
29+
this.connection = connection;
30+
this.listener = listener;
31+
this.driverHandle = -1;
32+
}
33+
34+
public boolean start() {
35+
if(this.driverHandle != -1) {
36+
return false; //we already started;
37+
}
38+
this.driverHandle = createDriver(connection.getFileDescriptor());
39+
boolean ok = startDriver(this.driverHandle, "");
40+
if(!ok) {
41+
LimeLog.info("xbox wireless dongle driver failed to start");
42+
destroyDriver(this.driverHandle);
43+
this.driverHandle = -1;
44+
return false;
45+
}
46+
return true;
47+
}
48+
49+
public void stop() {
50+
if(this.driverHandle == -1) {
51+
return; //we already cleaned;
52+
}
53+
stopDriver(this.driverHandle);
54+
destroyDriver(this.driverHandle);
55+
for(var i: controllers.keySet()) {
56+
this.listener.deviceRemoved(controllers.remove(i));
57+
}
58+
}
59+
60+
public static boolean canClaimDevice(UsbDevice device) {
61+
if (device.getVendorId() != 0x045e) {
62+
return false;
63+
}
64+
if (device.getProductId() != 0x02e6 && // Older one
65+
device.getProductId() != 0x02fe // new one
66+
) {
67+
return false;
68+
}
69+
70+
return true;
71+
}
72+
73+
public void addNewController(int id, long handle, short vid, short pid){
74+
var controller = new XboxWirelessController(id + 0x045e0000, listener, vid, pid, handle);
75+
controllers.put(id, controller);
76+
this.listener.deviceAdded(controller);
77+
}
78+
79+
public void removeController(int id) {
80+
var controller = controllers.get(id);
81+
if(controller == null) {
82+
return;
83+
}
84+
controllers.remove(id);
85+
this.listener.deviceRemoved(controller);
86+
}
87+
88+
private native long createDriver(int fd);
89+
private native boolean startDriver(long handle, String fwPath);
90+
private native void stopDriver(long handle);
91+
private native void destroyDriver(long handle);
92+
}

app/src/main/jni/Android.mk

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1-
include $(call all-subdir-makefiles)
1+
LOCAL_PATH := $(call my-dir)
2+
SUB_PROJECTS := $(call all-subdir-makefiles)
3+
4+
include $(LOCAL_PATH)/libusb/android/jni/libusb.mk
5+
include $(SUB_PROJECTS)

app/src/main/jni/Application.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ APP_PLATFORM := android-21
55

66
# We support 16KB pages
77
APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true
8+
9+
APP_STL := c++_shared

app/src/main/jni/libusb

Submodule libusb added at 467b6a8
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Android.mk for xbox wireless driver
2+
LOCAL_PATH := $(call my-dir)
3+
include $(CLEAR_VARS)
4+
LOCAL_MODULE := xow-driver
5+
LOCAL_SRC_FILES := \
6+
xow_driver_jni.cpp \
7+
dongle/firmware.cpp \
8+
dongle/usb.cpp \
9+
dongle/mt76.cpp \
10+
dongle/dongle.cpp \
11+
utils/log.cpp \
12+
controller/controller.cpp \
13+
controller/gip.cpp
14+
15+
LOCAL_C_INCLUDES := $(LOCAL_PATH) $(LIBUSB_ROOT_ABS)
16+
LOCAL_SHARED_LIBRARIES += libusb1.0
17+
LOCAL_LDLIBS := -llog
18+
19+
ifeq ($(NDK_DEBUG),1)
20+
LOCAL_CFLAGS += -D_DEBUG
21+
endif
22+
include $(BUILD_SHARED_LIBRARY)
23+
24+

0 commit comments

Comments
 (0)