mirror of
https://github.com/Maschell/HIDtoVPADNetworkClient.git
synced 2024-11-22 05:59:16 +01:00
Merge pull request #9 from QuarkTheAwesome/untested_both_hid_libs
Adding an abstract HID-Layer to be able to use different HID-Implementations + various other fixes. "With this extra abstraction we can use two different HID-APIs. Currently we use purejavahidapi for Windows (supports more devices) and hid4java for OSX and Unix (hopefully better support). This will also enable the auto scanning for OSX and change some Debug messages. HIDTest should now also run (a bit better)."
This commit is contained in:
commit
2eaab5a211
9
pom.xml
9
pom.xml
@ -138,9 +138,14 @@
|
||||
<version>1eb4087</version> <!-- JXInput 0.7 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.Maschell</groupId>
|
||||
<groupId>com.github.QuarkTheAwesome</groupId>
|
||||
<artifactId>purejavahidapi</artifactId>
|
||||
<version>cbf0588</version>
|
||||
<version>3591b7e</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hid4java</groupId>
|
||||
<artifactId>hid4java</artifactId>
|
||||
<version>0.4.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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();
|
@ -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
|
||||
|
@ -23,6 +23,10 @@ package net.ash.HIDToVPADNetworkClient.exeption;
|
||||
|
||||
public class ControllerInitializationFailedException extends Exception {
|
||||
|
||||
public ControllerInitializationFailedException(String string) {
|
||||
super(string);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -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.addActionListener(new ActionListener() {
|
||||
|
||||
|
40
src/net/ash/HIDToVPADNetworkClient/hid/HidDevice.java
Normal file
40
src/net/ash/HIDToVPADNetworkClient/hid/HidDevice.java
Normal file
@ -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();
|
||||
|
||||
}
|
52
src/net/ash/HIDToVPADNetworkClient/hid/HidManager.java
Normal file
52
src/net/ash/HIDToVPADNetworkClient/hid/HidManager.java
Normal file
@ -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<HidDevice> 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;
|
||||
}
|
||||
}
|
@ -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<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); } }
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
public abstract HidDevice getDeviceByPath(String path) throws IOException;
|
||||
|
||||
public static List<HidDeviceInfo> getAttachedController() {
|
||||
List<HidDeviceInfo> connectedGamepads = new ArrayList<HidDeviceInfo>();
|
||||
public List<HidDevice> getAttachedController() {
|
||||
List<HidDevice> connectedGamepads = new ArrayList<HidDevice>();
|
||||
|
||||
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<HidDevice> enumerateDevices();
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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<HidDevice> enumerateDevices() {
|
||||
List<HidDevice> result = new ArrayList<HidDevice>();
|
||||
for (org.hid4java.HidDevice info : HidManager.getHidServices().getAttachedHidDevices()) {
|
||||
result.add(new Hid4JavaHidDevice(info));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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<HidDevice> enumerateDevices() {
|
||||
List<HidDevice> result = new ArrayList<HidDevice>();
|
||||
for (purejavahidapi.HidDeviceInfo info : PureJavaHidApi.enumerateDevices()) {
|
||||
result.add(new PureJavaHidDevice(info));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HidDevice getDeviceByPath(String path) throws IOException {
|
||||
List<purejavahidapi.HidDeviceInfo> 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;
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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<String, Controller> attachedControllers = new HashMap<String, Controller>();
|
||||
private static final Map<String, HidDeviceInfo> connectedDevicesInfo = new HashMap<String, HidDeviceInfo>();
|
||||
|
||||
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<String> toRemove = new ArrayList<String>();
|
||||
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<String, ControllerType> detectHIDDevices() {
|
||||
Map<String, ControllerType> connectedDevices = new HashMap<String, ControllerType>();
|
||||
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<String, ControllerType> detectWindowsControllers() {
|
||||
private static Map<String, ControllerType> detectXInputControllers() {
|
||||
Map<String, ControllerType> result = new HashMap<String, ControllerType>();
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user