diff --git a/pom.xml b/pom.xml index 8a9a7c0..5a1aa59 100644 --- a/pom.xml +++ b/pom.xml @@ -138,9 +138,14 @@ 1eb4087 - com.github.Maschell + com.github.QuarkTheAwesome purejavahidapi - cbf0588 + 3591b7e + + + org.hid4java + hid4java + 0.4.0 diff --git a/src/net/ash/HIDToVPADNetworkClient/Main.java b/src/net/ash/HIDToVPADNetworkClient/Main.java index 5b5cf7c..45cad29 100644 --- a/src/net/ash/HIDToVPADNetworkClient/Main.java +++ b/src/net/ash/HIDToVPADNetworkClient/Main.java @@ -37,8 +37,8 @@ public final class Main { public static void main(String[] args) { Settings.loadSettings(); try { - new Thread(ActiveControllerManager.getInstance()).start(); - new Thread(NetworkManager.getInstance()).start(); + new Thread(ActiveControllerManager.getInstance(), "ActiveControllerManager").start(); + new Thread(NetworkManager.getInstance(), "NetworkManager").start(); } catch (Exception e) { e.printStackTrace(); fatal(); diff --git a/src/net/ash/HIDToVPADNetworkClient/controller/Controller.java b/src/net/ash/HIDToVPADNetworkClient/controller/Controller.java index 4792971..af5d1e5 100644 --- a/src/net/ash/HIDToVPADNetworkClient/controller/Controller.java +++ b/src/net/ash/HIDToVPADNetworkClient/controller/Controller.java @@ -21,6 +21,8 @@ *******************************************************************************/ package net.ash.HIDToVPADNetworkClient.controller; +import java.util.Arrays; + import lombok.Getter; import lombok.Synchronized; import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException; @@ -41,6 +43,8 @@ public abstract class Controller implements Runnable { @Getter private final String identifier; private byte[] latestData = null; + protected int MAX_PACKET_LENGTH = 64; + boolean shutdown = false; boolean shutdownDone = false; private final Object dataLock = new Object(); @@ -54,7 +58,7 @@ public abstract class Controller implements Runnable { this.type = type; this.identifier = identifier; if (!initController(identifier)) { - throw new ControllerInitializationFailedException(); + throw new ControllerInitializationFailedException("Initialization failed"); } } @@ -62,14 +66,18 @@ public abstract class Controller implements Runnable { public void run() { boolean shutdownState = shutdown; while (!shutdownState) { - Utilities.sleep(Settings.DETECT_CONTROLLER_INTERVAL); while (isActive()) { byte[] newData = pollLatestData(); if (newData != null && newData.length != 0) { + if (newData.length > MAX_PACKET_LENGTH) { + newData = Arrays.copyOfRange(newData, 0, MAX_PACKET_LENGTH); + } + // System.out.println("data:" + Utilities.ByteArrayToString(newData)); setLatestData(newData); } doSleepAfterPollingData(); } + Utilities.sleep(Settings.DETECT_CONTROLLER_ACTIVE_INTERVAL); synchronized (shutdownLock) { shutdownState = shutdown; } @@ -202,7 +210,7 @@ public abstract class Controller implements Runnable { } public enum ControllerType { - PureJAVAHid, LINUX, XINPUT13, XINPUT14 + HIDController, LINUX, XINPUT13, XINPUT14 } public abstract String getInfoText(); diff --git a/src/net/ash/HIDToVPADNetworkClient/controller/DS4NewController.java b/src/net/ash/HIDToVPADNetworkClient/controller/DS4NewController.java index 22b1f8c..e4aa4c4 100644 --- a/src/net/ash/HIDToVPADNetworkClient/controller/DS4NewController.java +++ b/src/net/ash/HIDToVPADNetworkClient/controller/DS4NewController.java @@ -5,26 +5,27 @@ import java.util.Arrays; import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException; import net.ash.HIDToVPADNetworkClient.util.Settings; -public class DS4NewController extends PureJavaHidController { +public class DS4NewController extends HidController { public static final short DS4_NEW_CONTROLLER_VID = 0x54C; public static final short DS4_NEW_CONTROLLER_PID = 0x09CC; public DS4NewController(String identifier) throws ControllerInitializationFailedException { super(identifier); if (Settings.isMacOSX()) { - this.PACKET_LENGTH = 7; + this.MAX_PACKET_LENGTH = 7; } else { - this.PACKET_LENGTH = 6; + this.MAX_PACKET_LENGTH = 6; } } @Override 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); + byte[] currentData = super.pollLatestData(); + if (Settings.isMacOSX() && currentData != null && currentData.length > 6) { // for some reason the controller has one extra byte at the beginning under + // OSX + currentData = Arrays.copyOfRange(currentData, 1, 7); } - - return currentData.clone(); + return currentData; } @Override diff --git a/src/net/ash/HIDToVPADNetworkClient/controller/PureJavaHidController.java b/src/net/ash/HIDToVPADNetworkClient/controller/HidController.java similarity index 67% rename from src/net/ash/HIDToVPADNetworkClient/controller/PureJavaHidController.java rename to src/net/ash/HIDToVPADNetworkClient/controller/HidController.java index 57c2523..c753d18 100644 --- a/src/net/ash/HIDToVPADNetworkClient/controller/PureJavaHidController.java +++ b/src/net/ash/HIDToVPADNetworkClient/controller/HidController.java @@ -22,63 +22,54 @@ package net.ash.HIDToVPADNetworkClient.controller; import java.io.IOException; -import java.util.Arrays; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; -import lombok.Synchronized; import lombok.extern.java.Log; import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException; -import net.ash.HIDToVPADNetworkClient.util.PureJavaHidApiManager; -import purejavahidapi.HidDevice; -import purejavahidapi.InputReportListener; +import net.ash.HIDToVPADNetworkClient.hid.HidDevice; +import net.ash.HIDToVPADNetworkClient.hid.HidManager; @Log -public class PureJavaHidController extends Controller implements InputReportListener { - private final Object dataLock = new Object(); - protected byte[] currentData = new byte[1]; - - protected int PACKET_LENGTH = 64; - +public class HidController extends Controller { @Getter @Setter(AccessLevel.PRIVATE) private HidDevice hidDevice; public static Controller getInstance(String deviceIdentifier) throws IOException, ControllerInitializationFailedException { - HidDevice device = PureJavaHidApiManager.getDeviceByPath(deviceIdentifier); + + HidDevice device = HidManager.getDeviceByPath(deviceIdentifier); short vid = 0; short pid = 0; if (device != null) { - vid = device.getHidDeviceInfo().getVendorId(); - pid = device.getHidDeviceInfo().getProductId(); - device.close(); + vid = device.getVendorId(); + pid = device.getProductId(); } // We use a special version to optimize the data for the switch pro controller if (vid == SwitchProController.SWITCH_PRO_CONTROLLER_VID && pid == SwitchProController.SWITCH_PRO_CONTROLLER_PID) { - return new SwitchProController(deviceIdentifier); } else if (vid == DS4NewController.DS4_NEW_CONTROLLER_VID && pid == DS4NewController.DS4_NEW_CONTROLLER_PID) { return new DS4NewController(deviceIdentifier); } else { - return new PureJavaHidController(deviceIdentifier); + return new HidController(deviceIdentifier); } } - public PureJavaHidController(String identifier) throws ControllerInitializationFailedException { - super(ControllerType.PureJAVAHid, identifier); + public HidController(String identifier) throws ControllerInitializationFailedException { + super(ControllerType.HIDController, identifier); } @Override public boolean initController(String identifier) { - HidDevice device; try { - device = PureJavaHidApiManager.getDeviceByPath(identifier); - if (device == null) { + HidDevice device = HidManager.getDeviceByPath(identifier); + + if (device == null || !device.open()) { return false; } + log.info("HidDevice opened!"); - device.setInputReportListener(this); setHidDevice(device); return true; @@ -89,9 +80,9 @@ public class PureJavaHidController extends Controller implements InputReportList } @Override - @Synchronized("dataLock") public byte[] pollLatestData() { - return currentData.clone(); + byte[] result = hidDevice.getLatestData(); + return result; } @Override @@ -105,34 +96,21 @@ public class PureJavaHidController extends Controller implements InputReportList throw e; } } - } @Override public short getVID() { - return getHidDevice().getHidDeviceInfo().getVendorId(); + return getHidDevice().getVendorId(); } @Override public short getPID() { - return getHidDevice().getHidDeviceInfo().getProductId(); - } - - @Override - @Synchronized("dataLock") - public void onInputReport(HidDevice source, byte reportID, byte[] reportData, int reportLength) { - if (isActive()) { - int length = PACKET_LENGTH; - if (reportLength < length) { - length = reportLength; - } - currentData = Arrays.copyOfRange(reportData, 0, length); - } + return getHidDevice().getProductId(); } @Override public String getInfoText() { - // TODO: + // TODO: own class for joycons if (getVID() == 0x57e) { if (getPID() == 0x2006) { return "Joy-Con (L) on " + getIdentifier(); diff --git a/src/net/ash/HIDToVPADNetworkClient/controller/SwitchProController.java b/src/net/ash/HIDToVPADNetworkClient/controller/SwitchProController.java index d1a6842..bc606b7 100644 --- a/src/net/ash/HIDToVPADNetworkClient/controller/SwitchProController.java +++ b/src/net/ash/HIDToVPADNetworkClient/controller/SwitchProController.java @@ -23,18 +23,19 @@ package net.ash.HIDToVPADNetworkClient.controller; import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException; -public class SwitchProController extends PureJavaHidController { +public class SwitchProController extends HidController { public static final short SWITCH_PRO_CONTROLLER_VID = 0x57e; public static final short SWITCH_PRO_CONTROLLER_PID = 0x2009; public SwitchProController(String identifier) throws ControllerInitializationFailedException { super(identifier); // truncate package to 11; - this.PACKET_LENGTH = 11; + this.MAX_PACKET_LENGTH = 11; } @Override public byte[] pollLatestData() { + byte[] currentData = super.pollLatestData(); if (currentData == null || currentData.length < 10) { return new byte[0]; } @@ -43,7 +44,7 @@ public class SwitchProController extends PureJavaHidController { currentData[5] = 0; currentData[7] = 0; currentData[9] = 0; - return currentData.clone(); + return currentData; } @Override diff --git a/src/net/ash/HIDToVPADNetworkClient/exeption/ControllerInitializationFailedException.java b/src/net/ash/HIDToVPADNetworkClient/exeption/ControllerInitializationFailedException.java index bc09711..15ebd7d 100644 --- a/src/net/ash/HIDToVPADNetworkClient/exeption/ControllerInitializationFailedException.java +++ b/src/net/ash/HIDToVPADNetworkClient/exeption/ControllerInitializationFailedException.java @@ -23,6 +23,10 @@ package net.ash.HIDToVPADNetworkClient.exeption; public class ControllerInitializationFailedException extends Exception { + public ControllerInitializationFailedException(String string) { + super(string); + } + /** * */ diff --git a/src/net/ash/HIDToVPADNetworkClient/gui/GuiInputControls.java b/src/net/ash/HIDToVPADNetworkClient/gui/GuiInputControls.java index e8b2067..dccbfdc 100644 --- a/src/net/ash/HIDToVPADNetworkClient/gui/GuiInputControls.java +++ b/src/net/ash/HIDToVPADNetworkClient/gui/GuiInputControls.java @@ -61,11 +61,7 @@ public final class GuiInputControls extends JPanel { 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.setSelected(Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS); cbautoScanForController.addActionListener(new ActionListener() { diff --git a/src/net/ash/HIDToVPADNetworkClient/hid/HidDevice.java b/src/net/ash/HIDToVPADNetworkClient/hid/HidDevice.java new file mode 100644 index 0000000..15391de --- /dev/null +++ b/src/net/ash/HIDToVPADNetworkClient/hid/HidDevice.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2017 Ash (QuarkTheAwesome) & Maschell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *******************************************************************************/ +package net.ash.HIDToVPADNetworkClient.hid; + +public interface HidDevice { + + short getVendorId(); + + short getProductId(); + + void close(); + + byte[] getLatestData(); + + short getUsage(); + + String getPath(); + + boolean open(); + +} diff --git a/src/net/ash/HIDToVPADNetworkClient/hid/HidManager.java b/src/net/ash/HIDToVPADNetworkClient/hid/HidManager.java new file mode 100644 index 0000000..92adccc --- /dev/null +++ b/src/net/ash/HIDToVPADNetworkClient/hid/HidManager.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2017 Ash (QuarkTheAwesome) & Maschell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *******************************************************************************/ +package net.ash.HIDToVPADNetworkClient.hid; + +import java.io.IOException; +import java.util.List; + +import net.ash.HIDToVPADNetworkClient.hid.hid4java.Hid4JavaHidManagerBackend; +import net.ash.HIDToVPADNetworkClient.hid.purejavahid.PureJavaHidManagerBackend; +import net.ash.HIDToVPADNetworkClient.util.Settings; + +public class HidManager { + private final static HidManagerBackend backend; + + public static List getAttachedController() { + return backend.getAttachedController(); + } + + public static HidDevice getDeviceByPath(String path) throws IOException { + return backend.getDeviceByPath(path); + } + + static { + if (Settings.isMacOSX()) { + backend = new Hid4JavaHidManagerBackend(); + } else if (Settings.isWindows()) { + backend = new PureJavaHidManagerBackend(); + } else if (Settings.isLinux()) { + backend = new Hid4JavaHidManagerBackend(); + } else + backend = null; + } +} diff --git a/src/net/ash/HIDToVPADNetworkClient/util/PureJavaHidApiManager.java b/src/net/ash/HIDToVPADNetworkClient/hid/HidManagerBackend.java similarity index 59% rename from src/net/ash/HIDToVPADNetworkClient/util/PureJavaHidApiManager.java rename to src/net/ash/HIDToVPADNetworkClient/hid/HidManagerBackend.java index 78fad0e..e1cef57 100644 --- a/src/net/ash/HIDToVPADNetworkClient/util/PureJavaHidApiManager.java +++ b/src/net/ash/HIDToVPADNetworkClient/hid/HidManagerBackend.java @@ -19,22 +19,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *******************************************************************************/ -package net.ash.HIDToVPADNetworkClient.util; +package net.ash.HIDToVPADNetworkClient.hid; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import net.ash.HIDToVPADNetworkClient.manager.ControllerManager; -import purejavahidapi.HidDevice; -import purejavahidapi.HidDeviceInfo; -import purejavahidapi.PureJavaHidApi; - -public final class PureJavaHidApiManager { - - private PureJavaHidApiManager() { - } +import net.ash.HIDToVPADNetworkClient.util.Settings; +public abstract class HidManagerBackend { /** * Searches the corresponding HIDDevice for the given path * @@ -43,25 +36,12 @@ public final class PureJavaHidApiManager { * @return It the device is found, it will be returned. Otherwise null is returned. * @throws IOException */ - public static HidDevice getDeviceByPath(String path) throws IOException { - HidDeviceInfo deviceinfo = ControllerManager.getDeviceInfoByPath(path); - if (deviceinfo != null) { - HidDevice result = PureJavaHidApi.openDevice(deviceinfo); - if (result != null) { - return result; - } - } - /* - * List devList = PureJavaHidApi.enumerateDevices(); HidDevice result = null; for (HidDeviceInfo info : devList) { String real_path = - * info.getPath(); if (real_path.equals(path)) { return PureJavaHidApi.openDevice(info); } } - */ - return null; - } + public abstract HidDevice getDeviceByPath(String path) throws IOException; - public static List getAttachedController() { - List connectedGamepads = new ArrayList(); + public List getAttachedController() { + List connectedGamepads = new ArrayList(); - for (HidDeviceInfo info : PureJavaHidApi.enumerateDevices()) { + for (HidDevice info : enumerateDevices()) { if (isGamepad(info)) { // Skip Xbox controller under windows. We should use XInput instead. if (isXboxController(info) && Settings.isWindows()) { @@ -73,24 +53,26 @@ public final class PureJavaHidApiManager { return connectedGamepads; } - public static boolean isGamepad(HidDeviceInfo info) { + public static boolean isGamepad(HidDevice info) { if (info == null) return false; - short usagePage = info.getUsagePage(); - return (usagePage == 0x05 || usagePage == 0x01 || usagePage == 0x04 || isNintendoController(info) || isPlaystationController(info)); + short usage = info.getUsage(); + return (usage == 0x05 || usage == 0x04 || isNintendoController(info) || isPlaystationController(info)); } - private static boolean isPlaystationController(HidDeviceInfo info) { + private static boolean isPlaystationController(HidDevice info) { if (info == null) return false; return (info.getVendorId() == 0x054c); } - private static boolean isNintendoController(HidDeviceInfo info) { + private static boolean isNintendoController(HidDevice info) { if (info == null) return false; return (info.getVendorId() == 0x57e); } - private static boolean isXboxController(HidDeviceInfo info) { + private static boolean isXboxController(HidDevice info) { if (info == null) return false; return (info.getVendorId() == 0x045e) && ((info.getProductId() == 0x02ff) || (info.getProductId() == 0x02a1)); } + + public abstract List enumerateDevices(); } diff --git a/src/net/ash/HIDToVPADNetworkClient/hid/hid4java/Hid4JavaHidDevice.java b/src/net/ash/HIDToVPADNetworkClient/hid/hid4java/Hid4JavaHidDevice.java new file mode 100644 index 0000000..9d9c661 --- /dev/null +++ b/src/net/ash/HIDToVPADNetworkClient/hid/hid4java/Hid4JavaHidDevice.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2017 Ash (QuarkTheAwesome) & Maschell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *******************************************************************************/ +package net.ash.HIDToVPADNetworkClient.hid.hid4java; + +import java.util.Arrays; + +import net.ash.HIDToVPADNetworkClient.hid.HidDevice; + +class Hid4JavaHidDevice implements HidDevice { + private org.hid4java.HidDevice myDevice; + + private final byte[] data = new byte[64]; + + public Hid4JavaHidDevice(org.hid4java.HidDevice device) { + this.myDevice = device; + } + + @Override + public boolean open() { + return myDevice.open(); + } + + @Override + public void close() { + myDevice.close(); + } + + @Override + public short getVendorId() { + return myDevice.getVendorId(); + } + + @Override + public short getProductId() { + return myDevice.getProductId(); + } + + @Override + public byte[] getLatestData() { + int length = myDevice.read(data); + if (length <= 0) return new byte[0]; + return Arrays.copyOf(data, length); + } + + @Override + public String getPath() { + return myDevice.getPath(); + } + + @Override + public String toString() { + return "Hid4JavaHidDevice [myDevice=" + myDevice + ", data=" + Arrays.toString(data) + "]"; + } + + @Override + public short getUsage() { + return (short) myDevice.getUsage(); + } +} diff --git a/src/net/ash/HIDToVPADNetworkClient/hid/hid4java/Hid4JavaHidManagerBackend.java b/src/net/ash/HIDToVPADNetworkClient/hid/hid4java/Hid4JavaHidManagerBackend.java new file mode 100644 index 0000000..d1dd1fe --- /dev/null +++ b/src/net/ash/HIDToVPADNetworkClient/hid/hid4java/Hid4JavaHidManagerBackend.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2017 Ash (QuarkTheAwesome) & Maschell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *******************************************************************************/ +package net.ash.HIDToVPADNetworkClient.hid.hid4java; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.hid4java.HidManager; +import org.hid4java.HidServices; + +import net.ash.HIDToVPADNetworkClient.hid.HidDevice; +import net.ash.HIDToVPADNetworkClient.hid.HidManagerBackend; + +public class Hid4JavaHidManagerBackend extends HidManagerBackend { + + @Override + public HidDevice getDeviceByPath(String path) throws IOException { + HidDevice result = null; + HidServices services = HidManager.getHidServices(); + if (services == null) return result; + + for (org.hid4java.HidDevice device : services.getAttachedHidDevices()) { + if (device.getPath().equals(path)) { + result = new Hid4JavaHidDevice(device); + break; + } + } + return result; + } + + @Override + public List enumerateDevices() { + List result = new ArrayList(); + for (org.hid4java.HidDevice info : HidManager.getHidServices().getAttachedHidDevices()) { + result.add(new Hid4JavaHidDevice(info)); + } + return result; + } + +} diff --git a/src/net/ash/HIDToVPADNetworkClient/hid/purejavahid/PureJavaHidDevice.java b/src/net/ash/HIDToVPADNetworkClient/hid/purejavahid/PureJavaHidDevice.java new file mode 100644 index 0000000..c7b28a6 --- /dev/null +++ b/src/net/ash/HIDToVPADNetworkClient/hid/purejavahid/PureJavaHidDevice.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2017 Ash (QuarkTheAwesome) & Maschell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *******************************************************************************/ +package net.ash.HIDToVPADNetworkClient.hid.purejavahid; + +import java.io.IOException; +import java.util.Arrays; + +import lombok.Synchronized; +import net.ash.HIDToVPADNetworkClient.hid.HidDevice; +import purejavahidapi.HidDeviceInfo; +import purejavahidapi.InputReportListener; + +class PureJavaHidDevice implements HidDevice, InputReportListener { + private purejavahidapi.HidDevice myDevice = null; + private final purejavahidapi.HidDeviceInfo myDeviceInfo; + + private final Object dataLock = new Object(); + protected byte[] currentData = new byte[1]; + + public PureJavaHidDevice(HidDeviceInfo info) { + this.myDeviceInfo = info; + } + + @Override + @Synchronized("dataLock") + public void onInputReport(purejavahidapi.HidDevice source, byte reportID, byte[] reportData, int reportLength) { + currentData = Arrays.copyOfRange(reportData, 0, reportLength); + } + + @Override + public short getVendorId() { + return myDeviceInfo.getVendorId(); + } + + @Override + public short getProductId() { + return myDeviceInfo.getProductId(); + } + + @Override + public boolean open() { + boolean result = true; + try { + myDevice = purejavahidapi.PureJavaHidApi.openDevice(myDeviceInfo); + myDevice.setInputReportListener(this); + } catch (IOException e) { + result = false; + e.printStackTrace(); + } + return result; + } + + @Override + public void close() { + myDevice.close(); + } + + @Override + @Synchronized("dataLock") + public byte[] getLatestData() { + return currentData.clone(); + } + + @Override + public short getUsage() { + return myDeviceInfo.getUsagePage(); + } + + @Override + public String getPath() { + return myDeviceInfo.getPath(); + } +} diff --git a/src/net/ash/HIDToVPADNetworkClient/hid/purejavahid/PureJavaHidManagerBackend.java b/src/net/ash/HIDToVPADNetworkClient/hid/purejavahid/PureJavaHidManagerBackend.java new file mode 100644 index 0000000..32e4989 --- /dev/null +++ b/src/net/ash/HIDToVPADNetworkClient/hid/purejavahid/PureJavaHidManagerBackend.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2017 Ash (QuarkTheAwesome) & Maschell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *******************************************************************************/ +package net.ash.HIDToVPADNetworkClient.hid.purejavahid; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import net.ash.HIDToVPADNetworkClient.hid.HidDevice; +import net.ash.HIDToVPADNetworkClient.hid.HidManagerBackend; +import purejavahidapi.PureJavaHidApi; + +public class PureJavaHidManagerBackend extends HidManagerBackend { + + @Override + public List enumerateDevices() { + List result = new ArrayList(); + for (purejavahidapi.HidDeviceInfo info : PureJavaHidApi.enumerateDevices()) { + result.add(new PureJavaHidDevice(info)); + } + return result; + } + + @Override + public HidDevice getDeviceByPath(String path) throws IOException { + List devList = PureJavaHidApi.enumerateDevices(); + HidDevice result = null; + for (purejavahidapi.HidDeviceInfo info : devList) { + String real_path = info.getPath(); + if (real_path.equals(path)) { + return new PureJavaHidDevice(info); + } + } + + return result; + } +} diff --git a/src/net/ash/HIDToVPADNetworkClient/manager/ActiveControllerManager.java b/src/net/ash/HIDToVPADNetworkClient/manager/ActiveControllerManager.java index 85acf31..e57cd4a 100644 --- a/src/net/ash/HIDToVPADNetworkClient/manager/ActiveControllerManager.java +++ b/src/net/ash/HIDToVPADNetworkClient/manager/ActiveControllerManager.java @@ -61,7 +61,7 @@ public final class ActiveControllerManager implements Runnable { Utilities.sleep(Settings.DETECT_CONTROLLER_INTERVAL); } } - }).start(); + }, "DetectControllerThread").start(); new Thread(new Runnable() { @Override @@ -71,7 +71,7 @@ public final class ActiveControllerManager implements Runnable { Utilities.sleep(Settings.HANDLE_INPUTS_INTERVAL); } } - }).start(); + }, "HandleControllerInputThread").start(); } public void updateControllerStates() { diff --git a/src/net/ash/HIDToVPADNetworkClient/manager/ControllerManager.java b/src/net/ash/HIDToVPADNetworkClient/manager/ControllerManager.java index eb28953..246f963 100644 --- a/src/net/ash/HIDToVPADNetworkClient/manager/ControllerManager.java +++ b/src/net/ash/HIDToVPADNetworkClient/manager/ControllerManager.java @@ -38,22 +38,21 @@ import lombok.Synchronized; import lombok.extern.java.Log; import net.ash.HIDToVPADNetworkClient.controller.Controller; import net.ash.HIDToVPADNetworkClient.controller.Controller.ControllerType; +import net.ash.HIDToVPADNetworkClient.controller.HidController; import net.ash.HIDToVPADNetworkClient.controller.LinuxDevInputController; -import net.ash.HIDToVPADNetworkClient.controller.PureJavaHidController; import net.ash.HIDToVPADNetworkClient.controller.XInput13Controller; import net.ash.HIDToVPADNetworkClient.controller.XInput14Controller; import net.ash.HIDToVPADNetworkClient.controller.XInputController; import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException; +import net.ash.HIDToVPADNetworkClient.hid.HidDevice; +import net.ash.HIDToVPADNetworkClient.hid.HidManager; import net.ash.HIDToVPADNetworkClient.util.MessageBox; import net.ash.HIDToVPADNetworkClient.util.MessageBoxManager; -import net.ash.HIDToVPADNetworkClient.util.PureJavaHidApiManager; import net.ash.HIDToVPADNetworkClient.util.Settings; -import purejavahidapi.HidDeviceInfo; @Log public final class ControllerManager { private static final Map attachedControllers = new HashMap(); - private static final Map connectedDevicesInfo = new HashMap(); private static boolean threwUnsatisfiedLinkError = false; @@ -71,7 +70,7 @@ public final class ControllerManager { if (Settings.isLinux()) { connectedDevices.putAll(detectLinuxControllers()); } else if (Settings.isWindows()) { - connectedDevices.putAll(detectWindowsControllers()); + connectedDevices.putAll(detectXInputControllers()); } connectedDevices.putAll(detectHIDDevices()); @@ -80,7 +79,6 @@ public final class ControllerManager { List toRemove = new ArrayList(); synchronized (attachedControllers) { for (String s : attachedControllers.keySet()) { - System.out.println(s); if (!connectedDevices.containsKey(s)) { toRemove.add(s); } @@ -91,6 +89,7 @@ public final class ControllerManager { synchronized (attachedControllers) { attachedControllers.get(remove).destroyAll(); attachedControllers.remove(remove); + log.info("Device removed: " + toRemove); } } @@ -104,11 +103,11 @@ public final class ControllerManager { if (!contains) { Controller c = null; switch (entry.getValue()) { - case PureJAVAHid: + case HIDController: try { - c = PureJavaHidController.getInstance(deviceIdentifier); + c = HidController.getInstance(deviceIdentifier); } catch (ControllerInitializationFailedException e) { - // e.printStackTrace(); + log.info(e.getMessage()); } catch (IOException e) { e.printStackTrace(); } @@ -117,14 +116,14 @@ public final class ControllerManager { try { c = new LinuxDevInputController(deviceIdentifier); } catch (ControllerInitializationFailedException e) { - // e.printStackTrace(); + log.info(e.getMessage()); } break; case XINPUT14: try { c = new XInput14Controller(deviceIdentifier); } catch (ControllerInitializationFailedException e) { - // e.printStackTrace(); + log.info(e.getMessage()); } break; case XINPUT13: @@ -141,10 +140,11 @@ public final class ControllerManager { if (Settings.AUTO_ACTIVATE_CONTROLLER) { c.setActive(true); } - new Thread(c).start(); + new Thread(c, "Controller Thread " + deviceIdentifier).start(); synchronized (attachedControllers) { attachedControllers.put(deviceIdentifier, c); } + log.info("Device added: " + deviceIdentifier); } } } @@ -157,19 +157,15 @@ public final class ControllerManager { private static Map detectHIDDevices() { Map connectedDevices = new HashMap(); - System.out.println("detectHIDDevices"); - for (HidDeviceInfo info : PureJavaHidApiManager.getAttachedController()) { + for (HidDevice info : HidManager.getAttachedController()) { String path = info.getPath(); - connectedDevices.put(path, ControllerType.PureJAVAHid); - synchronized (connectedDevicesInfo) { - connectedDevicesInfo.put(path, info); - } + connectedDevices.put(path, ControllerType.HIDController); } return connectedDevices; } - private static Map detectWindowsControllers() { + private static Map detectXInputControllers() { Map result = new HashMap(); ControllerType type = ControllerType.XINPUT13; @@ -245,10 +241,4 @@ public final class ControllerManager { c.setActive(false); } } - - @Synchronized("connectedDevicesInfo") - public static HidDeviceInfo getDeviceInfoByPath(String path) { - return connectedDevicesInfo.get(path); - } - } diff --git a/src/net/ash/HIDToVPADNetworkClient/network/NetworkManager.java b/src/net/ash/HIDToVPADNetworkClient/network/NetworkManager.java index 595d674..a26c0c8 100644 --- a/src/net/ash/HIDToVPADNetworkClient/network/NetworkManager.java +++ b/src/net/ash/HIDToVPADNetworkClient/network/NetworkManager.java @@ -157,17 +157,17 @@ public final class NetworkManager implements Runnable { } } - // TODO: PONG from WiiU? Hey Quark ;) private void sendPing(PingCommand command) { if (sendTCP(Protocol.getRawPingDataToSend(command))) { - log.info("PING"); byte pong; try { pong = tcpClient.recvByte(); - if (pong != Protocol.TCP_CMD_PONG) { + if (pong == Protocol.TCP_CMD_PONG) { + log.info("Ping...Pong!"); + } else { + log.info("Got no valid response to a Ping. Disconnecting."); disconnect(); } - log.info("got PONG!"); } catch (IOException e) { log.info("Failed to get PONG. Disconnecting."); tcpClient.checkShouldRetry(); diff --git a/src/net/ash/HIDToVPADNetworkClient/util/MessageBoxManager.java b/src/net/ash/HIDToVPADNetworkClient/util/MessageBoxManager.java index b430582..8fa7026 100644 --- a/src/net/ash/HIDToVPADNetworkClient/util/MessageBoxManager.java +++ b/src/net/ash/HIDToVPADNetworkClient/util/MessageBoxManager.java @@ -73,7 +73,7 @@ public final class MessageBoxManager implements Runnable { public static void addMessageBoxListener(MessageBoxListener msglistener) { if (!threadStarted) { - new Thread(instance).start(); + new Thread(instance, "MessageBoxManager").start(); threadStarted = true; } newList.add(msglistener); diff --git a/src/net/ash/HIDToVPADNetworkClient/util/Settings.java b/src/net/ash/HIDToVPADNetworkClient/util/Settings.java index f1a0b58..fec12c0 100644 --- a/src/net/ash/HIDToVPADNetworkClient/util/Settings.java +++ b/src/net/ash/HIDToVPADNetworkClient/util/Settings.java @@ -44,7 +44,9 @@ public final class Settings { public static final int PING_INTERVAL = 1000; public static final int PROCESS_CMD_INTERVAL = 10; - public static boolean SCAN_AUTOMATICALLY_FOR_CONTROLLERS = !isMacOSX(); // It doesn't work on OSX + public static final int DETECT_CONTROLLER_ACTIVE_INTERVAL = 100; + + public static boolean SCAN_AUTOMATICALLY_FOR_CONTROLLERS = true; public static boolean DEBUG_UDP_OUTPUT = false; public static boolean SEND_DATA_ONLY_ON_CHANGE = false;