mirror of
https://github.com/Maschell/HIDtoVPADNetworkClient.git
synced 2024-11-22 05:59:16 +01:00
Added option for disable auto-scanning for controllers
Alternative: buttons for scanning manually. - Change the OSX implementation. You need to scan for controller manually to get it working. - OSX doesn’t check is a connection is still open when sending. Added a PING response to check if the client is still connected. !!!!!!!!! - Changed the protocol! For this network client, you’ll need the newest nighty of HIDtoVPAD! !!!!!!!!!
This commit is contained in:
parent
79f4d738de
commit
25e8bc6faf
@ -1,6 +1,9 @@
|
|||||||
package net.ash.HIDToVPADNetworkClient.controller;
|
package net.ash.HIDToVPADNetworkClient.controller;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException;
|
import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException;
|
||||||
|
import net.ash.HIDToVPADNetworkClient.util.Settings;
|
||||||
|
|
||||||
public class DS4NewController extends PureJavaHidController {
|
public class DS4NewController extends PureJavaHidController {
|
||||||
public static final short DS4_NEW_CONTROLLER_VID = 0x54C;
|
public static final short DS4_NEW_CONTROLLER_VID = 0x54C;
|
||||||
@ -8,12 +11,19 @@ public class DS4NewController extends PureJavaHidController {
|
|||||||
|
|
||||||
public DS4NewController(String identifier) throws ControllerInitializationFailedException {
|
public DS4NewController(String identifier) throws ControllerInitializationFailedException {
|
||||||
super(identifier);
|
super(identifier);
|
||||||
// truncate package to 6;
|
if (Settings.isMacOSX()) {
|
||||||
this.PACKET_LENGTH = 6;
|
this.PACKET_LENGTH = 7;
|
||||||
|
} else {
|
||||||
|
this.PACKET_LENGTH = 6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] pollLatestData() {
|
public byte[] pollLatestData() {
|
||||||
|
if (Settings.isMacOSX()) { // for some reason the controller has one extra byte at the beginning under OSX
|
||||||
|
return Arrays.copyOfRange(currentData, 1, 7);
|
||||||
|
}
|
||||||
|
|
||||||
return currentData.clone();
|
return currentData.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,11 +28,13 @@ import lombok.AccessLevel;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.Synchronized;
|
import lombok.Synchronized;
|
||||||
|
import lombok.extern.java.Log;
|
||||||
import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException;
|
import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException;
|
||||||
import net.ash.HIDToVPADNetworkClient.util.PureJavaHidApiManager;
|
import net.ash.HIDToVPADNetworkClient.util.PureJavaHidApiManager;
|
||||||
import purejavahidapi.HidDevice;
|
import purejavahidapi.HidDevice;
|
||||||
import purejavahidapi.InputReportListener;
|
import purejavahidapi.InputReportListener;
|
||||||
|
|
||||||
|
@Log
|
||||||
public class PureJavaHidController extends Controller implements InputReportListener {
|
public class PureJavaHidController extends Controller implements InputReportListener {
|
||||||
private final Object dataLock = new Object();
|
private final Object dataLock = new Object();
|
||||||
protected byte[] currentData = new byte[1];
|
protected byte[] currentData = new byte[1];
|
||||||
@ -43,12 +45,20 @@ public class PureJavaHidController extends Controller implements InputReportList
|
|||||||
|
|
||||||
public static Controller getInstance(String deviceIdentifier) throws IOException, ControllerInitializationFailedException {
|
public static Controller getInstance(String deviceIdentifier) throws IOException, ControllerInitializationFailedException {
|
||||||
HidDevice device = PureJavaHidApiManager.getDeviceByPath(deviceIdentifier);
|
HidDevice device = PureJavaHidApiManager.getDeviceByPath(deviceIdentifier);
|
||||||
|
|
||||||
|
short vid = 0;
|
||||||
|
short pid = 0;
|
||||||
|
if (device != null) {
|
||||||
|
vid = device.getHidDeviceInfo().getVendorId();
|
||||||
|
pid = device.getHidDeviceInfo().getProductId();
|
||||||
|
device.close();
|
||||||
|
}
|
||||||
|
|
||||||
// We use a special version to optimize the data for the switch pro controller
|
// We use a special version to optimize the data for the switch pro controller
|
||||||
if (device.getHidDeviceInfo().getVendorId() == SwitchProController.SWITCH_PRO_CONTROLLER_VID
|
if (vid == SwitchProController.SWITCH_PRO_CONTROLLER_VID && pid == SwitchProController.SWITCH_PRO_CONTROLLER_PID) {
|
||||||
&& device.getHidDeviceInfo().getProductId() == SwitchProController.SWITCH_PRO_CONTROLLER_PID) {
|
|
||||||
return new SwitchProController(deviceIdentifier);
|
return new SwitchProController(deviceIdentifier);
|
||||||
} else if (device.getHidDeviceInfo().getVendorId() == DS4NewController.DS4_NEW_CONTROLLER_VID
|
} else if (vid == DS4NewController.DS4_NEW_CONTROLLER_VID && pid == DS4NewController.DS4_NEW_CONTROLLER_PID) {
|
||||||
&& device.getHidDeviceInfo().getProductId() == DS4NewController.DS4_NEW_CONTROLLER_PID) {
|
|
||||||
return new DS4NewController(deviceIdentifier);
|
return new DS4NewController(deviceIdentifier);
|
||||||
} else {
|
} else {
|
||||||
return new PureJavaHidController(deviceIdentifier);
|
return new PureJavaHidController(deviceIdentifier);
|
||||||
@ -64,6 +74,9 @@ public class PureJavaHidController extends Controller implements InputReportList
|
|||||||
HidDevice device;
|
HidDevice device;
|
||||||
try {
|
try {
|
||||||
device = PureJavaHidApiManager.getDeviceByPath(identifier);
|
device = PureJavaHidApiManager.getDeviceByPath(identifier);
|
||||||
|
if (device == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
device.setInputReportListener(this);
|
device.setInputReportListener(this);
|
||||||
setHidDevice(device);
|
setHidDevice(device);
|
||||||
@ -83,7 +96,16 @@ public class PureJavaHidController extends Controller implements InputReportList
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroyDriver() {
|
public void destroyDriver() {
|
||||||
getHidDevice().close();
|
try {
|
||||||
|
getHidDevice().close();
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
if (e.getMessage().equals("device not open")) {
|
||||||
|
log.info("Error closing the device." + e.getMessage());
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -35,7 +35,7 @@ public class SwitchProController extends PureJavaHidController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] pollLatestData() {
|
public byte[] pollLatestData() {
|
||||||
if(currentData == null || currentData.length < 10){
|
if (currentData == null || currentData.length < 10) {
|
||||||
return new byte[0];
|
return new byte[0];
|
||||||
}
|
}
|
||||||
// remove unused data (because only changed data will be sent)
|
// remove unused data (because only changed data will be sent)
|
||||||
|
@ -55,7 +55,7 @@ public class XInputController extends Controller {
|
|||||||
try {
|
try {
|
||||||
device = XInputDevice.getDeviceFor(pad);
|
device = XInputDevice.getDeviceFor(pad);
|
||||||
} catch (XInputNotLoadedException e) {
|
} catch (XInputNotLoadedException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
if (device == null) return false;
|
if (device == null) return false;
|
||||||
setDevice(device);
|
setDevice(device);
|
||||||
@ -65,9 +65,9 @@ public class XInputController extends Controller {
|
|||||||
@Override
|
@Override
|
||||||
public byte[] pollLatestData() {
|
public byte[] pollLatestData() {
|
||||||
boolean newData = false;
|
boolean newData = false;
|
||||||
try{
|
try {
|
||||||
newData = device.poll();
|
newData = device.poll();
|
||||||
}catch(BufferUnderflowException e){
|
} catch (BufferUnderflowException e) {
|
||||||
log.info("Error reading the XInput data " + e.getMessage());
|
log.info("Error reading the XInput data " + e.getMessage());
|
||||||
setActive(false);
|
setActive(false);
|
||||||
Thread.currentThread().stop();
|
Thread.currentThread().stop();
|
||||||
|
@ -38,10 +38,11 @@ import javax.swing.SwingUtilities;
|
|||||||
import javax.swing.Timer;
|
import javax.swing.Timer;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import net.ash.HIDToVPADNetworkClient.manager.ControllerManager;
|
||||||
import net.ash.HIDToVPADNetworkClient.network.NetworkManager;
|
import net.ash.HIDToVPADNetworkClient.network.NetworkManager;
|
||||||
import net.ash.HIDToVPADNetworkClient.util.Settings;
|
import net.ash.HIDToVPADNetworkClient.util.Settings;
|
||||||
|
|
||||||
public final class GuiInputControls extends JPanel implements ActionListener {
|
public final class GuiInputControls extends JPanel {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@Getter private static GuiInputControls instance = new GuiInputControls();
|
@Getter private static GuiInputControls instance = new GuiInputControls();
|
||||||
|
|
||||||
@ -59,6 +60,41 @@ public final class GuiInputControls extends JPanel implements ActionListener {
|
|||||||
final JButton connectButton = new JButton(CONNECT);
|
final JButton connectButton = new JButton(CONNECT);
|
||||||
connectButton.setAlignmentX(Component.CENTER_ALIGNMENT);
|
connectButton.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||||
|
|
||||||
|
final JCheckBox cbautoScanForController = new JCheckBox();
|
||||||
|
if (Settings.isMacOSX()) {
|
||||||
|
cbautoScanForController.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
cbautoScanForController.setSelected(Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
cbautoScanForController.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
boolean selected = ((JCheckBox) e.getSource()).isSelected();
|
||||||
|
Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS = selected;
|
||||||
|
cbautoScanForController.setSelected(selected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final JButton scanButton = new JButton("Scan for Controllers");
|
||||||
|
scanButton.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||||
|
scanButton.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
ControllerManager.detectControllers();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
JPanel scanWrap = new JPanel();
|
||||||
|
scanWrap.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
|
||||||
|
scanWrap.add(new JLabel("Auto Scan for Controllers: "));
|
||||||
|
scanWrap.add(cbautoScanForController);
|
||||||
|
|
||||||
ipTextBox = new JTextField();
|
ipTextBox = new JTextField();
|
||||||
ipTextBox.setColumns(15);
|
ipTextBox.setColumns(15);
|
||||||
ipTextBox.setText(Settings.getIpAddr());
|
ipTextBox.setText(Settings.getIpAddr());
|
||||||
@ -67,9 +103,6 @@ public final class GuiInputControls extends JPanel implements ActionListener {
|
|||||||
ipTextBoxWrap.add(ipTextBox);
|
ipTextBoxWrap.add(ipTextBox);
|
||||||
ipTextBoxWrap.setMaximumSize(new Dimension(1000, 20));
|
ipTextBoxWrap.setMaximumSize(new Dimension(1000, 20));
|
||||||
|
|
||||||
JLabel statusLabel = new JLabel("Ready.");
|
|
||||||
statusLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
|
|
||||||
|
|
||||||
final JCheckBox cbautoActivateController = new JCheckBox();
|
final JCheckBox cbautoActivateController = new JCheckBox();
|
||||||
cbautoActivateController.setSelected(Settings.AUTO_ACTIVATE_CONTROLLER);
|
cbautoActivateController.setSelected(Settings.AUTO_ACTIVATE_CONTROLLER);
|
||||||
cbautoActivateController.addActionListener(new ActionListener() {
|
cbautoActivateController.addActionListener(new ActionListener() {
|
||||||
@ -93,14 +126,33 @@ public final class GuiInputControls extends JPanel implements ActionListener {
|
|||||||
|
|
||||||
add(Box.createRigidArea(new Dimension(1, 4)));
|
add(Box.createRigidArea(new Dimension(1, 4)));
|
||||||
add(connectButton);
|
add(connectButton);
|
||||||
add(Box.createRigidArea(new Dimension(1, 8)));
|
add(Box.createRigidArea(new Dimension(1, 4)));
|
||||||
|
add(scanButton);
|
||||||
add(statusLabel);
|
add(scanWrap);
|
||||||
|
add(Box.createVerticalGlue());
|
||||||
add(autoActivateWrap);
|
add(autoActivateWrap);
|
||||||
|
|
||||||
add(Box.createVerticalGlue());
|
add(Box.createVerticalGlue());
|
||||||
|
|
||||||
connectButton.addActionListener(this);
|
connectButton.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
Settings.setIpAddr(ipTextBox.getText());
|
||||||
|
if (NetworkManager.getInstance().isReconnecting()) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (NetworkManager.getInstance().isConnected()) {
|
||||||
|
NetworkManager.getInstance().disconnect();
|
||||||
|
} else {
|
||||||
|
NetworkManager.getInstance().connect(ipTextBox.getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
int delay = 100; // milliseconds
|
int delay = 100; // milliseconds
|
||||||
ActionListener taskPerformer = new ActionListener() {
|
ActionListener taskPerformer = new ActionListener() {
|
||||||
@ -119,23 +171,4 @@ public final class GuiInputControls extends JPanel implements ActionListener {
|
|||||||
};
|
};
|
||||||
new Timer(delay, taskPerformer).start();
|
new Timer(delay, taskPerformer).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
Settings.setIpAddr(ipTextBox.getText());
|
|
||||||
if (NetworkManager.getInstance().isReconnecting()) {
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (NetworkManager.getInstance().isConnected()) {
|
|
||||||
NetworkManager.getInstance().disconnect();
|
|
||||||
} else {
|
|
||||||
NetworkManager.getInstance().connect(ipTextBox.getText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ public class GuiMain extends JPanel implements MessageBoxListener {
|
|||||||
super(new BorderLayout());
|
super(new BorderLayout());
|
||||||
|
|
||||||
GuiControllerList leftControllerList = new GuiControllerList();
|
GuiControllerList leftControllerList = new GuiControllerList();
|
||||||
leftControllerList.setPreferredSize(new Dimension(300, 100));
|
leftControllerList.setPreferredSize(new Dimension(400, 200));
|
||||||
add(leftControllerList, BorderLayout.CENTER);
|
add(leftControllerList, BorderLayout.CENTER);
|
||||||
GuiInputControls rightSideControls = GuiInputControls.getInstance();
|
GuiInputControls rightSideControls = GuiInputControls.getInstance();
|
||||||
add(rightSideControls, BorderLayout.LINE_END);
|
add(rightSideControls, BorderLayout.LINE_END);
|
||||||
|
@ -51,9 +51,13 @@ public final class ActiveControllerManager implements Runnable {
|
|||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
// Scan once initially
|
||||||
|
ControllerManager.detectControllers();
|
||||||
while (true) {
|
while (true) {
|
||||||
updateControllerStates();
|
updateControllerStates();
|
||||||
ControllerManager.detectControllers();
|
if (Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS) {
|
||||||
|
ControllerManager.detectControllers();
|
||||||
|
}
|
||||||
Utilities.sleep(Settings.DETECT_CONTROLLER_INTERVAL);
|
Utilities.sleep(Settings.DETECT_CONTROLLER_INTERVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,8 @@ import purejavahidapi.HidDeviceInfo;
|
|||||||
|
|
||||||
@Log
|
@Log
|
||||||
public final class ControllerManager {
|
public final class ControllerManager {
|
||||||
private static Map<String, Controller> attachedControllers = new HashMap<String, Controller>();
|
private static final Map<String, Controller> attachedControllers = new HashMap<String, Controller>();
|
||||||
|
private static final Map<String, HidDeviceInfo> connectedDevicesInfo = new HashMap<String, HidDeviceInfo>();
|
||||||
|
|
||||||
private static boolean threwUnsatisfiedLinkError = false;
|
private static boolean threwUnsatisfiedLinkError = false;
|
||||||
|
|
||||||
@ -63,7 +64,7 @@ public final class ControllerManager {
|
|||||||
/**
|
/**
|
||||||
* Detects all attached controller.
|
* Detects all attached controller.
|
||||||
*/
|
*/
|
||||||
@Synchronized("attachedControllers")
|
|
||||||
public static void detectControllers() {
|
public static void detectControllers() {
|
||||||
Map<String, ControllerType> connectedDevices = new HashMap<String, ControllerType>();
|
Map<String, ControllerType> connectedDevices = new HashMap<String, ControllerType>();
|
||||||
|
|
||||||
@ -77,20 +78,30 @@ public final class ControllerManager {
|
|||||||
|
|
||||||
// Remove detached devices
|
// Remove detached devices
|
||||||
List<String> toRemove = new ArrayList<String>();
|
List<String> toRemove = new ArrayList<String>();
|
||||||
for (String s : attachedControllers.keySet()) {
|
synchronized (attachedControllers) {
|
||||||
if (!connectedDevices.containsKey(s)) {
|
for (String s : attachedControllers.keySet()) {
|
||||||
toRemove.add(s);
|
System.out.println(s);
|
||||||
|
if (!connectedDevices.containsKey(s)) {
|
||||||
|
toRemove.add(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String remove : toRemove) {
|
for (String remove : toRemove) {
|
||||||
attachedControllers.get(remove).destroyAll();
|
synchronized (attachedControllers) {
|
||||||
attachedControllers.remove(remove);
|
attachedControllers.get(remove).destroyAll();
|
||||||
|
attachedControllers.remove(remove);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add attached devices!
|
// Add attached devices!
|
||||||
for (Entry<String, ControllerType> entry : connectedDevices.entrySet()) {
|
for (Entry<String, ControllerType> entry : connectedDevices.entrySet()) {
|
||||||
String deviceIdentifier = entry.getKey();
|
String deviceIdentifier = entry.getKey();
|
||||||
if (!attachedControllers.containsKey(deviceIdentifier)) {
|
boolean contains = false;
|
||||||
|
synchronized (attachedControllers) {
|
||||||
|
contains = attachedControllers.containsKey(deviceIdentifier);
|
||||||
|
}
|
||||||
|
if (!contains) {
|
||||||
Controller c = null;
|
Controller c = null;
|
||||||
switch (entry.getValue()) {
|
switch (entry.getValue()) {
|
||||||
case PureJAVAHid:
|
case PureJAVAHid:
|
||||||
@ -131,7 +142,9 @@ public final class ControllerManager {
|
|||||||
c.setActive(true);
|
c.setActive(true);
|
||||||
}
|
}
|
||||||
new Thread(c).start();
|
new Thread(c).start();
|
||||||
attachedControllers.put(deviceIdentifier, c);
|
synchronized (attachedControllers) {
|
||||||
|
attachedControllers.put(deviceIdentifier, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,12 +157,13 @@ public final class ControllerManager {
|
|||||||
|
|
||||||
private static Map<String, ControllerType> detectHIDDevices() {
|
private static Map<String, ControllerType> detectHIDDevices() {
|
||||||
Map<String, ControllerType> connectedDevices = new HashMap<String, ControllerType>();
|
Map<String, ControllerType> connectedDevices = new HashMap<String, ControllerType>();
|
||||||
|
System.out.println("detectHIDDevices");
|
||||||
for (HidDeviceInfo info : PureJavaHidApiManager.getAttachedController()) {
|
for (HidDeviceInfo info : PureJavaHidApiManager.getAttachedController()) {
|
||||||
String path = info.getPath();
|
String path = info.getPath();
|
||||||
|
|
||||||
if (Settings.isMacOSX()) path = path.substring(0, 13);
|
|
||||||
connectedDevices.put(path, ControllerType.PureJAVAHid);
|
connectedDevices.put(path, ControllerType.PureJAVAHid);
|
||||||
|
synchronized (connectedDevicesInfo) {
|
||||||
|
connectedDevicesInfo.put(path, info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return connectedDevices;
|
return connectedDevices;
|
||||||
@ -214,10 +228,10 @@ public final class ControllerManager {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized("attachedControllers")
|
|
||||||
public static List<Controller> getActiveControllers() {
|
public static List<Controller> getActiveControllers() {
|
||||||
List<Controller> active = new ArrayList<Controller>();
|
List<Controller> active = new ArrayList<Controller>();
|
||||||
for (Controller c : attachedControllers.values()) {
|
List<Controller> attached = getAttachedControllers();
|
||||||
|
for (Controller c : attached) {
|
||||||
if (c.isActive()) {
|
if (c.isActive()) {
|
||||||
active.add(c);
|
active.add(c);
|
||||||
}
|
}
|
||||||
@ -225,11 +239,16 @@ public final class ControllerManager {
|
|||||||
return active;
|
return active;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized("attachedControllers")
|
|
||||||
public static void deactivateAllAttachedControllers() {
|
public static void deactivateAllAttachedControllers() {
|
||||||
for (Controller c : attachedControllers.values()) {
|
List<Controller> attached = getAttachedControllers();
|
||||||
|
for (Controller c : attached) {
|
||||||
c.setActive(false);
|
c.setActive(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized("connectedDevicesInfo")
|
||||||
|
public static HidDeviceInfo getDeviceInfoByPath(String path) {
|
||||||
|
return connectedDevicesInfo.get(path);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -161,6 +161,18 @@ public final class NetworkManager implements Runnable {
|
|||||||
private void sendPing(PingCommand command) {
|
private void sendPing(PingCommand command) {
|
||||||
if (sendTCP(Protocol.getRawPingDataToSend(command))) {
|
if (sendTCP(Protocol.getRawPingDataToSend(command))) {
|
||||||
log.info("PING");
|
log.info("PING");
|
||||||
|
byte pong;
|
||||||
|
try {
|
||||||
|
pong = tcpClient.recvByte();
|
||||||
|
if (pong != Protocol.TCP_CMD_PONG) {
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
log.info("got PONG!");
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.info("Failed to get PONG. Disconnecting.");
|
||||||
|
tcpClient.checkShouldRetry();
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
log.info("Sending the PING failed");
|
log.info("Sending the PING failed");
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ final class Protocol {
|
|||||||
static final byte TCP_CMD_ATTACH = 0x01;
|
static final byte TCP_CMD_ATTACH = 0x01;
|
||||||
static final byte TCP_CMD_DETACH = 0x02;
|
static final byte TCP_CMD_DETACH = 0x02;
|
||||||
static final byte TCP_CMD_PING = (byte) 0xF0;
|
static final byte TCP_CMD_PING = (byte) 0xF0;
|
||||||
|
static final byte TCP_CMD_PONG = (byte) 0xF1;
|
||||||
|
|
||||||
static final byte UDP_CMD_DATA = 0x03;
|
static final byte UDP_CMD_DATA = 0x03;
|
||||||
|
|
||||||
|
@ -90,20 +90,24 @@ final class TCPClient {
|
|||||||
out.write(rawCommand);
|
out.write(rawCommand);
|
||||||
out.flush();
|
out.flush();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
try {
|
checkShouldRetry();
|
||||||
if (shouldRetry++ < Settings.MAXIMUM_TRIES_FOR_RECONNECTING) {
|
|
||||||
log.info("Trying again to connect! Attempt number " + shouldRetry);
|
|
||||||
connect(ip);
|
|
||||||
} else {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
} catch (Exception e1) {
|
|
||||||
// e1.printStackTrace();
|
|
||||||
}
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void checkShouldRetry() {
|
||||||
|
try {
|
||||||
|
if (shouldRetry++ < Settings.MAXIMUM_TRIES_FOR_RECONNECTING) {
|
||||||
|
log.info("Trying again to connect! Attempt number " + shouldRetry);
|
||||||
|
connect(ip);
|
||||||
|
} else {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
} catch (Exception e1) {
|
||||||
|
// e1.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void send(int value) throws IOException {
|
void send(int value) throws IOException {
|
||||||
send(ByteBuffer.allocate(4).putInt(value).array());
|
send(ByteBuffer.allocate(4).putInt(value).array());
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.ash.HIDToVPADNetworkClient.manager.ControllerManager;
|
||||||
import purejavahidapi.HidDevice;
|
import purejavahidapi.HidDevice;
|
||||||
import purejavahidapi.HidDeviceInfo;
|
import purejavahidapi.HidDeviceInfo;
|
||||||
import purejavahidapi.PureJavaHidApi;
|
import purejavahidapi.PureJavaHidApi;
|
||||||
@ -43,25 +44,17 @@ public final class PureJavaHidApiManager {
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public static HidDevice getDeviceByPath(String path) throws IOException {
|
public static HidDevice getDeviceByPath(String path) throws IOException {
|
||||||
List<HidDeviceInfo> devList = PureJavaHidApi.enumerateDevices();
|
HidDeviceInfo deviceinfo = ControllerManager.getDeviceInfoByPath(path);
|
||||||
HidDevice result = null;
|
if (deviceinfo != null) {
|
||||||
for (HidDeviceInfo info : devList) {
|
HidDevice result = PureJavaHidApi.openDevice(deviceinfo);
|
||||||
result = openDeviceByPath(info, path);
|
if (result != null) {
|
||||||
if (result != null) return result;
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
/*
|
||||||
}
|
* List<HidDeviceInfo> devList = PureJavaHidApi.enumerateDevices(); HidDevice result = null; for (HidDeviceInfo info : devList) { String real_path =
|
||||||
|
* info.getPath(); if (real_path.equals(path)) { return PureJavaHidApi.openDevice(info); } }
|
||||||
private static HidDevice openDeviceByPath(HidDeviceInfo info, String expected_path) throws IOException {
|
*/
|
||||||
if (info == null) return null;
|
|
||||||
String real_path = info.getPath();
|
|
||||||
|
|
||||||
if (Settings.isMacOSX()) real_path = real_path.substring(0, 13);
|
|
||||||
|
|
||||||
if (real_path.equals(expected_path)) {
|
|
||||||
return PureJavaHidApi.openDevice(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,14 +62,35 @@ public final class PureJavaHidApiManager {
|
|||||||
List<HidDeviceInfo> connectedGamepads = new ArrayList<HidDeviceInfo>();
|
List<HidDeviceInfo> connectedGamepads = new ArrayList<HidDeviceInfo>();
|
||||||
|
|
||||||
for (HidDeviceInfo info : PureJavaHidApi.enumerateDevices()) {
|
for (HidDeviceInfo info : PureJavaHidApi.enumerateDevices()) {
|
||||||
if (info.getUsagePage() == 0x05 ||info.getUsagePage() == 0x01 || info.getUsagePage() == 0x04 || (info.getVendorId() == 0x57e) || (info.getVendorId() == 0x054c)) {
|
if (isGamepad(info)) {
|
||||||
if(((info.getVendorId() == 0x045e) && ((info.getProductId() == 0x02ff) || (info.getProductId() == 0x02a1))) && Settings.isWindows()){ //Skip Xbox pads on windows. We have XInput
|
// Skip Xbox controller under windows. We should use XInput instead.
|
||||||
|
if (isXboxController(info) && Settings.isWindows()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
connectedGamepads.add(info);
|
connectedGamepads.add(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return connectedGamepads;
|
return connectedGamepads;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static boolean isGamepad(HidDeviceInfo info) {
|
||||||
|
if (info == null) return false;
|
||||||
|
short usagePage = info.getUsagePage();
|
||||||
|
return (usagePage == 0x05 || usagePage == 0x01 || usagePage == 0x04 || isNintendoController(info) || isPlaystationController(info));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPlaystationController(HidDeviceInfo info) {
|
||||||
|
if (info == null) return false;
|
||||||
|
return (info.getVendorId() == 0x054c);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isNintendoController(HidDeviceInfo info) {
|
||||||
|
if (info == null) return false;
|
||||||
|
return (info.getVendorId() == 0x57e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isXboxController(HidDeviceInfo info) {
|
||||||
|
if (info == null) return false;
|
||||||
|
return (info.getVendorId() == 0x045e) && ((info.getProductId() == 0x02ff) || (info.getProductId() == 0x02a1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -44,9 +44,11 @@ public final class Settings {
|
|||||||
public static final int PING_INTERVAL = 1000;
|
public static final int PING_INTERVAL = 1000;
|
||||||
public static final int PROCESS_CMD_INTERVAL = 10;
|
public static final int PROCESS_CMD_INTERVAL = 10;
|
||||||
|
|
||||||
|
public static boolean SCAN_AUTOMATICALLY_FOR_CONTROLLERS = !isMacOSX(); // It doesn't work on OSX
|
||||||
|
|
||||||
public static boolean DEBUG_UDP_OUTPUT = false;
|
public static boolean DEBUG_UDP_OUTPUT = false;
|
||||||
public static boolean SEND_DATA_ONLY_ON_CHANGE = false;
|
public static boolean SEND_DATA_ONLY_ON_CHANGE = false;
|
||||||
public static boolean AUTO_ACTIVATE_CONTROLLER = true;
|
public static boolean AUTO_ACTIVATE_CONTROLLER = false;
|
||||||
|
|
||||||
@Getter @Setter private static String ipAddr = "192.168.0.35"; // @Maschell, you're welcome
|
@Getter @Setter private static String ipAddr = "192.168.0.35"; // @Maschell, you're welcome
|
||||||
|
|
||||||
@ -88,6 +90,7 @@ public final class Settings {
|
|||||||
Settings.ipAddr = prop.getProperty("ipAddr");
|
Settings.ipAddr = prop.getProperty("ipAddr");
|
||||||
String autoActivatingControllerString = prop.getProperty("autoActivatingController");
|
String autoActivatingControllerString = prop.getProperty("autoActivatingController");
|
||||||
String sendDataOnlyOnChanges = prop.getProperty("sendDataOnlyOnChanges");
|
String sendDataOnlyOnChanges = prop.getProperty("sendDataOnlyOnChanges");
|
||||||
|
String scanAutomaticallyForControllers = prop.getProperty("scanAutomaticallyForControllers");
|
||||||
|
|
||||||
if (autoActivatingControllerString != null) { // We don't combine the if statements to keep the default value.
|
if (autoActivatingControllerString != null) { // We don't combine the if statements to keep the default value.
|
||||||
if ("true".equals(autoActivatingControllerString)) {
|
if ("true".equals(autoActivatingControllerString)) {
|
||||||
@ -103,6 +106,13 @@ public final class Settings {
|
|||||||
Settings.SEND_DATA_ONLY_ON_CHANGE = false;
|
Settings.SEND_DATA_ONLY_ON_CHANGE = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (scanAutomaticallyForControllers != null) { // We don't combine the if statements to keep the default value.
|
||||||
|
if ("true".equals(scanAutomaticallyForControllers)) {
|
||||||
|
Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS = true;
|
||||||
|
} else {
|
||||||
|
Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.info("Loaded config successfully!");
|
log.info("Loaded config successfully!");
|
||||||
}
|
}
|
||||||
@ -125,6 +135,7 @@ public final class Settings {
|
|||||||
prop.setProperty("ipAddr", Settings.ipAddr);
|
prop.setProperty("ipAddr", Settings.ipAddr);
|
||||||
prop.setProperty("autoActivatingController", Boolean.toString(Settings.AUTO_ACTIVATE_CONTROLLER));
|
prop.setProperty("autoActivatingController", Boolean.toString(Settings.AUTO_ACTIVATE_CONTROLLER));
|
||||||
prop.setProperty("sendDataOnlyOnChanges", Boolean.toString(Settings.SEND_DATA_ONLY_ON_CHANGE));
|
prop.setProperty("sendDataOnlyOnChanges", Boolean.toString(Settings.SEND_DATA_ONLY_ON_CHANGE));
|
||||||
|
prop.setProperty("scanAutomaticallyForControllers", Boolean.toString(Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FileOutputStream outStream = new FileOutputStream(configFile);
|
FileOutputStream outStream = new FileOutputStream(configFile);
|
||||||
|
Loading…
Reference in New Issue
Block a user