/* * Copyright 2016 Nathan Howard * * This file is part of OpenGrave * * OpenGrave is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenGrave is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenGrave. If not, see <http://www.gnu.org/licenses/>. */ package com.opengrave.og.input; import java.io.*; import java.util.ArrayList; import com.opengrave.og.MainThread; import com.opengrave.og.util.Vector4f; /** * This is stored information about the layout of a given gamepad, by ID * * Axis pairs should not be deadzoned separately but as a length of x&y * * @author triggerhapp * */ public class ControllerLayout { private ArrayList<ControllerAxisPairs> pairs = new ArrayList<ControllerAxisPairs>(); private ArrayList<ControllerAxisTrigger> triggers = new ArrayList<ControllerAxisTrigger>(); private ArrayList<ControllerButton> buttons = new ArrayList<ControllerButton>(); private String padName; public ControllerLayout(String padName) { this.padName = padName; } public String getName() { return padName; } public void addPair(int axis1, int axis2, String label, Vector4f col1, Vector4f col2) { synchronized (pairs) { pairs.add(new ControllerAxisPairs(axis1, axis2, label, col1, col2)); } } public void addSingle(int axis, String label, Vector4f col1, Vector4f col2) { synchronized (triggers) { triggers.add(new ControllerAxisTrigger(axis, label, col1, col2)); } } public void addButton(int buttonId, String label, int icon1, int icon2, Vector4f col1, Vector4f col2) { synchronized (buttons) { buttons.add(new ControllerButton(buttonId, label, icon1, icon2, col1, col2)); } } public boolean hasPair(int axis1, int axis2) { synchronized (pairs) { for (ControllerAxisPairs pair : pairs) { if (pair.hasAxis(axis1) || pair.hasAxis(axis2)) { return true; } } } return false; } public ArrayList<ControllerAxisPairs> getPairs() { ArrayList<ControllerAxisPairs> list = new ArrayList<ControllerAxisPairs>(); synchronized (pairs) { for (ControllerAxisPairs pair : pairs) { list.add(pair); } } return list; } public boolean hasPair(int axis) { synchronized (pairs) { for (ControllerAxisPairs pair : pairs) { if (pair.hasAxis(axis)) { return true; } } } return false; } public ArrayList<ControllerAxisTrigger> getTriggers() { ArrayList<ControllerAxisTrigger> list = new ArrayList<ControllerAxisTrigger>(); synchronized (triggers) { for (ControllerAxisTrigger cat : triggers) { list.add(cat); } } return list; } public ArrayList<ControllerButton> getButtons() { ArrayList<ControllerButton> list = new ArrayList<ControllerButton>(); synchronized (buttons) { for (ControllerButton cb : buttons) { list.add(cb); } } return list; } public ControllerAxisTrigger getTrigger(int index) { synchronized (triggers) { for (ControllerAxisTrigger cb : triggers) { if (cb.getAxis() == index) { return cb; } } } return null; } public ControllerButton getButton(int index) { synchronized (buttons) { for (ControllerButton cb : buttons) { if (cb.getIndex() == index) { return cb; } } } return null; } static String sanitiseFileString(String string) { if (string.toLowerCase().endsWith(".pad")) { string = string.substring(0, string.length() - 4); } return string.replaceAll("[^a-zA-Z0-9]", ""); } public static ControllerLayout load(String string) { string = sanitiseFileString(string); ControllerLayout cl = null; File f = new File(MainThread.cache, "input/" + string + ".pad"); String contName; try (BufferedReader in = new BufferedReader(new FileReader(f))) { contName = in.readLine(); if (contName == null) { System.err.println("No controller name in '" + string + "' pad description file"); return null; } cl = new ControllerLayout(contName); int countPairs = readInt(in); for (int i = 0; i < countPairs; i++) { int xId = readInt(in); int yId = readInt(in); String s = in.readLine(); Vector4f col1 = fromHex(in.readLine()); Vector4f col2 = fromHex(in.readLine()); cl.addPair(xId, yId, s, col1, col2); } int countTriggers = readInt(in); for (int i = 0; i < countTriggers; i++) { int axis = readInt(in); String s = in.readLine(); Vector4f col1 = fromHex(in.readLine()); Vector4f col2 = fromHex(in.readLine()); cl.addSingle(axis, s, col1, col2); } int countButtons = readInt(in); for (int i = 0; i < countButtons; i++) { int index = readInt(in); int icon1 = readInt(in); int icon2 = readInt(in); String label = in.readLine(); Vector4f col1 = fromHex(in.readLine()); Vector4f col2 = fromHex(in.readLine()); cl.addButton(index, label, icon1, icon2, col1, col2); } } catch (FileNotFoundException e) { System.err.println("No pad description file for '" + string + "'"); } catch (IOException e) { e.printStackTrace(); } catch (NumberFormatException e) { System.err.println("Expected integer number while reading '" + string + "' pad description file"); } return cl; } private static int readInt(BufferedReader in) throws NumberFormatException, IOException { return Integer.parseInt(in.readLine()); } public void save(String string) { string = sanitiseFileString(string); File f = new File(MainThread.cache, "input/" + string + ".pad"); try (BufferedWriter out = new BufferedWriter(new FileWriter(f))) { out.write(string); out.newLine(); synchronized (pairs) { out.write("" + pairs.size()); out.newLine(); for (ControllerAxisPairs pair : pairs) { out.write("" + pair.xId); out.newLine(); out.write("" + pair.yId); out.newLine(); out.write("" + pair.getLabel()); out.newLine(); out.write("" + asHex(pair.getColour1())); out.newLine(); out.write("" + asHex(pair.getColour2())); out.newLine(); } } synchronized (triggers) { out.write("" + triggers.size()); out.newLine(); for (ControllerAxisTrigger trigger : triggers) { out.write("" + trigger.getAxis()); out.newLine(); out.write("" + trigger.getLabel()); out.newLine(); out.write("" + asHex(trigger.getColour1())); out.newLine(); out.write("" + asHex(trigger.getColour2())); out.newLine(); } } synchronized (buttons) { out.write("" + buttons.size()); out.newLine(); for (ControllerButton button : buttons) { out.write("" + button.getIndex()); out.newLine(); out.write("" + button.getIcon1()); out.newLine(); out.write("" + button.getIcon2()); out.newLine(); out.write("" + button.getLabel()); out.newLine(); out.write("" + asHex(button.getColour1())); out.newLine(); out.write("" + asHex(button.getColour2())); out.newLine(); } } } catch (FileNotFoundException e) { System.err.println("No cache directory 'pads'"); e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private static Vector4f fromHex(String s) throws NumberFormatException { Vector4f vec = new Vector4f(); if (s.length() != 6) { throw new NumberFormatException(); } vec.x = Integer.parseInt(s.substring(0, 2), 16) / 255f; vec.y = Integer.parseInt(s.substring(2, 4), 16) / 255f; vec.z = Integer.parseInt(s.substring(4, 6), 16) / 255f; vec.w = 1f; return vec; } private static String asHex(Vector4f colour) { return String.format("%02X%02X%02X", (int) (colour.x * 255), (int) (colour.y * 255), (int) (colour.z * 255)); } public ControllerAxisPairs getPair(int axis) { synchronized (pairs) { for (ControllerAxisPairs pair : pairs) { if (pair.hasAxis(axis)) { return pair; } } } return null; } public ControlDescription getComponent(int index) { ControllerButton cb = getButton(index); if (cb != null) { return cb; } ControllerAxisTrigger ct = getTrigger(index); if (ct != null) { return ct; } ControllerAxisPairs cp = getPair(index); // 4chan party bus not included if (cp != null) { return cp; } return null; } }