mirror of
https://github.com/Maschell/HIDtoVPADNetworkClient.git
synced 2024-11-24 23:16:52 +01:00
Merge pull request #12 from QuarkTheAwesome/gui
Polish up HID-related GUI things; controller filtering; Options dialog
This commit is contained in:
commit
9399f9f42e
2
pom.xml
2
pom.xml
@ -140,7 +140,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.QuarkTheAwesome</groupId>
|
<groupId>com.github.QuarkTheAwesome</groupId>
|
||||||
<artifactId>purejavahidapi</artifactId>
|
<artifactId>purejavahidapi</artifactId>
|
||||||
<version>3591b7e</version>
|
<version>f877704</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hid4java</groupId>
|
<groupId>org.hid4java</groupId>
|
||||||
|
@ -170,7 +170,7 @@ public abstract class Controller implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getType() + " " + getIdentifier();
|
return getType() + " " + getIdentifier().trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -119,6 +119,7 @@ public class HidController extends Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "USB HID on " + getIdentifier();
|
String name = getHidDevice().getProductString();
|
||||||
|
return ((name != null) ? name : "USB HID") + " on " + getIdentifier();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -30,7 +30,6 @@ import java.awt.event.ActionListener;
|
|||||||
import javax.swing.Box;
|
import javax.swing.Box;
|
||||||
import javax.swing.BoxLayout;
|
import javax.swing.BoxLayout;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JTextField;
|
import javax.swing.JTextField;
|
||||||
@ -60,19 +59,6 @@ public final class GuiInputControls extends JPanel {
|
|||||||
final JButton connectButton = new JButton(CONNECT);
|
final JButton connectButton = new JButton(CONNECT);
|
||||||
connectButton.setAlignmentX(Component.CENTER_ALIGNMENT);
|
connectButton.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||||
|
|
||||||
final JCheckBox cbautoScanForController = new JCheckBox();
|
|
||||||
cbautoScanForController.setSelected(Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS);
|
|
||||||
|
|
||||||
cbautoScanForController.addActionListener(new ActionListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
boolean selected = ((JCheckBox) e.getSource()).isSelected();
|
|
||||||
Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS = selected;
|
|
||||||
cbautoScanForController.setSelected(selected);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
final JButton scanButton = new JButton("Scan for Controllers");
|
final JButton scanButton = new JButton("Scan for Controllers");
|
||||||
scanButton.setAlignmentX(Component.CENTER_ALIGNMENT);
|
scanButton.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||||
scanButton.addActionListener(new ActionListener() {
|
scanButton.addActionListener(new ActionListener() {
|
||||||
@ -86,11 +72,19 @@ public final class GuiInputControls extends JPanel {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
JPanel scanWrap = new JPanel();
|
final JButton optionsButton = new JButton("Options");
|
||||||
scanWrap.setLayout(new BoxLayout(scanWrap, BoxLayout.X_AXIS));
|
optionsButton.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||||
JLabel label = new JLabel("Auto Scan for Controllers: ");
|
optionsButton.addActionListener(new ActionListener() {
|
||||||
scanWrap.add(label);
|
@Override
|
||||||
scanWrap.add(cbautoScanForController);
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
GuiOptionsWindow.showWindow(GuiMain.getInstance());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ipTextBox = new JTextField();
|
ipTextBox = new JTextField();
|
||||||
ipTextBox.setColumns(15);
|
ipTextBox.setColumns(15);
|
||||||
@ -100,23 +94,6 @@ public final class GuiInputControls extends JPanel {
|
|||||||
ipTextBoxWrap.add(ipTextBox);
|
ipTextBoxWrap.add(ipTextBox);
|
||||||
ipTextBoxWrap.setMaximumSize(new Dimension(1000, 20));
|
ipTextBoxWrap.setMaximumSize(new Dimension(1000, 20));
|
||||||
|
|
||||||
final JCheckBox cbautoActivateController = new JCheckBox();
|
|
||||||
cbautoActivateController.setSelected(Settings.AUTO_ACTIVATE_CONTROLLER);
|
|
||||||
cbautoActivateController.addActionListener(new ActionListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
boolean selected = ((JCheckBox) e.getSource()).isSelected();
|
|
||||||
Settings.AUTO_ACTIVATE_CONTROLLER = selected;
|
|
||||||
cbautoActivateController.setSelected(selected);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
JPanel autoActivateWrap = new JPanel();
|
|
||||||
autoActivateWrap.setLayout(new BoxLayout(autoActivateWrap, BoxLayout.X_AXIS));
|
|
||||||
autoActivateWrap.add(new JLabel("Auto Activate Controller: "));
|
|
||||||
autoActivateWrap.add(cbautoActivateController);
|
|
||||||
|
|
||||||
add(Box.createVerticalGlue());
|
add(Box.createVerticalGlue());
|
||||||
|
|
||||||
add(ipTextBoxWrap);
|
add(ipTextBoxWrap);
|
||||||
@ -126,9 +103,7 @@ public final class GuiInputControls extends JPanel {
|
|||||||
add(Box.createRigidArea(new Dimension(1, 4)));
|
add(Box.createRigidArea(new Dimension(1, 4)));
|
||||||
add(scanButton);
|
add(scanButton);
|
||||||
add(Box.createRigidArea(new Dimension(1, 4)));
|
add(Box.createRigidArea(new Dimension(1, 4)));
|
||||||
add(scanWrap);
|
add(optionsButton);
|
||||||
add(Box.createRigidArea(new Dimension(1, 4)));
|
|
||||||
add(autoActivateWrap);
|
|
||||||
add(Box.createVerticalGlue());
|
add(Box.createVerticalGlue());
|
||||||
|
|
||||||
add(Box.createVerticalGlue());
|
add(Box.createVerticalGlue());
|
||||||
|
267
src/net/ash/HIDToVPADNetworkClient/gui/GuiOptionsWindow.java
Normal file
267
src/net/ash/HIDToVPADNetworkClient/gui/GuiOptionsWindow.java
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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.gui;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.GridLayout;
|
||||||
|
import java.awt.LayoutManager;
|
||||||
|
import java.awt.Toolkit;
|
||||||
|
import java.awt.datatransfer.StringSelection;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.Box;
|
||||||
|
import javax.swing.BoxLayout;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JTabbedPane;
|
||||||
|
import javax.swing.JTextArea;
|
||||||
|
import javax.swing.border.EtchedBorder;
|
||||||
|
|
||||||
|
import lombok.extern.java.Log;
|
||||||
|
import net.ash.HIDToVPADNetworkClient.util.Settings;
|
||||||
|
import net.ash.HIDToVPADNetworkClient.util.StatusReport;
|
||||||
|
|
||||||
|
@Log
|
||||||
|
public class GuiOptionsWindow extends JPanel {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static final GuiOptionsWindow instance = new GuiOptionsWindow();
|
||||||
|
|
||||||
|
private final List<Tab> tabs = new ArrayList<Tab>();
|
||||||
|
|
||||||
|
public static void showWindow() {
|
||||||
|
showWindow(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showWindow(Component parent) {
|
||||||
|
instance.setOpaque(true);
|
||||||
|
for (Tab t : instance.tabs) {
|
||||||
|
t.updateTab();
|
||||||
|
}
|
||||||
|
|
||||||
|
JFrame window = new JFrame("Options");
|
||||||
|
window.setContentPane(instance);
|
||||||
|
window.pack();
|
||||||
|
window.setLocationRelativeTo(parent);
|
||||||
|
window.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private GuiOptionsWindow() {
|
||||||
|
super(new GridLayout(1, 1));
|
||||||
|
|
||||||
|
log.info("Hello from the Options window!");
|
||||||
|
|
||||||
|
setPreferredSize(new Dimension(600, 200));
|
||||||
|
|
||||||
|
JTabbedPane tabPane = new JTabbedPane();
|
||||||
|
tabPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
|
||||||
|
|
||||||
|
Tab controllerTab = new ControllerTab();
|
||||||
|
tabs.add(controllerTab);
|
||||||
|
tabPane.addTab("Controllers", controllerTab);
|
||||||
|
|
||||||
|
Tab infoTab = new InfoTab();
|
||||||
|
tabs.add(infoTab);
|
||||||
|
tabPane.addTab("Info", infoTab);
|
||||||
|
|
||||||
|
add(tabPane);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ControllerTab extends Tab {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final ControllerFilteringList cFilterList;
|
||||||
|
private final JCheckBox cBoxScanForControllers;
|
||||||
|
private final JCheckBox cBoxAutoActivateControllers;
|
||||||
|
|
||||||
|
private ControllerTab() {
|
||||||
|
super(new GridLayout(1, 2));
|
||||||
|
|
||||||
|
cFilterList = new ControllerFilteringList();
|
||||||
|
|
||||||
|
for (Settings.ControllerFiltering.Type type : Settings.ControllerFiltering.Type.values()) {
|
||||||
|
if (!type.isSupportedOnPlatform()) continue;
|
||||||
|
ControllerFilteringListItem item = new ControllerFilteringListItem(type);
|
||||||
|
cFilterList.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
add(cFilterList);
|
||||||
|
|
||||||
|
JPanel rightSideControls = new JPanel();
|
||||||
|
rightSideControls.setLayout(new BoxLayout(rightSideControls, BoxLayout.PAGE_AXIS));
|
||||||
|
rightSideControls.add(Box.createVerticalGlue());
|
||||||
|
|
||||||
|
cBoxScanForControllers = new JCheckBox("Automatically scan for controllers");
|
||||||
|
cBoxScanForControllers.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||||
|
cBoxScanForControllers.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS = cBoxScanForControllers.isSelected();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
rightSideControls.add(cBoxScanForControllers);
|
||||||
|
|
||||||
|
rightSideControls.add(Box.createVerticalStrut(2));
|
||||||
|
|
||||||
|
cBoxAutoActivateControllers = new JCheckBox("Automatically activate controllers");
|
||||||
|
cBoxAutoActivateControllers.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||||
|
cBoxAutoActivateControllers.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
Settings.AUTO_ACTIVATE_CONTROLLER = cBoxAutoActivateControllers.isSelected();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
rightSideControls.add(cBoxAutoActivateControllers);
|
||||||
|
|
||||||
|
rightSideControls.add(Box.createVerticalGlue());
|
||||||
|
add(rightSideControls);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateTab() {
|
||||||
|
for (ControllerFilteringListItem c : cFilterList.items) {
|
||||||
|
c.updateItem();
|
||||||
|
}
|
||||||
|
cBoxScanForControllers.setSelected(Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS);
|
||||||
|
cBoxAutoActivateControllers.setSelected(Settings.AUTO_ACTIVATE_CONTROLLER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ControllerFilteringList extends JPanel {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private List<ControllerFilteringListItem> items = new ArrayList<ControllerFilteringListItem>();
|
||||||
|
private JPanel innerPanel;
|
||||||
|
|
||||||
|
private ControllerFilteringList() {
|
||||||
|
super(new BorderLayout());
|
||||||
|
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 0));
|
||||||
|
|
||||||
|
innerPanel = new JPanel();
|
||||||
|
innerPanel.setLayout(new BoxLayout(innerPanel, BoxLayout.PAGE_AXIS));
|
||||||
|
|
||||||
|
JScrollPane innerPanelWrap = new JScrollPane(innerPanel, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||||
|
innerPanelWrap.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
|
||||||
|
add(innerPanelWrap, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
JLabel controllerFilterText = new JLabel("Controllers to show:");
|
||||||
|
controllerFilterText.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
|
||||||
|
add(controllerFilterText, BorderLayout.PAGE_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component add(ControllerFilteringListItem c) {
|
||||||
|
items.add(c);
|
||||||
|
return innerPanel.add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ControllerFilteringListItem extends JPanel {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final JCheckBox cBox;
|
||||||
|
private final Settings.ControllerFiltering.Type type;
|
||||||
|
|
||||||
|
private ControllerFilteringListItem(Settings.ControllerFiltering.Type typeIn) {
|
||||||
|
super(new GridLayout(1, 1));
|
||||||
|
this.type = typeIn;
|
||||||
|
|
||||||
|
cBox = new JCheckBox(type.getName());
|
||||||
|
cBox.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||||
|
cBox.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
Settings.ControllerFiltering.setFilterState(type, cBox.isSelected());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
add(cBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateItem() {
|
||||||
|
cBox.setSelected(Settings.ControllerFiltering.getFilterState(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
//I can't believe I didn't figure this out for GuiControllerList
|
||||||
|
@Override
|
||||||
|
public Dimension getMaximumSize() {
|
||||||
|
return new Dimension(Integer.MAX_VALUE, getPreferredSize().height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class InfoTab extends Tab {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final JTextArea infoText;
|
||||||
|
private final JScrollPane infoTextWrap;
|
||||||
|
|
||||||
|
private InfoTab() {
|
||||||
|
super();
|
||||||
|
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
||||||
|
setBorder(BorderFactory.createEmptyBorder(5, 5, 10, 5));
|
||||||
|
|
||||||
|
infoText = new JTextArea();
|
||||||
|
infoText.setEditable(false);
|
||||||
|
infoTextWrap = new JScrollPane(infoText, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
|
||||||
|
infoTextWrap.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||||
|
add(infoTextWrap);
|
||||||
|
|
||||||
|
add(Box.createVerticalStrut(10));
|
||||||
|
|
||||||
|
JButton copyButton = new JButton("Copy");
|
||||||
|
copyButton.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
StringSelection data = new StringSelection(infoText.getText());
|
||||||
|
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(data, data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
copyButton.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||||
|
add(copyButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateTab() {
|
||||||
|
infoText.setCaretPosition(0);
|
||||||
|
infoText.setText(StatusReport.generateStatusReport());
|
||||||
|
infoText.setCaretPosition(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private abstract class Tab extends JPanel {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
public abstract void updateTab();
|
||||||
|
public Tab(LayoutManager l) {
|
||||||
|
super(l);
|
||||||
|
}
|
||||||
|
public Tab() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -57,11 +57,18 @@ public interface HidDevice {
|
|||||||
byte[] getLatestData();
|
byte[] getLatestData();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retuns the Usage of this HID-Device
|
* Retuns the Usage Page of this HID-Device
|
||||||
*
|
*
|
||||||
* @return usage
|
* @return usage page
|
||||||
*/
|
*/
|
||||||
short getUsage();
|
short getUsagePage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retuns the Usage ID of this HID-Device
|
||||||
|
*
|
||||||
|
* @return usage id
|
||||||
|
*/
|
||||||
|
short getUsageID();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the path of this HidDevice
|
* Returns the path of this HidDevice
|
||||||
@ -69,4 +76,11 @@ public interface HidDevice {
|
|||||||
* @return path
|
* @return path
|
||||||
*/
|
*/
|
||||||
String getPath();
|
String getPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the HID device
|
||||||
|
*
|
||||||
|
* @return product string (name)
|
||||||
|
*/
|
||||||
|
String getProductString();
|
||||||
}
|
}
|
||||||
|
@ -43,23 +43,50 @@ public class HidManager {
|
|||||||
|
|
||||||
for (HidDevice info : backend.enumerateDevices()) {
|
for (HidDevice info : backend.enumerateDevices()) {
|
||||||
if (isGamepad(info)) {
|
if (isGamepad(info)) {
|
||||||
|
if (Settings.ControllerFiltering.getFilterState(Settings.ControllerFiltering.Type.HIDGAMEPAD)) {
|
||||||
// Skip Xbox controller under windows. We should use XInput instead.
|
// Skip Xbox controller under windows. We should use XInput instead.
|
||||||
if (isXboxController(info) && Settings.isWindows()) {
|
if (isXboxController(info) && Settings.isWindows()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
connectedGamepads.add(info);
|
||||||
}
|
}
|
||||||
|
} else if (isKeyboard(info)) {
|
||||||
|
if (Settings.ControllerFiltering.getFilterState(Settings.ControllerFiltering.Type.HIDKEYBOARD)) {
|
||||||
|
connectedGamepads.add(info);
|
||||||
|
}
|
||||||
|
} else if (isMouse(info)) {
|
||||||
|
if (Settings.ControllerFiltering.getFilterState(Settings.ControllerFiltering.Type.HIDMOUSE)) {
|
||||||
|
connectedGamepads.add(info);
|
||||||
|
}
|
||||||
|
} else if (Settings.ControllerFiltering.getFilterState(Settings.ControllerFiltering.Type.HIDOTHER)) {
|
||||||
connectedGamepads.add(info);
|
connectedGamepads.add(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return connectedGamepads;
|
return connectedGamepads;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<HidDevice> getAllAttachedControllers() {
|
||||||
|
return backend.enumerateDevices();
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isGamepad(HidDevice info) {
|
public static boolean isGamepad(HidDevice info) {
|
||||||
if (info == null) return false;
|
if (info == null) return false;
|
||||||
short usage = info.getUsage();
|
short usage = info.getUsageID();
|
||||||
return (usage == 0x05 || usage == 0x04 || isNintendoController(info) || isPlaystationController(info));
|
return (usage == 0x05 || usage == 0x04 || isNintendoController(info) || isPlaystationController(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isKeyboard(HidDevice info) {
|
||||||
|
if (info == null) return false;
|
||||||
|
short usage = info.getUsageID();
|
||||||
|
return (usage == 0x06);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isMouse(HidDevice info) {
|
||||||
|
if (info == null) return false;
|
||||||
|
short usage = info.getUsageID();
|
||||||
|
return (usage == 0x02);
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isPlaystationController(HidDevice info) {
|
private static boolean isPlaystationController(HidDevice info) {
|
||||||
if (info == null) return false;
|
if (info == null) return false;
|
||||||
return (info.getVendorId() == (short) 0x054c);
|
return (info.getVendorId() == (short) 0x054c);
|
||||||
@ -75,13 +102,17 @@ public class HidManager {
|
|||||||
return (info.getVendorId() == (short) 0x045e) && ((info.getProductId() == (short) 0x02ff) || (info.getProductId() == (short) 0x02a1));
|
return (info.getVendorId() == (short) 0x045e) && ((info.getProductId() == (short) 0x02ff) || (info.getProductId() == (short) 0x02a1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getBackendType() {
|
||||||
|
return backend.getClass().getSimpleName();
|
||||||
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
if (Settings.isMacOSX()) {
|
if (Settings.isMacOSX()) {
|
||||||
backend = new Hid4JavaHidManagerBackend();
|
backend = new Hid4JavaHidManagerBackend();
|
||||||
} else if (Settings.isWindows()) {
|
} else if (Settings.isWindows()) {
|
||||||
backend = new PureJavaHidManagerBackend();
|
backend = new PureJavaHidManagerBackend();
|
||||||
} else if (Settings.isLinux()) {
|
} else if (Settings.isLinux()) {
|
||||||
backend = new Hid4JavaHidManagerBackend();
|
backend = new PureJavaHidManagerBackend();
|
||||||
} else {
|
} else {
|
||||||
backend = null;
|
backend = null;
|
||||||
}
|
}
|
||||||
|
@ -67,12 +67,22 @@ class Hid4JavaHidDevice implements HidDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String getProductString() {
|
||||||
return "Hid4JavaHidDevice [vid= " + getVendorId() + ", pid= " + getProductId() + ", data=" + Arrays.toString(data) + "]";
|
return myDevice.getProduct();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short getUsage() {
|
public String toString() {
|
||||||
|
return "Hid4JavaHidDevice [vid= " + getVendorId() + ", pid= " + getProductId() + ", usage= " + String.format("%04X:%04X", getUsagePage(), getUsageID()) + ", data=" + Arrays.toString(data) + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getUsageID() {
|
||||||
return (short) myDevice.getUsage();
|
return (short) myDevice.getUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getUsagePage() {
|
||||||
|
return (short) myDevice.getUsagePage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,18 +81,28 @@ class PureJavaHidDevice implements HidDevice, InputReportListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short getUsage() {
|
public short getUsagePage() {
|
||||||
return myDeviceInfo.getUsagePage();
|
return myDeviceInfo.getUsagePage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getUsageID() {
|
||||||
|
return myDeviceInfo.getUsageID();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPath() {
|
public String getPath() {
|
||||||
return myDeviceInfo.getPath();
|
return myDeviceInfo.getPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProductString() {
|
||||||
|
return myDeviceInfo.getProductString();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PureJavaHidDevice [vid= " + String.format("%04X", getVendorId()) + ", pid= " + String.format("%04X", getProductId()) + ", path= " + getPath()
|
return "PureJavaHidDevice [vid= " + String.format("%04X", getVendorId()) + ", pid= " + String.format("%04X", getProductId()) + ", path= " + getPath().trim()
|
||||||
+ ", data=" + Arrays.toString(currentData) + "]";
|
+ ", usage= " + String.format("%04X:%04X", getUsagePage(), getUsageID()) + ", data=" + Arrays.toString(currentData) + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import java.io.FileInputStream;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@ -117,6 +118,13 @@ public final class Settings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String filterStates = prop.getProperty("filterStates");
|
||||||
|
if (filterStates != null) {
|
||||||
|
ControllerFiltering.loadFilterStates(filterStates);
|
||||||
|
} else {
|
||||||
|
ControllerFiltering.setDefaultFilterStates();
|
||||||
|
}
|
||||||
|
|
||||||
log.info("Loaded config successfully!");
|
log.info("Loaded config successfully!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,6 +147,7 @@ public final class Settings {
|
|||||||
prop.setProperty("autoActivatingController", Boolean.toString(Settings.AUTO_ACTIVATE_CONTROLLER));
|
prop.setProperty("autoActivatingController", Boolean.toString(Settings.AUTO_ACTIVATE_CONTROLLER));
|
||||||
prop.setProperty("sendDataOnlyOnChanges", Boolean.toString(Settings.SEND_DATA_ONLY_ON_CHANGE));
|
prop.setProperty("sendDataOnlyOnChanges", Boolean.toString(Settings.SEND_DATA_ONLY_ON_CHANGE));
|
||||||
prop.setProperty("scanAutomaticallyForControllers", Boolean.toString(Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS));
|
prop.setProperty("scanAutomaticallyForControllers", Boolean.toString(Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS));
|
||||||
|
prop.setProperty("filterStates", ControllerFiltering.getFilterStates());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FileOutputStream outStream = new FileOutputStream(configFile);
|
FileOutputStream outStream = new FileOutputStream(configFile);
|
||||||
@ -183,10 +192,65 @@ public final class Settings {
|
|||||||
} else if (os.contains("Mac OS X")) {
|
} else if (os.contains("Mac OS X")) {
|
||||||
return Platform.MAC_OS_X;
|
return Platform.MAC_OS_X;
|
||||||
}
|
}
|
||||||
return null;
|
return Platform.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Platform {
|
public enum Platform {
|
||||||
LINUX, WINDOWS, MAC_OS_X, UNKNOWN
|
LINUX (0x1), WINDOWS (0x2), MAC_OS_X (0x4), UNKNOWN (0x8);
|
||||||
|
|
||||||
|
private int mask;
|
||||||
|
private Platform(int mask) {
|
||||||
|
this.mask = mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO rename this to something less nonsensical
|
||||||
|
public static class ControllerFiltering {
|
||||||
|
public static enum Type {
|
||||||
|
HIDGAMEPAD (0, "HID Gamepads", Platform.LINUX.mask | Platform.WINDOWS.mask | Platform.MAC_OS_X.mask),
|
||||||
|
HIDKEYBOARD (1, "HID Keyboards", Platform.LINUX.mask | Platform.MAC_OS_X.mask),
|
||||||
|
HIDMOUSE (2, "HID Mice", Platform.LINUX.mask | Platform.MAC_OS_X.mask),
|
||||||
|
HIDOTHER (3, "Other HIDs", Platform.LINUX.mask | Platform.WINDOWS.mask | Platform.MAC_OS_X.mask);
|
||||||
|
|
||||||
|
private int index;
|
||||||
|
@Getter private String name;
|
||||||
|
private int platforms;
|
||||||
|
private Type(int index, String name, int platforms) {
|
||||||
|
this.index = index;
|
||||||
|
this.name = name;
|
||||||
|
this.platforms = platforms;
|
||||||
|
}
|
||||||
|
public boolean isSupportedOnPlatform() {
|
||||||
|
return (platforms & getPlattform().mask) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean[] filterStates = new boolean[Type.values().length];
|
||||||
|
public static String getFilterStates() {
|
||||||
|
return Arrays.toString(filterStates);
|
||||||
|
}
|
||||||
|
public static void loadFilterStates(String newFilterStates) {
|
||||||
|
boolean[] newFilterStatesParsed = Utilities.stringToBoolArray(newFilterStates);
|
||||||
|
if (newFilterStatesParsed.length != filterStates.length) {
|
||||||
|
//TODO handle changes in filtering more gracefully
|
||||||
|
log.warning("Number of controller filters in config does not match reality, using defaults...");
|
||||||
|
setDefaultFilterStates();
|
||||||
|
} else {
|
||||||
|
filterStates = newFilterStatesParsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setFilterState(Type filter, boolean state) {
|
||||||
|
filterStates[filter.index] = state;
|
||||||
|
}
|
||||||
|
public static boolean getFilterState(Type filter) {
|
||||||
|
return filterStates[filter.index] || !filter.isSupportedOnPlatform();
|
||||||
|
}
|
||||||
|
public static void setDefaultFilterStates() {
|
||||||
|
filterStates[Type.HIDGAMEPAD.index] = true;
|
||||||
|
filterStates[Type.HIDKEYBOARD.index] = false;
|
||||||
|
filterStates[Type.HIDMOUSE.index] = false;
|
||||||
|
filterStates[Type.HIDOTHER.index] = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
39
src/net/ash/HIDToVPADNetworkClient/util/StatusReport.java
Normal file
39
src/net/ash/HIDToVPADNetworkClient/util/StatusReport.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package net.ash.HIDToVPADNetworkClient.util;
|
||||||
|
|
||||||
|
import net.ash.HIDToVPADNetworkClient.controller.Controller;
|
||||||
|
import net.ash.HIDToVPADNetworkClient.hid.HidDevice;
|
||||||
|
import net.ash.HIDToVPADNetworkClient.hid.HidManager;
|
||||||
|
import net.ash.HIDToVPADNetworkClient.manager.ControllerManager;
|
||||||
|
import net.ash.HIDToVPADNetworkClient.network.NetworkManager;
|
||||||
|
|
||||||
|
public class StatusReport {
|
||||||
|
public static String generateStatusReport() {
|
||||||
|
String report = "HID to VPAD Network Client\n\nRunning on ";
|
||||||
|
report += Settings.getPlattform();
|
||||||
|
|
||||||
|
report += "\nHID Backend: ";
|
||||||
|
report += HidManager.getBackendType();
|
||||||
|
|
||||||
|
report += "\nCurrently ";
|
||||||
|
report += (NetworkManager.getInstance().isConnected()) ? "Connected.\n" : "Disconnected.\n";
|
||||||
|
report += (NetworkManager.getInstance().isReconnecting()) ? "" : "Not ";
|
||||||
|
report += "Reconnecting.";
|
||||||
|
|
||||||
|
report += "\n\nCurrently attached controllers:";
|
||||||
|
for (Controller c : ControllerManager.getAttachedControllers()) {
|
||||||
|
report += "\n";
|
||||||
|
report += c.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
report += "\n\nFiltering settings:\n";
|
||||||
|
report += Settings.ControllerFiltering.getFilterStates();
|
||||||
|
|
||||||
|
report += "\n\nAll HIDs:";
|
||||||
|
for (HidDevice d : HidManager.getAllAttachedControllers()) {
|
||||||
|
report += "\n";
|
||||||
|
report += d.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
}
|
@ -76,4 +76,19 @@ public final class Utilities {
|
|||||||
public static short signedShortToByte(short value) {
|
public static short signedShortToByte(short value) {
|
||||||
return signedShortToByte((int) value);
|
return signedShortToByte((int) value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arrays.toString(boolean[]) in reverse.
|
||||||
|
* https://stackoverflow.com/questions/456367/
|
||||||
|
* @param string
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static boolean[] stringToBoolArray(String string) {
|
||||||
|
String[] strings = string.replace("[", "").replace("]", "").split(", ");
|
||||||
|
boolean result[] = new boolean[strings.length];
|
||||||
|
for (int i = 0; i < result.length; i++) {
|
||||||
|
result[i] = Boolean.parseBoolean(strings[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user