mirror of
https://github.com/moonlight-stream/moonlight-embedded.git
synced 2026-04-18 14:30:17 +00:00
Merge pull request #85 from cgutman/master
Add multiple controller support and fix input device watcher issues
This commit is contained in:
@@ -107,7 +107,7 @@
|
|||||||
<target name="compile-common" depends="init">
|
<target name="compile-common" depends="init">
|
||||||
<!-- compile limelight -->
|
<!-- compile limelight -->
|
||||||
<javac includeantruntime="false" destdir="${classes.dir}/common">
|
<javac includeantruntime="false" destdir="${classes.dir}/common">
|
||||||
<src path="${common.src.dir}"/>java
|
<src path="${common.src.dir}"/>
|
||||||
|
|
||||||
<classpath>
|
<classpath>
|
||||||
<fileset dir="${common.libs.dir}" includes="*.jar"/>
|
<fileset dir="${common.libs.dir}" includes="*.jar"/>
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ public class EvdevAbsolute {
|
|||||||
return reverse?Short.MAX_VALUE:Short.MIN_VALUE;
|
return reverse?Short.MAX_VALUE:Short.MIN_VALUE;
|
||||||
else {
|
else {
|
||||||
value += value<avg?flat:-flat;
|
value += value<avg?flat:-flat;
|
||||||
return (short) ((value-avg) * Short.MAX_VALUE / (reverse?flat-range:range-flat));
|
|
||||||
|
// Divide the value by the range before multiplying to avoid overflowing
|
||||||
|
return (short) (((value-avg) / (float)(reverse?flat-range:range-flat)) * 0x7FFE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.limelight.input;
|
package com.limelight.input;
|
||||||
|
|
||||||
|
import com.limelight.LimeLog;
|
||||||
import com.limelight.nvstream.NvConnection;
|
import com.limelight.nvstream.NvConnection;
|
||||||
import com.limelight.nvstream.input.ControllerPacket;
|
import com.limelight.nvstream.input.ControllerPacket;
|
||||||
import com.limelight.nvstream.input.KeyboardPacket;
|
import com.limelight.nvstream.input.KeyboardPacket;
|
||||||
@@ -20,11 +21,16 @@ public class EvdevHandler extends EvdevReader {
|
|||||||
/* GFE's prefix for every key code */
|
/* GFE's prefix for every key code */
|
||||||
public static final short KEY_PREFIX = (short) 0x80;
|
public static final short KEY_PREFIX = (short) 0x80;
|
||||||
|
|
||||||
|
/* Global controller ID state */
|
||||||
|
private static int assignedControllerIds = 0;
|
||||||
|
private static Object controllerIdLock = new Object();
|
||||||
|
|
||||||
/* Gamepad state */
|
/* Gamepad state */
|
||||||
private short buttonFlags;
|
private short buttonFlags;
|
||||||
private byte leftTrigger, rightTrigger;
|
private byte leftTrigger, rightTrigger;
|
||||||
private short leftStickX, leftStickY, rightStickX, rightStickY;
|
private short leftStickX, leftStickY, rightStickX, rightStickY;
|
||||||
private boolean gamepadSynced;
|
private boolean gamepadSynced;
|
||||||
|
private short controllerId = -1;
|
||||||
|
|
||||||
private short mouseDeltaX, mouseDeltaY;
|
private short mouseDeltaX, mouseDeltaY;
|
||||||
private byte mouseScroll;
|
private byte mouseScroll;
|
||||||
@@ -41,9 +47,6 @@ public class EvdevHandler extends EvdevReader {
|
|||||||
this.conn = conn;
|
this.conn = conn;
|
||||||
this.mapping = mapping;
|
this.mapping = mapping;
|
||||||
|
|
||||||
// We want limelight-common to scale the axis values to match Xinput values
|
|
||||||
ControllerPacket.enableAxisScaling = true;
|
|
||||||
|
|
||||||
absLX = new EvdevAbsolute(device, mapping.abs_x, mapping.reverse_x);
|
absLX = new EvdevAbsolute(device, mapping.abs_x, mapping.reverse_x);
|
||||||
absLY = new EvdevAbsolute(device, mapping.abs_y, !mapping.reverse_y);
|
absLY = new EvdevAbsolute(device, mapping.abs_y, !mapping.reverse_y);
|
||||||
absRX = new EvdevAbsolute(device, mapping.abs_rx, mapping.reverse_rx);
|
absRX = new EvdevAbsolute(device, mapping.abs_rx, mapping.reverse_rx);
|
||||||
@@ -57,6 +60,30 @@ public class EvdevHandler extends EvdevReader {
|
|||||||
gamepadSynced = true;
|
gamepadSynced = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assignNewControllerId() {
|
||||||
|
synchronized (controllerIdLock) {
|
||||||
|
for (short i = 0; i < 4; i++) {
|
||||||
|
if ((assignedControllerIds & (1 << i)) == 0) {
|
||||||
|
// Assign this unused value to this input device
|
||||||
|
assignedControllerIds |= (1 << i);
|
||||||
|
controllerId = i;
|
||||||
|
LimeLog.info("Assigning controller ID "+i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All IDs have been assigned so use controller 0 for the rest
|
||||||
|
controllerId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void releaseControllerId() {
|
||||||
|
LimeLog.info("Releasing controller ID "+controllerId);
|
||||||
|
synchronized (controllerIdLock) {
|
||||||
|
assignedControllerIds &= ~(1 << controllerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void parseEvent(ByteBuffer buffer) {
|
protected void parseEvent(ByteBuffer buffer) {
|
||||||
if (buffer.limit()==EvdevConstants.MAX_STRUCT_SIZE_BYTES) {
|
if (buffer.limit()==EvdevConstants.MAX_STRUCT_SIZE_BYTES) {
|
||||||
@@ -73,7 +100,16 @@ public class EvdevHandler extends EvdevReader {
|
|||||||
|
|
||||||
if (type==EvdevConstants.EV_SYN) {
|
if (type==EvdevConstants.EV_SYN) {
|
||||||
if (!gamepadSynced) {
|
if (!gamepadSynced) {
|
||||||
conn.sendControllerInput(buttonFlags, leftTrigger, rightTrigger, leftStickX, leftStickY, rightStickX, rightStickY);
|
// Assign a controller ID if one hasn't been assigned yet.
|
||||||
|
// Note that we're only assigning IDs to things that actually send
|
||||||
|
// some form of controller input to avoid falsely reserving IDs for
|
||||||
|
// devices that aren't actually controllers or are inactive controllers.
|
||||||
|
if (controllerId < 0) {
|
||||||
|
assignNewControllerId();
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.sendControllerInput(controllerId, buttonFlags, leftTrigger, rightTrigger,
|
||||||
|
leftStickX, leftStickY, rightStickX, rightStickY);
|
||||||
gamepadSynced = true;
|
gamepadSynced = true;
|
||||||
}
|
}
|
||||||
if (mouseDeltaX != 0 || mouseDeltaY != 0) {
|
if (mouseDeltaX != 0 || mouseDeltaY != 0) {
|
||||||
@@ -222,6 +258,14 @@ public class EvdevHandler extends EvdevReader {
|
|||||||
gamepadSynced &= !gamepadModified;
|
gamepadSynced &= !gamepadModified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deviceRemoved() {
|
||||||
|
// Release this device's controller ID (if it has one)
|
||||||
|
if (controllerId >= 0) {
|
||||||
|
releaseControllerId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private short accountForDeadzone(short value) {
|
private short accountForDeadzone(short value) {
|
||||||
return Math.abs(value) > mapping.abs_deadzone?value:0;
|
return Math.abs(value) > mapping.abs_deadzone?value:0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,16 +90,22 @@ public class EvdevLoader implements Runnable {
|
|||||||
WatchService watcher = evdev.getFileSystem().newWatchService();
|
WatchService watcher = evdev.getFileSystem().newWatchService();
|
||||||
evdev.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
|
evdev.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
|
||||||
|
|
||||||
WatchKey watckKey = watcher.take();
|
for (;;) {
|
||||||
List<WatchEvent<?>> events = watckKey.pollEvents();
|
WatchKey watchKey = watcher.take();
|
||||||
for (WatchEvent event:events) {
|
List<WatchEvent<?>> events = watchKey.pollEvents();
|
||||||
if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
|
for (WatchEvent event:events) {
|
||||||
String name = event.context().toString();
|
if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
|
||||||
if (filter.accept(input, name)) {
|
String name = event.context().toString();
|
||||||
LimeLog.info("Input " + name + " added");
|
if (filter.accept(input, name)) {
|
||||||
new EvdevHandler(conn, new File(input, name).getAbsolutePath(), mapping).start();
|
LimeLog.info("Input " + name + " added");
|
||||||
|
new EvdevHandler(conn, new File(input, name).getAbsolutePath(), mapping).start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!watchKey.reset()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException | InterruptedException ex) {
|
} catch (IOException | InterruptedException ex) {
|
||||||
LimeLog.severe(ex.getMessage());
|
LimeLog.severe(ex.getMessage());
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public abstract class EvdevReader implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void parseEvent(ByteBuffer buffer);
|
protected abstract void parseEvent(ByteBuffer buffer);
|
||||||
|
protected abstract void deviceRemoved();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -54,6 +55,7 @@ public abstract class EvdevReader implements Runnable {
|
|||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LimeLog.warning("Input device removed");
|
LimeLog.warning("Input device removed");
|
||||||
|
deviceRemoved();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,11 @@ public class GamepadMapper extends EvdevReader {
|
|||||||
notify();
|
notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deviceRemoved() {
|
||||||
|
// Nothing for us to do
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void readKey(String key, String name) throws InterruptedException {
|
public synchronized void readKey(String key, String name) throws InterruptedException {
|
||||||
System.out.println(name);
|
System.out.println(name);
|
||||||
|
|||||||
Reference in New Issue
Block a user