Android: Convert WiimoteAdapter to Kotlin

This commit is contained in:
Simonx22 2026-04-06 18:07:21 -04:00
parent 5abf0e3556
commit 662b1d74a8
2 changed files with 153 additions and 172 deletions

View File

@ -1,172 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.utils;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbConfiguration;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Build;
import androidx.annotation.Keep;
import org.dolphinemu.dolphinemu.DolphinApplication;
import org.dolphinemu.dolphinemu.services.USBPermService;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class WiimoteAdapter
{
final static int MAX_PAYLOAD = 23;
final static int MAX_WIIMOTES = 4;
final static int TIMEOUT = 200;
final static short NINTENDO_VENDOR_ID = 0x057e;
final static short NINTENDO_WIIMOTE_PRODUCT_ID = 0x0306;
public static UsbManager manager;
static UsbDeviceConnection usbConnection;
static UsbInterface[] usbInterface = new UsbInterface[MAX_WIIMOTES];
static UsbEndpoint[] usbIn = new UsbEndpoint[MAX_WIIMOTES];
@Keep
public static byte[][] wiimotePayload = new byte[MAX_WIIMOTES][MAX_PAYLOAD];
private static void requestPermission()
{
HashMap<String, UsbDevice> devices = manager.getDeviceList();
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
{
UsbDevice dev = pair.getValue();
if (dev.getProductId() == NINTENDO_WIIMOTE_PRODUCT_ID &&
dev.getVendorId() == NINTENDO_VENDOR_ID)
{
if (!manager.hasPermission(dev))
{
Log.warning("Requesting permission for Wii Remote adapter");
Context context = DolphinApplication.getAppContext();
Intent intent = new Intent(context, USBPermService.class);
int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ?
PendingIntent.FLAG_IMMUTABLE : 0;
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, flags);
manager.requestPermission(dev, pendingIntent);
}
}
}
}
@Keep
public static boolean queryAdapter()
{
HashMap<String, UsbDevice> devices = manager.getDeviceList();
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
{
UsbDevice dev = pair.getValue();
if (dev.getProductId() == NINTENDO_WIIMOTE_PRODUCT_ID &&
dev.getVendorId() == NINTENDO_VENDOR_ID)
{
if (manager.hasPermission(dev))
return true;
else
requestPermission();
}
}
return false;
}
@Keep
public static int input(int index)
{
return usbConnection.bulkTransfer(usbIn[index], wiimotePayload[index], MAX_PAYLOAD, TIMEOUT);
}
@Keep
public static int output(int index, byte[] buf, int size)
{
byte report_number = buf[0];
// Remove the report number from the buffer
buf = Arrays.copyOfRange(buf, 1, buf.length);
size--;
final int LIBUSB_REQUEST_TYPE_CLASS = (1 << 5);
final int LIBUSB_RECIPIENT_INTERFACE = 0x1;
final int LIBUSB_ENDPOINT_OUT = 0;
final int HID_SET_REPORT = 0x9;
final int HID_OUTPUT = (2 << 8);
int write = usbConnection.controlTransfer(
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
HID_SET_REPORT,
HID_OUTPUT | report_number,
index,
buf, size,
1000);
if (write < 0)
return 0;
return write + 1;
}
@Keep
public static boolean openAdapter()
{
// If the adapter is already open. Don't attempt to do it again
if (usbConnection != null && usbConnection.getFileDescriptor() != -1)
return true;
HashMap<String, UsbDevice> devices = manager.getDeviceList();
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
{
UsbDevice dev = pair.getValue();
if (dev.getProductId() == NINTENDO_WIIMOTE_PRODUCT_ID &&
dev.getVendorId() == NINTENDO_VENDOR_ID)
{
if (manager.hasPermission(dev))
{
usbConnection = manager.openDevice(dev);
UsbConfiguration conf = dev.getConfiguration(0);
Log.info("Number of configurations: " + dev.getConfigurationCount());
Log.info("Number of Interfaces: " + dev.getInterfaceCount());
Log.info("Number of Interfaces from conf: " + conf.getInterfaceCount());
// Sometimes the interface count is returned as zero.
// Means the device needs to be unplugged and plugged back in again
if (dev.getInterfaceCount() > 0)
{
for (int i = 0; i < MAX_WIIMOTES; ++i)
{
// One interface per Wii Remote
usbInterface[i] = dev.getInterface(i);
usbConnection.claimInterface(usbInterface[i], true);
// One endpoint per Wii Remote. Input only
// Output reports go through the control channel.
usbIn[i] = usbInterface[i].getEndpoint(0);
Log.info("Interface " + i + " endpoint count:" + usbInterface[i].getEndpointCount());
}
return true;
}
else
{
// XXX: Message that the device was found, but it needs to be unplugged and plugged back in?
usbConnection.close();
}
}
}
}
return false;
}
}

View File

@ -0,0 +1,153 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.utils
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.hardware.usb.UsbConfiguration
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbEndpoint
import android.hardware.usb.UsbInterface
import android.hardware.usb.UsbManager
import androidx.annotation.Keep
import org.dolphinemu.dolphinemu.DolphinApplication
import org.dolphinemu.dolphinemu.services.USBPermService
import java.util.Arrays
object WiimoteAdapter {
private const val MAX_PAYLOAD = 23
private const val MAX_WIIMOTES = 4
private const val TIMEOUT = 200
private const val NINTENDO_VENDOR_ID = 0x057e
private const val NINTENDO_WIIMOTE_PRODUCT_ID = 0x0306
lateinit var manager: UsbManager
private var usbConnection: UsbDeviceConnection? = null
private val usbInterface = arrayOfNulls<UsbInterface>(MAX_WIIMOTES)
private val usbIn = arrayOfNulls<UsbEndpoint>(MAX_WIIMOTES)
@Keep
@JvmField
val wiimotePayload: Array<ByteArray> = Array(MAX_WIIMOTES) { ByteArray(MAX_PAYLOAD) }
private fun requestPermission() {
val devices = manager.deviceList
for (dev in devices.values) {
if (dev.productId == NINTENDO_WIIMOTE_PRODUCT_ID && dev.vendorId == NINTENDO_VENDOR_ID) {
if (!manager.hasPermission(dev)) {
Log.warning("Requesting permission for Wii Remote adapter")
val context: Context = DolphinApplication.getAppContext()
val intent = Intent(context, USBPermService::class.java)
val pendingIntent =
PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
manager.requestPermission(dev, pendingIntent)
}
}
}
}
@Keep
@JvmStatic
fun queryAdapter(): Boolean {
val devices = manager.deviceList
for (dev in devices.values) {
if (dev.productId == NINTENDO_WIIMOTE_PRODUCT_ID && dev.vendorId == NINTENDO_VENDOR_ID) {
if (manager.hasPermission(dev)) {
return true
} else {
requestPermission()
}
}
}
return false
}
@Keep
@JvmStatic
fun input(index: Int): Int {
return usbConnection!!.bulkTransfer(
usbIn[index], wiimotePayload[index], MAX_PAYLOAD, TIMEOUT
)
}
@Keep
@JvmStatic
fun output(index: Int, buf: ByteArray, size: Int): Int {
val reportNumber = buf[0]
// Remove the report number from the buffer
val outputBuffer = Arrays.copyOfRange(buf, 1, buf.size)
val outputSize = size - 1
val libusbRequestTypeClass = 1 shl 5
val libusbRecipientInterface = 0x1
val libusbEndpointOut = 0
val hidSetReport = 0x9
val hidOutput = 2 shl 8
val write = usbConnection!!.controlTransfer(
libusbRequestTypeClass or libusbRecipientInterface or libusbEndpointOut,
hidSetReport,
hidOutput or reportNumber.toInt(),
index,
outputBuffer,
outputSize,
1000
)
if (write < 0) {
return 0
}
return write + 1
}
@Keep
@JvmStatic
fun openAdapter(): Boolean {
// If the adapter is already open. Don't attempt to do it again
if (usbConnection != null && usbConnection!!.fileDescriptor != -1) {
return true
}
val devices = manager.deviceList
for (dev in devices.values) {
if (dev.productId == NINTENDO_WIIMOTE_PRODUCT_ID && dev.vendorId == NINTENDO_VENDOR_ID) {
if (manager.hasPermission(dev)) {
usbConnection = manager.openDevice(dev)
val conf: UsbConfiguration = dev.getConfiguration(0)
Log.info("Number of configurations: " + dev.configurationCount)
Log.info("Number of Interfaces: " + dev.interfaceCount)
Log.info("Number of Interfaces from conf: " + conf.interfaceCount)
// Sometimes the interface count is returned as zero.
// Means the device needs to be unplugged and plugged back in again
if (dev.interfaceCount > 0) {
for (i in 0 until MAX_WIIMOTES) {
// One interface per Wii Remote
usbInterface[i] = dev.getInterface(i)
usbConnection!!.claimInterface(usbInterface[i], true)
// One endpoint per Wii Remote. Input only
// Output reports go through the control channel.
usbIn[i] = usbInterface[i]!!.getEndpoint(0)
Log.info("Interface " + i + " endpoint count:" + usbInterface[i]!!.endpointCount)
}
return true
} else {
// XXX: Message that the device was found, but it needs to be unplugged and plugged back in?
usbConnection!!.close()
}
}
}
}
return false
}
}