First commit

This commit is contained in:
Maschell 2017-04-23 13:25:43 +02:00
parent 70b5da2206
commit a7575238e1
9 changed files with 260 additions and 36 deletions

View File

@ -137,15 +137,20 @@
<artifactId>jxinput</artifactId>
<version>1eb4087</version> <!-- JXInput 0.7 -->
</dependency>
<dependency>
<!-- <dependency>
<groupId>com.github.QuarkTheAwesome</groupId>
<artifactId>purejavahidapi</artifactId>
<version>f877704</version>
</dependency>
</dependency> -->
<dependency>
<groupId>org.hid4java</groupId>
<artifactId>hid4java</artifactId>
<version>0.4.0</version>
</dependency>
<dependency>
<groupId>purejavahidapi</groupId>
<artifactId>purejavahidapi</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
</project>

View File

@ -2,8 +2,10 @@ package net.ash.HIDToVPADNetworkClient.controller;
import java.util.Arrays;
import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException;
import net.ash.HIDToVPADNetworkClient.util.Settings;
import net.ash.HIDToVPADNetworkClient.util.Utilities;
public class DS4NewController extends HidController {
public static final short DS4_NEW_CONTROLLER_VID = 0x54C;
@ -11,18 +13,13 @@ public class DS4NewController extends HidController {
public DS4NewController(String identifier) throws ControllerInitializationFailedException {
super(identifier);
if (Settings.isMacOSX()) {
this.MAX_PACKET_LENGTH = 7;
} else {
this.MAX_PACKET_LENGTH = 6;
}
this.MAX_PACKET_LENGTH = 7;
}
@Override
public byte[] pollLatestData() {
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
if(currentData.length >= 7){
currentData = Arrays.copyOfRange(currentData, 1, 7);
}
return currentData;

View File

@ -33,7 +33,8 @@ import net.ash.HIDToVPADNetworkClient.hid.HidManager;
@Log
public class HidController extends Controller {
@Getter @Setter(AccessLevel.PRIVATE) private HidDevice hidDevice;
@Getter @Setter(AccessLevel.PRIVATE)
protected HidDevice hidDevice;
public static Controller getInstance(String deviceIdentifier) throws IOException, ControllerInitializationFailedException {
@ -68,6 +69,8 @@ public class HidController extends Controller {
if (device == null || !device.open()) {
return false;
}
log.info("HidDevice opened!");
setHidDevice(device);

View File

@ -21,32 +21,209 @@
*******************************************************************************/
package net.ash.HIDToVPADNetworkClient.controller;
import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import lombok.extern.java.Log;
import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException;
import net.ash.HIDToVPADNetworkClient.manager.ActiveControllerManager;
import net.ash.HIDToVPADNetworkClient.manager.ControllerManager;
import net.ash.HIDToVPADNetworkClient.util.MessageBoxManager;
import net.ash.HIDToVPADNetworkClient.util.Utilities;
import purejavahidapi.linux.UdevLibrary.hidraw_report_descriptor;
@Log
public class SwitchProController extends HidController {
public static final short SWITCH_PRO_CONTROLLER_VID = 0x57e;
public static final short SWITCH_PRO_CONTROLLER_PID = 0x2009;
private static final int SWITCH_PRO_USB_BUTTON_A = 0x08000000;
private static final int SWITCH_PRO_USB_BUTTON_B = 0x04000000;
private static final int SWITCH_PRO_USB_BUTTON_X = 0x02000000;
private static final int SWITCH_PRO_USB_BUTTON_Y = 0x01000000;
private static final int SWITCH_PRO_USB_BUTTON_PLUS = 0x00020000;
private static final int SWITCH_PRO_USB_BUTTON_MINUS = 0x00010000;
private static final int SWITCH_PRO_USB_BUTTON_HOME = 0x00100000;
private static final int SWITCH_PRO_USB_BUTTON_SCREENSHOT = 0x00200000;
private static final int SWITCH_PRO_USB_BUTTON_R = 0x40000000;
private static final int SWITCH_PRO_USB_BUTTON_ZR = 0x80000000;
private static final int SWITCH_PRO_USB_BUTTON_STICK_R = 0x00040000;
private static final int SWITCH_PRO_USB_BUTTON_L = 0x00004000;
private static final int SWITCH_PRO_USB_BUTTON_ZL = 0x00008000;
private static final int SWITCH_PRO_USB_BUTTON_STICK_L = 0x00080000;
private static final byte SWITCH_PRO_USB_BUTTON_LEFT_VALUE = 0x08;
private static final byte SWITCH_PRO_USB_BUTTON_RIGHT_VALUE = 0x04;
private static final byte SWITCH_PRO_USB_BUTTON_DOWN_VALUE = 0x01;
private static final byte SWITCH_PRO_USB_BUTTON_UP_VALUE = 0x02;
private static final int SWITCH_PRO_BT_BUTTON_A = 0x02000000;
private static final int SWITCH_PRO_BT_BUTTON_B = 0x01000000;
private static final int SWITCH_PRO_BT_BUTTON_X = 0x08000000;
private static final int SWITCH_PRO_BT_BUTTON_Y = 0x04000000;
private static final int SWITCH_PRO_BT_BUTTON_PLUS = 0x00020000;
private static final int SWITCH_PRO_BT_BUTTON_MINUS = 0x00010000;
private static final int SWITCH_PRO_BT_BUTTON_HOME = 0x00100000;
private static final int SWITCH_PRO_BT_BUTTON_R = 0x20000000;
private static final int SWITCH_PRO_BT_BUTTON_ZR = 0x80000000;
private static final int SWITCH_PRO_BT_BUTTON_STICK_R = 0x00080000;
private static final int SWITCH_PRO_BT_BUTTON_L = 0x10000000;
private static final int SWITCH_PRO_BT_BUTTON_ZL = 0x40000000;
private static final int SWITCH_PRO_BT_BUTTON_STICK_L = 0x00040000;
private static final byte SWITCH_PRO_BT_BUTTON_DPAD_N_VALUE = 0x00;
private static final byte SWITCH_PRO_BT_BUTTON_DPAD_NE_VALUE = 0x01;
private static final byte SWITCH_PRO_BT_BUTTON_DPAD_E_VALUE = 0x02;
private static final byte SWITCH_PRO_BT_BUTTON_DPAD_SE_VALUE = 0x03;
private static final byte SWITCH_PRO_BT_BUTTON_DPAD_S_VALUE = 0x04;
private static final byte SWITCH_PRO_BT_BUTTON_DPAD_SW_VALUE = 0x05;
private static final byte SWITCH_PRO_BT_BUTTON_DPAD_W_VALUE = 0x06;
private static final byte SWITCH_PRO_BT_BUTTON_DPAD_NW_VALUE = 0x07;
private static final byte SWITCH_PRO_BT_BUTTON_DPAD_NEUTRAL_VALUE = 0x08;
private static boolean isUSB = false;
private final byte[] CMD_readInput = new byte[]{(byte) 0x92,0x00,0x01,0x00,0x00,0x00,0x00,0x1F};
private final byte[] CMD_getMAC = new byte[]{0x01};
private final byte[] CMD_DO_HANDSHAKE = new byte[]{0x02};
private final byte[] CMD_SWITCH_BAUDRATE = new byte[]{0x03};
private final byte[] CMD_HID_ONLY = new byte[]{0x04};
public SwitchProController(String identifier) throws ControllerInitializationFailedException {
super(identifier);
// truncate package to 11;
this.MAX_PACKET_LENGTH = 11;
if((isUSB = doUSBHandshake())){
log.info("Switch Pro Controller USB Handshake successful!");
}else{
log.info("Switch Pro Controller USB Handshake failed! The controller is probably connected via Bluetooth");
}
}
@Override
public byte[] pollLatestData() {
if(isUSB){
sendReadCmd();
}
byte[] currentData = super.pollLatestData();
if (currentData == null || currentData.length < 10) {
return new byte[0];
}
// remove unused data (because only changed data will be sent)
currentData[3] = 0;
currentData[5] = 0;
currentData[7] = 0;
currentData[9] = 0;
if(isUSB){
if(currentData[0] == (byte)0x81 && currentData[1] == (byte)0x92){
currentData = Arrays.copyOfRange(currentData, 0x0D,0x20);
int buttons = ByteBuffer.wrap(currentData).getInt() & 0xFFFFFF00;
byte LX = (byte) ((short) ((currentData[0x04] << 8 &0xFF00) | (((short)currentData[0x03])&0xFF)) >> 0x04);
byte LY = currentData[0x05];
byte RX = (byte) ((short) ((currentData[0x07] << 8 &0xFF00) | (((short)currentData[0x06])&0xFF)) >> 0x04);
byte RY = currentData[0x08];
byte[] btData = new byte[0x0B];
int newButtons = 0;
if((buttons & SWITCH_PRO_USB_BUTTON_A) == SWITCH_PRO_USB_BUTTON_A) newButtons |= SWITCH_PRO_BT_BUTTON_A;
if((buttons & SWITCH_PRO_USB_BUTTON_B) == SWITCH_PRO_USB_BUTTON_B) newButtons |= SWITCH_PRO_BT_BUTTON_B;
if((buttons & SWITCH_PRO_USB_BUTTON_X) == SWITCH_PRO_USB_BUTTON_X) newButtons |= SWITCH_PRO_BT_BUTTON_X;
if((buttons & SWITCH_PRO_USB_BUTTON_Y) == SWITCH_PRO_USB_BUTTON_Y) newButtons |= SWITCH_PRO_BT_BUTTON_Y;
if((buttons & SWITCH_PRO_USB_BUTTON_PLUS) == SWITCH_PRO_USB_BUTTON_PLUS) newButtons |= SWITCH_PRO_BT_BUTTON_PLUS;
if((buttons & SWITCH_PRO_USB_BUTTON_MINUS) == SWITCH_PRO_USB_BUTTON_MINUS) newButtons |= SWITCH_PRO_BT_BUTTON_MINUS;
if((buttons & SWITCH_PRO_USB_BUTTON_HOME) == SWITCH_PRO_USB_BUTTON_HOME) newButtons |= SWITCH_PRO_BT_BUTTON_HOME;
//if((buttons & SWITCH_PRO_USB_BUTTON_SCREENSHOT) == SWITCH_PRO_USB_BUTTON_SCREENSHOT) newButtons |= SWITCH_PRO_BT_BUTTON_SCREENSHOT;
if((buttons & SWITCH_PRO_USB_BUTTON_R) == SWITCH_PRO_USB_BUTTON_R) newButtons |= SWITCH_PRO_BT_BUTTON_R;
if((buttons & SWITCH_PRO_USB_BUTTON_ZR) == SWITCH_PRO_USB_BUTTON_ZR) newButtons |= SWITCH_PRO_BT_BUTTON_ZR;
if((buttons & SWITCH_PRO_USB_BUTTON_STICK_R) == SWITCH_PRO_USB_BUTTON_STICK_R) newButtons |= SWITCH_PRO_BT_BUTTON_STICK_R;
if((buttons & SWITCH_PRO_USB_BUTTON_L) == SWITCH_PRO_USB_BUTTON_L) newButtons |= SWITCH_PRO_BT_BUTTON_L;
if((buttons & SWITCH_PRO_USB_BUTTON_ZL) == SWITCH_PRO_USB_BUTTON_ZL) newButtons |= SWITCH_PRO_BT_BUTTON_ZL;
if((buttons & SWITCH_PRO_USB_BUTTON_STICK_L) == SWITCH_PRO_USB_BUTTON_STICK_L) newButtons |= SWITCH_PRO_BT_BUTTON_STICK_L;
byte dpad = currentData[2];
byte dpadResult = SWITCH_PRO_BT_BUTTON_DPAD_NEUTRAL_VALUE;
if(((dpad & SWITCH_PRO_USB_BUTTON_UP_VALUE) == SWITCH_PRO_USB_BUTTON_UP_VALUE) &&
((dpad & SWITCH_PRO_USB_BUTTON_RIGHT_VALUE) == SWITCH_PRO_USB_BUTTON_RIGHT_VALUE)){
dpadResult = SWITCH_PRO_BT_BUTTON_DPAD_NE_VALUE;
}else if(((dpad & SWITCH_PRO_USB_BUTTON_DOWN_VALUE) == SWITCH_PRO_USB_BUTTON_DOWN_VALUE) &&
((dpad & SWITCH_PRO_USB_BUTTON_RIGHT_VALUE) == SWITCH_PRO_USB_BUTTON_RIGHT_VALUE)){
dpadResult = SWITCH_PRO_BT_BUTTON_DPAD_SE_VALUE;
}else if(((dpad & SWITCH_PRO_USB_BUTTON_DOWN_VALUE) == SWITCH_PRO_USB_BUTTON_DOWN_VALUE) &&
((dpad & SWITCH_PRO_USB_BUTTON_LEFT_VALUE) == SWITCH_PRO_USB_BUTTON_LEFT_VALUE)){
dpadResult = SWITCH_PRO_BT_BUTTON_DPAD_SW_VALUE;
}else if(((dpad & SWITCH_PRO_USB_BUTTON_UP_VALUE) == SWITCH_PRO_USB_BUTTON_UP_VALUE) &&
((dpad & SWITCH_PRO_USB_BUTTON_LEFT_VALUE) == SWITCH_PRO_USB_BUTTON_LEFT_VALUE)){
dpadResult = SWITCH_PRO_BT_BUTTON_DPAD_NW_VALUE;
}else if((dpad & SWITCH_PRO_USB_BUTTON_UP_VALUE) == SWITCH_PRO_USB_BUTTON_UP_VALUE){
dpadResult = SWITCH_PRO_BT_BUTTON_DPAD_N_VALUE;
}else if((dpad & SWITCH_PRO_USB_BUTTON_RIGHT_VALUE) == SWITCH_PRO_USB_BUTTON_RIGHT_VALUE){
dpadResult = SWITCH_PRO_BT_BUTTON_DPAD_E_VALUE;
}else if((dpad & SWITCH_PRO_USB_BUTTON_DOWN_VALUE) == SWITCH_PRO_USB_BUTTON_DOWN_VALUE){
dpadResult = SWITCH_PRO_BT_BUTTON_DPAD_S_VALUE;
}else if((dpad & SWITCH_PRO_USB_BUTTON_LEFT_VALUE) == SWITCH_PRO_USB_BUTTON_LEFT_VALUE){
dpadResult = SWITCH_PRO_BT_BUTTON_DPAD_W_VALUE;
}
btData[0] = (byte) ((newButtons >> 24) & 0xFF);
btData[1] = (byte) ((newButtons >> 16) & 0xFF);
btData[2] |= dpadResult;
btData[4] = LX;
btData[6] = (byte) (LY * -1) ;
btData[8] = RX;
btData[10] = (byte) (RY * -1) ;
currentData = btData;
//System.out.println(Utilities.ByteArrayToString(currentData));
}else{
return new byte[0];
}
}else{
currentData = Arrays.copyOfRange(currentData, 0x01,12);
currentData[3] = 0;
currentData[5] = 0;
currentData[7] = 0;
currentData[9] = 0;
}
return currentData;
}
private boolean sendReadCmd() {
return (hidDevice.hid_write(CMD_readInput, CMD_readInput.length,(byte) 0x80) > 0);
}
private boolean doUSBHandshake() {
byte[] read_buf = new byte[0x40];
int res = 0;
if(res >= 0){
hidDevice.hid_read(read_buf,read_buf.length);
res = hidDevice.hid_write(CMD_DO_HANDSHAKE,CMD_DO_HANDSHAKE.length,(byte) 0x80);
if(res < 0) return false;
res = hidDevice.hid_write(CMD_HID_ONLY,CMD_HID_ONLY.length,(byte) 0x80);
if(res < 0) return false;
res = hidDevice.hid_read(read_buf,read_buf.length+1);
if(read_buf[0] != 0x00){
MessageBoxManager.addMessageBox("You need to reattach the Switch Pro Controller or restart the network client!");
return false;
}
return true;
}
return false;
}
@Override
public String getInfoText() {
return "Switch Pro Controller on " + getIdentifier();

View File

@ -83,4 +83,10 @@ public interface HidDevice {
* @return product string (name)
*/
String getProductString();
int hid_write(byte[] data, int length, byte reportID);
int hid_read(byte[] data);
int hid_read(byte[] data, int timeoutMillis);
}

View File

@ -72,8 +72,8 @@ public class HidManager {
public static boolean isGamepad(HidDevice info) {
if (info == null) return false;
short usage = info.getUsageID();
return (info.getProductString().toLowerCase().contains("gamepad") || usage == 0x05 || usage == 0x04 || isNintendoController(info)
|| isPlaystationController(info));
String productString = info.getProductString();
return ((productString != null && productString.toLowerCase().contains("gamepad")) || usage == 0x05 || usage == 0x04 || isNintendoController(info) || isPlaystationController(info));
}
public static boolean isKeyboard(HidDevice info) {
@ -108,7 +108,7 @@ public class HidManager {
}
static {
if (Settings.isMacOSX()) {
if (Settings.isMacOSX()) { // PureJavaHid is not properly implemented for OSX!
backend = new Hid4JavaHidManagerBackend();
} else if (Settings.isWindows()) {
backend = new PureJavaHidManagerBackend();

View File

@ -56,7 +56,7 @@ class Hid4JavaHidDevice implements HidDevice {
@Override
public byte[] getLatestData() {
int length = myDevice.read(data);
int length = hid_read(data);
if (length <= 0) return new byte[0];
return Arrays.copyOf(data, length);
}
@ -86,4 +86,19 @@ class Hid4JavaHidDevice implements HidDevice {
public short getUsagePage() {
return (short) myDevice.getUsagePage();
}
@Override
public int hid_write(byte[] data, int length,byte reportId) {
return myDevice.write(data, length, reportId);
}
@Override
public int hid_read(byte[] data) {
return myDevice.read(data);
}
@Override
public int hid_read(byte[] data,int timeoutMillis) {
return myDevice.read(data,timeoutMillis);
}
}

View File

@ -30,27 +30,21 @@ import net.ash.HIDToVPADNetworkClient.hid.HidDevice;
import net.ash.HIDToVPADNetworkClient.util.MessageBox;
import net.ash.HIDToVPADNetworkClient.util.MessageBoxManager;
import net.ash.HIDToVPADNetworkClient.util.Settings;
import net.ash.HIDToVPADNetworkClient.util.Utilities;
import purejavahidapi.HidDeviceInfo;
import purejavahidapi.InputReportListener;
@Log
class PureJavaHidDevice implements HidDevice, InputReportListener {
class PureJavaHidDevice implements HidDevice {
private purejavahidapi.HidDevice myDevice = null;
private final purejavahidapi.HidDeviceInfo myDeviceInfo;
private final Object dataLock = new Object();
protected byte[] currentData = new byte[0];
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();
@ -68,7 +62,6 @@ class PureJavaHidDevice implements HidDevice, InputReportListener {
boolean result = true;
try {
myDevice = purejavahidapi.PureJavaHidApi.openDevice(myDeviceInfo);
myDevice.setInputReportListener(this);
} catch (IOException e) {
result = false;
if (e.getMessage().contains("errno 13") && Settings.isLinux()) {
@ -83,6 +76,8 @@ class PureJavaHidDevice implements HidDevice, InputReportListener {
e.printStackTrace();
}
}
return result;
}
@ -91,10 +86,12 @@ class PureJavaHidDevice implements HidDevice, InputReportListener {
myDevice.close();
}
private byte[] data = new byte[64];
@Override
@Synchronized("dataLock")
public byte[] getLatestData() {
return currentData.clone();
public byte[] getLatestData() {
int length = hid_read(data);
if (length <= 0) return new byte[0];
return Arrays.copyOf(data, length);
}
@Override
@ -114,7 +111,9 @@ class PureJavaHidDevice implements HidDevice, InputReportListener {
@Override
public String getProductString() {
return myDeviceInfo.getProductString().trim();
String result = myDeviceInfo.getProductString();
if(result != null) result = result.trim();
return result;
}
@Override
@ -122,4 +121,27 @@ class PureJavaHidDevice implements HidDevice, InputReportListener {
return "PureJavaHidDevice [vid= " + String.format("%04X", getVendorId()) + ", pid= " + String.format("%04X", getProductId()) + ", path= "
+ getPath().trim() + ", usage= " + String.format("%04X:%04X", getUsagePage(), getUsageID()) + ", data=" + Arrays.toString(currentData) + "]";
}
@Override
public int hid_write(byte[] data, int length, byte reportID){
try{
return myDevice.setOutputReport(reportID, data, length);
}catch(IllegalStateException e){
return -1;
}
}
@Override
public int hid_read(byte[] data) {
return hid_read(data,0);
}
@Override
public int hid_read(byte[] data, int timeoutMillis) {
try{
return myDevice.getInputReport(data,timeoutMillis);
}catch(IllegalStateException e){
return -1;
}
}
}

View File

@ -166,6 +166,5 @@ public final class ActiveControllerManager implements Runnable {
}
}
return null;
}
}
}