diff --git a/.gitignore b/.gitignore index f2eb28af..69c4c327 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ build # other eclipse run +logs # Files from Forge MDK forge*changelog.txt diff --git a/README.md b/README.md index c902deb3..e7492f62 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![Controllable Banner](https://i.imgur.com/ILkyAfn.png) -[![Download](https://img.shields.io/static/v1?label=&message=Download&color=2d2d2d&labelColor=dddddd&style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB98BHA41LJJkRpIAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMvvhp8YAAAGGSURBVDhPjZK9SgNBFIVHBEUE8QeMhLAzdzdYBFL7CmnstEjjO4iFjWClFiGJm42VFpYSUptKRfABFBQE7UUI2AmGmPXM5k6cjFE8cJjZ3fPduTOzIiJarvl+bPmuLuWS+K/KmcwUoK4pEGoTnetvYTY7GUpZOCTa0sZi+QRyhQ83pkBShKjDUBvzGKNxr6rU8W4uN8FoX4CKEcB6EMR61OZOEtApEqNIndFvAbiNuAB30QeU+sDYBXSCdw3MrzHvlnx/kdFkC3kU6NkwF3iM0ukFnNM8R0UplZquKHWE85nhV0Kg4o4GrDMwre5x5G9h9aaBHL/VPI849rtqRFfwqALaIcd+F87gYnDy1ha0sY12VcoiR0cLq5/ae3e3gyLbHB2tMAgKQ1fXh+z5a1mpDXQyy8hPIdgyAEMDW8+fWOQJHbfgzXUhxhkXYh/3jcC9C7s2V43c+9DPpHXgeXMIXbqQbV7gAV5hbFixEGMVolUEmvjjXuBeRcoOnp/R/hm81hi0LsQX8OcRBvBjZ8YAAAAASUVORK5CYII=)](https://mrcrayfish.com/mods?id=controllable) ![Minecraft](https://img.shields.io/static/v1?label=&message=1.15%20|%201.14%20|%201.12&color=2d2d2d&labelColor=dddddd&style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjCGJ1kDAAACoElEQVQ4T22SeU8aURTF/ULGtNRWWVQY9lXABWldIDPIMgVbNgEVtaa0damiqGBdipXaJcY2ofEf4ycbTt97pVAabzK5b27u+Z377kwXgK77QthRy7OfXbeJM+ttqKSXN8sdwbT/A0L7elmsYqrPHZmROLPh5YkV4oEBwaKuHj+yyJptLDoAhbq3O1V1XCVObY3FL24mfn5oRPrcwSCRfQOyNWcjVjZdCbtcdwcgXrXUspdOKbDN/XE9tiBJMhXHT60gUIT2dMhcDLMc3NVKQklz0QIkf5qlyEcO6Qs7yPhMJB4amDMFimQSmqNlE8SKAZFzDfxHfVILIIZ10sJ3OwIbcqSuiOjchkzNCboHev9o2YhgiUP8mxnLN24I6/3ghYdtQG5iUMpFBuCP9iKwLsfiLyeCp2rMnZgwX3NArGoxW1Ridl+BzLEVKa8KSxOqNmDdz0kFnxaLHhWEgAyZigWhHXL+pEDy2ozsDxv8vAzTnh7w5kcghqCaFmCT10of4iPIT2mRdPUh4HoCcVwBH/8Ac2kzUkEV5r3EfVSOvbAJa5NDyI0r2oDtWb1EClh+OoC3Pg7v/Bw7p939yI4rsRW2Y3lKh01eh7WpIRyKZqzyjjYgPdIvlaMWRqYuG7wWryYHsRM0sFolZiPvQ3jheIwSmSBPdkByG/B6Wi3RYiVmRX7GiAPiUCRisii8D+jZNKvPBrHCW1GY0bAz6WkDCtOaSyKQFsi4K5NqNiZtehN2Y5uAShETqolhBqJXpfdPuPsuWwAaRdHSkxdc11mPqkGnyY4pyKbpl1GyJ0Pel7yqBoFcF3zqno5f+d8ohYy9Sx7lzQpxo1eirluCDgt++00p6uxttrG4F/A39sJGZWZMfrcp6O6+5kaVzXJHAOj6DeSs8qw5o8oxAAAAAElFTkSuQmCC) ![Curseforge](http://cf.way2muchnoise.eu/full_controllable_downloads.svg?badge_style=for_the_badge) +[![Download](https://img.shields.io/static/v1?label=&message=Download&color=2d2d2d&labelColor=dddddd&style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB98BHA41LJJkRpIAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMvvhp8YAAAGGSURBVDhPjZK9SgNBFIVHBEUE8QeMhLAzdzdYBFL7CmnstEjjO4iFjWClFiGJm42VFpYSUptKRfABFBQE7UUI2AmGmPXM5k6cjFE8cJjZ3fPduTOzIiJarvl+bPmuLuWS+K/KmcwUoK4pEGoTnetvYTY7GUpZOCTa0sZi+QRyhQ83pkBShKjDUBvzGKNxr6rU8W4uN8FoX4CKEcB6EMR61OZOEtApEqNIndFvAbiNuAB30QeU+sDYBXSCdw3MrzHvlnx/kdFkC3kU6NkwF3iM0ukFnNM8R0UplZquKHWE85nhV0Kg4o4GrDMwre5x5G9h9aaBHL/VPI849rtqRFfwqALaIcd+F87gYnDy1ha0sY12VcoiR0cLq5/ae3e3gyLbHB2tMAgKQ1fXh+z5a1mpDXQyy8hPIdgyAEMDW8+fWOQJHbfgzXUhxhkXYh/3jcC9C7s2V43c+9DPpHXgeXMIXbqQbV7gAV5hbFixEGMVolUEmvjjXuBeRcoOnp/R/hm81hi0LsQX8OcRBvBjZ8YAAAAASUVORK5CYII=)](https://mrcrayfish.com/mods?id=controllable) ![Minecraft](https://img.shields.io/static/v1?label=&message=1.16%20|%201.15%20|%201.14%20|%201.12&color=2d2d2d&labelColor=dddddd&style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjCGJ1kDAAACoElEQVQ4T22SeU8aURTF/ULGtNRWWVQY9lXABWldIDPIMgVbNgEVtaa0damiqGBdipXaJcY2ofEf4ycbTt97pVAabzK5b27u+Z377kwXgK77QthRy7OfXbeJM+ttqKSXN8sdwbT/A0L7elmsYqrPHZmROLPh5YkV4oEBwaKuHj+yyJptLDoAhbq3O1V1XCVObY3FL24mfn5oRPrcwSCRfQOyNWcjVjZdCbtcdwcgXrXUspdOKbDN/XE9tiBJMhXHT60gUIT2dMhcDLMc3NVKQklz0QIkf5qlyEcO6Qs7yPhMJB4amDMFimQSmqNlE8SKAZFzDfxHfVILIIZ10sJ3OwIbcqSuiOjchkzNCboHev9o2YhgiUP8mxnLN24I6/3ghYdtQG5iUMpFBuCP9iKwLsfiLyeCp2rMnZgwX3NArGoxW1Ridl+BzLEVKa8KSxOqNmDdz0kFnxaLHhWEgAyZigWhHXL+pEDy2ozsDxv8vAzTnh7w5kcghqCaFmCT10of4iPIT2mRdPUh4HoCcVwBH/8Ac2kzUkEV5r3EfVSOvbAJa5NDyI0r2oDtWb1EClh+OoC3Pg7v/Bw7p939yI4rsRW2Y3lKh01eh7WpIRyKZqzyjjYgPdIvlaMWRqYuG7wWryYHsRM0sFolZiPvQ3jheIwSmSBPdkByG/B6Wi3RYiVmRX7GiAPiUCRisii8D+jZNKvPBrHCW1GY0bAz6WkDCtOaSyKQFsi4K5NqNiZtehN2Y5uAShETqolhBqJXpfdPuPsuWwAaRdHSkxdc11mPqkGnyY4pyKbpl1GyJ0Pel7yqBoFcF3zqno5f+d8ohYy9Sx7lzQpxo1eirluCDgt++00p6uxttrG4F/A39sJGZWZMfrcp6O6+5kaVzXJHAOj6DeSs8qw5o8oxAAAAAElFTkSuQmCC) ![Curseforge](http://cf.way2muchnoise.eu/full_controllable_downloads.svg?badge_style=for_the_badge) # Controllable diff --git a/build.gradle b/build.gradle index 29fbbbc0..bec86cc4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,22 +1,29 @@ buildscript { repositories { maven { url = 'https://files.minecraftforge.net/maven' } + maven { url = 'https://repo.spongepowered.org/maven' } jcenter() mavenCentral() } dependencies { classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true + classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT' } } apply plugin: 'net.minecraftforge.gradle' +apply plugin: 'org.spongepowered.mixin' //Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. -version = "1.15.2-0.8.0" +version = "0.11.0-1.15.2" group = "com.mrcrayfish" // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = "controllable" sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' +mixin { + add sourceSets.main, "controllable.refmap.json" +} + minecraft { mappings channel: 'snapshot', version: '20200122-1.15.1' @@ -27,6 +34,7 @@ minecraft { workingDirectory project.file('run') property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' property 'forge.logging.console.level', 'debug' + arg "-mixin.config=controllable.mixins.json" mods { controllable { source sourceSets.main @@ -38,6 +46,7 @@ minecraft { workingDirectory project.file('run') property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' property 'forge.logging.console.level', 'debug' + arg "-mixin.config=controllable.mixins.json" mods { controllable { source sourceSets.main @@ -59,21 +68,23 @@ minecraft { } } -configurations { - libraries - compile.extendsFrom libraries -} - -dependencies { - minecraft 'net.minecraftforge:forge:1.15.2-31.0.14' -} - repositories { jcenter() + maven { + // location of the maven that hosts JEI files + name = "Progwml6 maven" + url = "https://dvs1.progwml6.com/files/maven/" + } + maven { + // location of a maven mirror for JEI files, as a fallback + name = "ModMaven" + url = "https://modmaven.k-4u.nl" + } } dependencies { - libraries "uk.co.electronstudio.sdl2gdx:sdl2gdx:1.0.+" + minecraft 'net.minecraftforge:forge:1.15.2-31.2.45' + compile fg.deobf("mezz.jei:jei-1.15.2:6.0.3.15") } jar { @@ -86,12 +97,10 @@ jar { "Implementation-Version": "${version}", "Implementation-Vendor" :"MrCrayfish", "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), - "Signing-Fingerprint": project.hasProperty('fingerprint') ? project.property('fingerprint') : 'unsigned' + "Signing-Fingerprint": project.hasProperty('fingerprint') ? project.property('fingerprint') : 'unsigned', + "MixinConfigs" : "controllable.mixins.json" ]) } - from { - configurations.libraries.collect { it.isDirectory() ? it : zipTree(it) } - } } Properties keyStoreProperties = new Properties() diff --git a/src/main/java/com/mrcrayfish/controllable/ButtonStates.java b/src/main/java/com/mrcrayfish/controllable/ButtonStates.java index 575ea2ac..141f7e7d 100644 --- a/src/main/java/com/mrcrayfish/controllable/ButtonStates.java +++ b/src/main/java/com/mrcrayfish/controllable/ButtonStates.java @@ -21,7 +21,7 @@ public boolean getState(int index) return this.states[index]; } - void setState(int index, boolean state) + protected void setState(int index, boolean state) { if(index < 0 || index >= states.length) return; diff --git a/src/main/java/com/mrcrayfish/controllable/Config.java b/src/main/java/com/mrcrayfish/controllable/Config.java new file mode 100644 index 00000000..2964431a --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/Config.java @@ -0,0 +1,83 @@ +package com.mrcrayfish.controllable; + +import com.mrcrayfish.controllable.client.ActionVisibility; +import com.mrcrayfish.controllable.client.ControllerIcons; +import com.mrcrayfish.controllable.client.CursorType; +import net.minecraftforge.common.ForgeConfigSpec; +import org.apache.commons.lang3.tuple.Pair; + +/** + * Author: MrCrayfish + */ +public class Config +{ + static final ForgeConfigSpec clientSpec; + public static final Config.Client CLIENT; + + public static class Client + { + public final ForgeConfigSpec.LongValue controllerPollInterval; + public final Options options; + + Client(ForgeConfigSpec.Builder builder) + { + builder.comment("Client configuration settings").push("client"); + this.controllerPollInterval = builder + .comment("The time in milliseconds to wait before polling the controller. The lower the value the better the input latency but drains the controller battery faster.") + .translation("controllable.configgui.controllerPollInterval") + .defineInRange("controllerPollInterval", 8L, 1L, 128L); + this.options = new Options(builder); + builder.pop(); + } + + public static class Options + { + public final ForgeConfigSpec.BooleanValue forceFeedback; + public final ForgeConfigSpec.BooleanValue autoSelect; + public final ForgeConfigSpec.BooleanValue renderMiniPlayer; + public final ForgeConfigSpec.BooleanValue virtualMouse; + public final ForgeConfigSpec.BooleanValue consoleHotbar; + public final ForgeConfigSpec.EnumValue cursorType; + public final ForgeConfigSpec.EnumValue controllerIcons; + public final ForgeConfigSpec.BooleanValue invertLook; + public final ForgeConfigSpec.DoubleValue deadZone; + public final ForgeConfigSpec.DoubleValue rotationSpeed; + public final ForgeConfigSpec.DoubleValue mouseSpeed; + public final ForgeConfigSpec.EnumValue showActions; + public final ForgeConfigSpec.BooleanValue quickCraft; + + public Options(ForgeConfigSpec.Builder builder) + { + builder.comment("In-game related options. These can be changed in game instead of config!").push("options"); + { + this.forceFeedback = builder.comment("If enabled, some actions will cause the controller to vibrate").define("forceFeedback", true); + this.autoSelect = builder.comment("If enabled, controller will be automatically selected on start up or when plugged in").define("autoSelect", true); + this.renderMiniPlayer = builder.comment("If enabled, the player will render in the top left corner likes Bedrock Edition").define("renderMiniPlayer", true); + this.virtualMouse = builder.comment("If enabled, the game will use a virtual cursor instead of the real cursor. This must be turned on to be able to run multiple instances!").define("virtualMouse", true); + this.consoleHotbar = builder.comment("If enabled, hotbar will render closer to the center of the screen like on console.").define("consoleHotbar", false); + this.cursorType = builder.comment("The image to use for the cursor. This only applies if virtual mouse is enabled!").defineEnum("cursorType", CursorType.LIGHT); + this.controllerIcons = builder.comment("The controller icons to use in game to display actions").defineEnum("controllerIcons", ControllerIcons.DEFAULT); + this.invertLook = builder.comment("If enabled, inverts the controls on the Y axis for the camera").define("invertLook", false); + this.deadZone = builder.comment("The distance you have to move the thumbstick before it's input is registered. This fixes drifting as some thumbsticks don't center to zero.").defineInRange("deadZone", 0.15, 0.0, 1.0); + this.rotationSpeed = builder.comment("The speed which the camera turns in game").defineInRange("rotationSpeed", 25.0, 0.0, 50.0); + this.mouseSpeed = builder.comment("The speed which the cursor or virtual mouse moves around the screen").defineInRange("mouseSpeed", 15.0, 0.0, 50.0); + this.showActions = builder.comment("If enabled, shows common actions when displaying available on the screen").defineEnum("showActions", ActionVisibility.MINIMAL); + this.quickCraft = builder.comment("If enabled, allows you to craft quickly when clicking an item in the recipe book").define("quickCraft", true); + } + builder.pop(); + } + } + } + + static + { + final Pair specPair = new ForgeConfigSpec.Builder().configure(Config.Client::new); + clientSpec = specPair.getRight(); + CLIENT = specPair.getLeft(); + } + + public static void save() + { + clientSpec.save(); + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/Controllable.java b/src/main/java/com/mrcrayfish/controllable/Controllable.java index 6770c891..ebe42761 100644 --- a/src/main/java/com/mrcrayfish/controllable/Controllable.java +++ b/src/main/java/com/mrcrayfish/controllable/Controllable.java @@ -1,43 +1,53 @@ package com.mrcrayfish.controllable; -import com.badlogic.gdx.controllers.ControllerAdapter; +import com.google.common.io.ByteStreams; import com.mrcrayfish.controllable.client.*; +import com.mrcrayfish.controllable.client.gui.ButtonBindingScreen; import com.mrcrayfish.controllable.client.gui.ControllerLayoutScreen; -import com.mrcrayfish.controllable.client.settings.ControllerOptions; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.Screen; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.TickEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.fml.loading.FMLLoader; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.libsdl.SDL_Error; -import uk.co.electronstudio.sdl2gdx.SDL2Controller; -import uk.co.electronstudio.sdl2gdx.SDL2ControllerManager; +import org.lwjgl.glfw.GLFW; +import org.lwjgl.system.MemoryUtil; import javax.annotation.Nullable; import java.io.File; - -import static org.libsdl.SDL.*; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.Comparator; +import java.util.Optional; /** * Author: MrCrayfish */ @Mod(Reference.MOD_ID) -public class Controllable extends ControllerAdapter +public class Controllable implements IControllerListener { public static final Logger LOGGER = LogManager.getLogger(Reference.MOD_NAME); - private static ControllerOptions options; - private static SDL2ControllerManager manager; + private static ControllerManager manager; private static Controller controller; private static ControllerInput input; + private static File configFolder; + private static boolean jeiLoaded; public Controllable() { FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientSetup); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onLoadComplete); + ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, Config.clientSpec); MinecraftForge.EVENT_BUS.register(this); } @@ -47,35 +57,50 @@ public static Controller getController() return controller; } - public static ControllerOptions getOptions() + public static ControllerInput getInput() { - return options; + return input; } - public static ControllerInput getInput() + public static File getConfigFolder() { - return input; + return configFolder; + } + + public static boolean isJeiLoaded() + { + return jeiLoaded; } private void onClientSetup(FMLClientSetupEvent event) { Minecraft mc = event.getMinecraftSupplier().get(); - File configFolder = new File(mc.gameDir, "config"); + configFolder = new File(mc.gameDir, "config"); + jeiLoaded = ModList.get().isLoaded("jei"); ControllerProperties.load(configFolder); - Controllable.options = new ControllerOptions(mc.gameDir); - /* Loads up the controller manager and setup shutdown cleanup */ - Controllable.manager = new SDL2ControllerManager(); - Controllable.manager.addListenerAndRunForConnectedControllers(this); + try(InputStream is = Mappings.class.getResourceAsStream("/gamecontrollerdb.txt")) + { + byte[] bytes = ByteStreams.toByteArray(is); + ByteBuffer buffer = MemoryUtil.memASCIISafe(new String(bytes)); + GLFW.glfwUpdateGamepadMappings(buffer); + } + catch(IOException e) + { + e.printStackTrace(); + } + + /* Loads up the controller manager and adds a listener */ + Controllable.manager = new ControllerManager(); + Controllable.manager.addControllerListener(this); /* Attempts to load the first controller connected if auto select is enabled */ - if(options.isAutoSelect() && manager.getControllers().size > 0) + if(Config.CLIENT.options.autoSelect.get()) { - com.badlogic.gdx.controllers.Controller controller = manager.getControllers().get(0); - if(controller instanceof SDL2Controller) + if(GLFW.glfwJoystickPresent(GLFW.GLFW_JOYSTICK_1) && GLFW.glfwJoystickIsGamepad(GLFW.GLFW_JOYSTICK_1)) { - setController((SDL2Controller) controller); + setController(new Controller(GLFW.GLFW_JOYSTICK_1)); } } @@ -87,48 +112,56 @@ private void onClientSetup(FMLClientSetupEvent event) MinecraftForge.EVENT_BUS.register(new RenderEvents()); MinecraftForge.EVENT_BUS.register(new GuiEvents(Controllable.manager)); MinecraftForge.EVENT_BUS.register(new ControllerEvents()); + + this.startControllerThread(); + } + + private void onLoadComplete(FMLLoadCompleteEvent event) + { + if(FMLLoader.getDist() != Dist.CLIENT) + return; + + BindingRegistry.getInstance().load(); } @Override - public void connected(com.badlogic.gdx.controllers.Controller sdlController) + public void connected(int jid) { Minecraft.getInstance().enqueue(() -> { - if(sdlController instanceof SDL2Controller) + if(Controllable.controller == null) { - if(Controllable.controller == null) + if(Config.CLIENT.options.autoSelect.get()) { - if(options.isAutoSelect()) - { - setController((SDL2Controller) sdlController); - } + setController(new Controller(jid)); + } - Minecraft mc = Minecraft.getInstance(); - if(mc.player != null) - { - Minecraft.getInstance().getToastGui().add(new ControllerToast(true, Controllable.controller.getName())); - } + Minecraft mc = Minecraft.getInstance(); + if(mc.player != null && Controllable.controller != null) + { + Minecraft.getInstance().getToastGui().add(new ControllerToast(true, Controllable.controller.getName())); } } }); } @Override - public void disconnected(com.badlogic.gdx.controllers.Controller sdlController) + public void disconnected(int jid) { Minecraft.getInstance().enqueue(() -> { if(Controllable.controller != null) { - if(Controllable.controller.getSDL2Controller() == sdlController) + if(Controllable.controller.getJid() == jid) { Controller oldController = Controllable.controller; setController(null); - if(options.isAutoSelect() && manager.getControllers().size > 0) + if(Config.CLIENT.options.autoSelect.get() && manager.getControllerCount() > 0) { - setController((SDL2Controller) manager.getControllers().get(0)); + Optional optional = manager.getControllers().keySet().stream().min(Comparator.comparing(i -> i)); + optional.ifPresent(minJid -> setController(new Controller(minJid))); } Minecraft mc = Minecraft.getInstance(); @@ -141,11 +174,10 @@ public void disconnected(com.badlogic.gdx.controllers.Controller sdlController) }); } - public static void setController(@Nullable SDL2Controller sdl2Controller) + public static void setController(@Nullable Controller controller) { - if(sdl2Controller != null) + if(controller != null) { - Controller controller = new Controller(sdl2Controller); Controllable.controller = controller; Mappings.updateControllerMappings(controller); } @@ -155,54 +187,78 @@ public static void setController(@Nullable SDL2Controller sdl2Controller) } } - @SubscribeEvent - public void handleButtonInput(TickEvent.RenderTickEvent event) + private void startControllerThread() { - if(event.phase != TickEvent.Phase.START) - return; - - try + Runnable r = () -> { - manager.pollState(); - } - catch(SDL_Error e) - { - e.printStackTrace(); - } - - if(controller == null) + final long pollInterval = Config.CLIENT.controllerPollInterval.get(); + while(Minecraft.getInstance().isRunning()) + { + manager.update(); + if(controller != null) + { + controller.updateGamepadState(); + this.gatherAndQueueControllerInput(); + } + try + { + Thread.sleep(pollInterval); + } + catch(InterruptedException e) + { + e.printStackTrace(); + } + } + }; + Thread controllerPollThread = new Thread(r, "Controller Input"); + controllerPollThread.setDaemon(true); + controllerPollThread.start(); + } + + private void gatherAndQueueControllerInput() + { + Controller currentController = controller; + if(currentController == null) return; + ButtonStates states = new ButtonStates(); + states.setState(Buttons.A, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_A)); + states.setState(Buttons.B, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_B)); + states.setState(Buttons.X, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_X)); + states.setState(Buttons.Y, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_Y)); + states.setState(Buttons.SELECT, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_BACK)); + states.setState(Buttons.HOME, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_GUIDE)); + states.setState(Buttons.START, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_START)); + states.setState(Buttons.LEFT_THUMB_STICK, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_LEFT_THUMB)); + states.setState(Buttons.RIGHT_THUMB_STICK, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB)); + states.setState(Buttons.LEFT_BUMPER, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)); + states.setState(Buttons.RIGHT_BUMPER, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)); + states.setState(Buttons.LEFT_TRIGGER, currentController.getLTriggerValue() >= 0.5F); + states.setState(Buttons.RIGHT_TRIGGER, currentController.getRTriggerValue() >= 0.5F); + states.setState(Buttons.DPAD_UP, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP)); + states.setState(Buttons.DPAD_DOWN, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN)); + states.setState(Buttons.DPAD_LEFT, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT)); + states.setState(Buttons.DPAD_RIGHT, this.getButtonState(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)); + Minecraft.getInstance().enqueue(() -> this.processButtons(states)); + } + private void processButtons(ButtonStates states) + { ButtonBinding.tick(); - - Controller currentController = controller; - this.processButton(Buttons.A, this.getButtonState(SDL_CONTROLLER_BUTTON_A)); - this.processButton(Buttons.B, this.getButtonState(SDL_CONTROLLER_BUTTON_B)); - this.processButton(Buttons.X, this.getButtonState(SDL_CONTROLLER_BUTTON_X)); - this.processButton(Buttons.Y, this.getButtonState(SDL_CONTROLLER_BUTTON_Y)); - this.processButton(Buttons.SELECT, this.getButtonState(SDL_CONTROLLER_BUTTON_BACK)); - this.processButton(Buttons.HOME, this.getButtonState(SDL_CONTROLLER_BUTTON_GUIDE)); - this.processButton(Buttons.START, this.getButtonState(SDL_CONTROLLER_BUTTON_START)); - this.processButton(Buttons.LEFT_THUMB_STICK, this.getButtonState(SDL_CONTROLLER_BUTTON_LEFTSTICK)); - this.processButton(Buttons.RIGHT_THUMB_STICK, this.getButtonState(SDL_CONTROLLER_BUTTON_RIGHTSTICK)); - this.processButton(Buttons.LEFT_BUMPER, this.getButtonState(SDL_CONTROLLER_BUTTON_LEFTSHOULDER)); - this.processButton(Buttons.RIGHT_BUMPER, this.getButtonState(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)); - this.processButton(Buttons.LEFT_TRIGGER, Math.abs(currentController.getLTriggerValue()) >= 0.1F); - this.processButton(Buttons.RIGHT_TRIGGER, Math.abs(currentController.getRTriggerValue()) >= 0.1F); - this.processButton(Buttons.DPAD_UP, this.getButtonState(SDL_CONTROLLER_BUTTON_DPAD_UP)); - this.processButton(Buttons.DPAD_DOWN, this.getButtonState(SDL_CONTROLLER_BUTTON_DPAD_DOWN)); - this.processButton(Buttons.DPAD_LEFT, this.getButtonState(SDL_CONTROLLER_BUTTON_DPAD_LEFT)); - this.processButton(Buttons.DPAD_RIGHT, this.getButtonState(SDL_CONTROLLER_BUTTON_DPAD_RIGHT)); + for(int i = 0; i < Buttons.BUTTONS.length; i++) + { + this.processButton(Buttons.BUTTONS[i], states); + } } - private void processButton(int index, boolean state) + private void processButton(int index, ButtonStates newStates) { - if(Minecraft.getInstance().currentScreen instanceof ControllerLayoutScreen && state) + boolean state = newStates.getState(index); + + Screen screen = Minecraft.getInstance().currentScreen; + if(screen instanceof ControllerLayoutScreen) { - if(((ControllerLayoutScreen) Minecraft.getInstance().currentScreen).onButtonInput(index)) - { - return; - } + ((ControllerLayoutScreen) screen).processButton(index, newStates); + return; } if (controller == null) @@ -228,6 +284,13 @@ private void processButton(int index, boolean state) if(!states.getState(index)) { states.setState(index, true); + if(screen instanceof ButtonBindingScreen) + { + if(((ButtonBindingScreen) screen).processButton(index)) + { + return; + } + } input.handleButtonInput(controller, index, true); } } @@ -252,6 +315,6 @@ public static boolean isButtonPressed(int button) private boolean getButtonState(int buttonCode) { - return controller != null && controller.getSDL2Controller().getButton(buttonCode); + return controller != null && controller.getGamepadState().buttons(buttonCode) == GLFW.GLFW_PRESS; } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/Action.java b/src/main/java/com/mrcrayfish/controllable/client/Action.java index deabb09e..99b9c155 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/Action.java +++ b/src/main/java/com/mrcrayfish/controllable/client/Action.java @@ -16,7 +16,7 @@ public Action(String description, Side side) public String getDescription() { - return description; + return this.description; } public void setDescription(String description) @@ -26,7 +26,7 @@ public void setDescription(String description) public Side getSide() { - return side; + return this.side; } public void setSide(Side side) diff --git a/src/main/java/com/mrcrayfish/controllable/client/ActionVisibility.java b/src/main/java/com/mrcrayfish/controllable/client/ActionVisibility.java new file mode 100644 index 00000000..a52b002b --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/ActionVisibility.java @@ -0,0 +1,26 @@ +package com.mrcrayfish.controllable.client; + +import net.minecraft.util.IStringSerializable; + +/** + * Author: MrCrayfish + */ +public enum ActionVisibility implements IStringSerializable +{ + ALL("all"), + MINIMAL("minimal"), + NONE("none"); + + String name; + + ActionVisibility(String name) + { + this.name = name; + } + + @Override + public String getName() + { + return this.name; + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/client/BindingRegistry.java b/src/main/java/com/mrcrayfish/controllable/client/BindingRegistry.java new file mode 100644 index 00000000..aad68e4a --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/BindingRegistry.java @@ -0,0 +1,149 @@ +package com.mrcrayfish.controllable.client; + +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableList; +import com.google.common.io.Files; +import com.mrcrayfish.controllable.Controllable; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.*; + +/** + * Author: MrCrayfish + */ +public class BindingRegistry +{ + static + { + getInstance().register(ButtonBindings.JUMP); + getInstance().register(ButtonBindings.SNEAK); + getInstance().register(ButtonBindings.SPRINT); + getInstance().register(ButtonBindings.INVENTORY); + getInstance().register(ButtonBindings.SWAP_HANDS); + getInstance().register(ButtonBindings.DROP_ITEM); + getInstance().register(ButtonBindings.USE_ITEM); + getInstance().register(ButtonBindings.ATTACK); + getInstance().register(ButtonBindings.PICK_BLOCK); + getInstance().register(ButtonBindings.PLAYER_LIST); + getInstance().register(ButtonBindings.TOGGLE_PERSPECTIVE); + getInstance().register(ButtonBindings.SCREENSHOT); + getInstance().register(ButtonBindings.SCROLL_LEFT); + getInstance().register(ButtonBindings.SCROLL_RIGHT); + getInstance().register(ButtonBindings.PAUSE_GAME); + getInstance().register(ButtonBindings.NEXT_CREATIVE_TAB); + getInstance().register(ButtonBindings.PREVIOUS_CREATIVE_TAB); + getInstance().register(ButtonBindings.NEXT_RECIPE_TAB); + getInstance().register(ButtonBindings.PREVIOUS_RECIPE_TAB); + getInstance().register(ButtonBindings.NAVIGATE_UP); + getInstance().register(ButtonBindings.NAVIGATE_DOWN); + getInstance().register(ButtonBindings.NAVIGATE_LEFT); + getInstance().register(ButtonBindings.NAVIGATE_RIGHT); + getInstance().register(ButtonBindings.PICKUP_ITEM); + getInstance().register(ButtonBindings.QUICK_MOVE); + getInstance().register(ButtonBindings.SPLIT_STACK); + getInstance().register(ButtonBindings.ADVANCEMENTS); + getInstance().register(ButtonBindings.HIGHLIGHT_PLAYERS); + getInstance().register(ButtonBindings.CINEMATIC_CAMERA); + getInstance().register(ButtonBindings.FULLSCREEN); + getInstance().register(ButtonBindings.DEBUG_INFO); + } + + private static BindingRegistry instance; + + public static BindingRegistry getInstance() + { + if(instance == null) + { + instance = new BindingRegistry(); + } + return instance; + } + + private List bindings = new ArrayList<>(); + private Map registeredBindings = new HashMap<>(); + private Map> idToButtonList = new HashMap<>(); + + private BindingRegistry() {} + + List getRegisteredBindings() + { + return this.bindings; + } + + List getBindingListForButton(int button) + { + List list = this.idToButtonList.get(button); + return list != null ? ImmutableList.copyOf(list) : ImmutableList.of(); + } + + public List getBindings() + { + return ImmutableList.copyOf(this.bindings); + } + + public void register(ButtonBinding binding) + { + if(this.registeredBindings.putIfAbsent(binding.getDescription(), binding) == null) + { + this.bindings.add(binding); + this.idToButtonList.computeIfAbsent(binding.getButton(), i -> new ArrayList<>()).add(binding); + } + } + + public void resetBindingHash() + { + this.idToButtonList.clear(); + this.bindings.stream().filter(binding -> binding.getButton() != -1).forEach(binding -> { + this.idToButtonList.computeIfAbsent(binding.getButton(), i -> new ArrayList<>()).add(binding); + }); + } + + public void load() + { + File file = new File(Controllable.getConfigFolder(), "controllable/bindings.properties"); + try(BufferedReader reader = Files.newReader(file, Charsets.UTF_8)) + { + Properties properties = new Properties(); + properties.load(reader); + this.bindings.stream().filter(ButtonBinding::isNotReserved).forEach(binding -> + { + String name = properties.getProperty(binding.getDescription(), Buttons.getNameForButton(binding.getButton())); + if(name != null) + { + binding.setButton(Buttons.getButtonFromName(name)); + } + }); + this.resetBindingHash(); + } + catch(IOException e) + { + e.printStackTrace(); + } + } + + public void save() + { + Properties properties = new Properties(); + this.bindings.stream().filter(ButtonBinding::isNotReserved).forEach(binding -> + { + String name = Buttons.getNameForButton(binding.getButton()); + if(name != null) + { + properties.put(binding.getDescription(), name); + } + }); + + try + { + File file = new File(Controllable.getConfigFolder(), "controllable/bindings.properties"); + properties.store(new FileOutputStream(file), "Button Bindings"); + } + catch(IOException e) + { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/client/ButtonBinding.java b/src/main/java/com/mrcrayfish/controllable/client/ButtonBinding.java index 508c22be..7690a963 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/ButtonBinding.java +++ b/src/main/java/com/mrcrayfish/controllable/client/ButtonBinding.java @@ -1,38 +1,42 @@ package com.mrcrayfish.controllable.client; -import java.util.ArrayList; +import net.minecraft.client.resources.I18n; +import net.minecraftforge.client.settings.IKeyConflictContext; + import java.util.List; /** * Author: MrCrayfish */ -public class ButtonBinding +public class ButtonBinding implements Comparable { - private static final List BINDINGS = new ArrayList<>(); - + private final int defaultButton; private int button; private String descriptionKey; private String category; - private boolean ignoreConflict; + private IKeyConflictContext context; private boolean pressed; private int pressedTime; + private boolean reserved; - public ButtonBinding(int button, String descriptionKey) + public ButtonBinding(int button, String descriptionKey, String category, IKeyConflictContext context) { - this(button, descriptionKey, false); + this(button, descriptionKey, category, context, false); } - public ButtonBinding(int button, String descriptionKey, boolean ignoreConflict) + ButtonBinding(int button, String descriptionKey, String category, IKeyConflictContext context, boolean reserved) { + this.defaultButton = button; this.button = button; this.descriptionKey = descriptionKey; - this.ignoreConflict = ignoreConflict; - BINDINGS.add(this); + this.category = category; + this.context = context; + this.reserved = reserved; } public int getButton() { - return button; + return this.button; } public void setButton(int button) @@ -42,22 +46,42 @@ public void setButton(int button) public String getDescription() { - return descriptionKey; + return this.descriptionKey; + } + + public String getCategory() + { + return this.category; + } + + public boolean isDefault() + { + return this.button == this.defaultButton; } public boolean isButtonPressed() { - return pressed && pressedTime == 0; + return this.pressed && this.pressedTime == 0 && this.isActiveAndValidContext(); + } + + public boolean isNotReserved() + { + return !this.reserved; } public boolean isButtonDown() { - return pressed; + return this.pressed && this.isActiveAndValidContext(); + } + + public void reset() + { + this.button = this.defaultButton; } public static void tick() { - for(ButtonBinding binding : BINDINGS) + for(ButtonBinding binding : BindingRegistry.getInstance().getRegisteredBindings()) { if(binding.isButtonDown()) { @@ -68,11 +92,12 @@ public static void tick() public static void setButtonState(int button, boolean state) { - for(ButtonBinding binding : BINDINGS) + List bindings = BindingRegistry.getInstance().getBindingListForButton(button); + for(ButtonBinding binding : bindings) { - if(binding.getButton() == button) + binding.pressed = state; + if(state) { - binding.pressed = state; binding.pressedTime = 0; } } @@ -83,9 +108,63 @@ public static void setButtonState(int button, boolean state) */ public static void resetButtonStates() { - for(ButtonBinding binding : BINDINGS) + for(ButtonBinding binding : BindingRegistry.getInstance().getRegisteredBindings()) { binding.pressed = false; } } + + @Override + public int compareTo(ButtonBinding o) + { + return I18n.format(this.descriptionKey).compareTo(I18n.format(o.descriptionKey)); + } + + public boolean isConflictingContext() + { + List bindings = BindingRegistry.getInstance().getBindingListForButton(this.button); + + if(bindings == null) + return false; + + for(ButtonBinding binding : bindings) + { + if(this.conflicts(binding)) + { + return true; + } + } + return false; + } + + /** + * Checks if the context is active and that this binding does not conflict with any other binding. + */ + private boolean isActiveAndValidContext() + { + return this.context.isActive() && !this.isConflictingContext(); + } + + /** + * Tests if the given binding conflicts with this binding + * + * @param binding the binding to test against + * @return true if the bindings conflict + */ + private boolean conflicts(ButtonBinding binding) + { + return this != binding && this.button == binding.getButton() && this.context.conflicts(binding.context); + } + + @Override + public int hashCode() + { + return this.descriptionKey.hashCode(); + } + + @Override + public boolean equals(Object obj) + { + return this == obj; + } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/ButtonBindings.java b/src/main/java/com/mrcrayfish/controllable/client/ButtonBindings.java index 7bfdc164..c771b2d4 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/ButtonBindings.java +++ b/src/main/java/com/mrcrayfish/controllable/client/ButtonBindings.java @@ -1,24 +1,42 @@ package com.mrcrayfish.controllable.client; +import net.minecraftforge.client.settings.KeyConflictContext; + /** * Author: MrCrayfish */ public class ButtonBindings { - public static final ButtonBinding JUMP = new ButtonBinding(Buttons.A, "key.jump"); - public static final ButtonBinding SNEAK = new ButtonBinding(Buttons.LEFT_THUMB_STICK, "key.sneak"); - public static final ButtonBinding SPRINT = new ButtonBinding(-1, "key.sprint"); - public static final ButtonBinding INVENTORY = new ButtonBinding(Buttons.Y, "key.inventory"); - public static final ButtonBinding SWAP_HANDS = new ButtonBinding(Buttons.X, "key.swapHands"); - public static final ButtonBinding DROP_ITEM = new ButtonBinding(Buttons.DPAD_DOWN, "key.drop"); - public static final ButtonBinding USE_ITEM = new ButtonBinding(Buttons.LEFT_TRIGGER, "key.use"); - public static final ButtonBinding ATTACK = new ButtonBinding(Buttons.RIGHT_TRIGGER, "key.attack"); - public static final ButtonBinding PICK_BLOCK = new ButtonBinding(Buttons.RIGHT_THUMB_STICK, "key.pickItem"); - public static final ButtonBinding PLAYER_LIST = new ButtonBinding(Buttons.SELECT, "key.playerlist"); - public static final ButtonBinding TOGGLE_PERSPECTIVE = new ButtonBinding(Buttons.DPAD_UP, "key.togglePerspective"); - public static final ButtonBinding SCREENSHOT = new ButtonBinding(-1, "key.screenshot"); - public static final ButtonBinding SCROLL_LEFT = new ButtonBinding(Buttons.LEFT_BUMPER, "key.scrollLeft"); - public static final ButtonBinding SCROLL_RIGHT = new ButtonBinding(Buttons.RIGHT_BUMPER, "key.scrollRight"); - public static final ButtonBinding QUICK_MOVE = new ButtonBinding(Buttons.B, "key.quickMove"); - public static final ButtonBinding PAUSE_GAME = new ButtonBinding(Buttons.START, "key.pauseGame"); + public static final ButtonBinding JUMP = new ButtonBinding(Buttons.A, "key.jump", "key.categories.movement", KeyConflictContext.IN_GAME); + public static final ButtonBinding SNEAK = new ButtonBinding(Buttons.RIGHT_THUMB_STICK, "key.sneak", "key.categories.movement", KeyConflictContext.IN_GAME); + public static final ButtonBinding SPRINT = new ButtonBinding(Buttons.LEFT_THUMB_STICK, "key.sprint", "key.categories.movement", KeyConflictContext.IN_GAME); + public static final ButtonBinding INVENTORY = new ButtonBinding(Buttons.Y, "key.inventory", "key.categories.inventory", KeyConflictContext.UNIVERSAL); + public static final ButtonBinding SWAP_HANDS = new ButtonBinding(Buttons.X, "key.swapOffhand", "key.categories.gameplay", KeyConflictContext.IN_GAME); + public static final ButtonBinding DROP_ITEM = new ButtonBinding(Buttons.DPAD_DOWN, "key.drop", "key.categories.gameplay", KeyConflictContext.IN_GAME); + public static final ButtonBinding USE_ITEM = new ButtonBinding(Buttons.LEFT_TRIGGER, "key.use", "key.categories.gameplay", KeyConflictContext.IN_GAME); + public static final ButtonBinding ATTACK = new ButtonBinding(Buttons.RIGHT_TRIGGER, "key.attack", "key.categories.gameplay", KeyConflictContext.IN_GAME); + public static final ButtonBinding PICK_BLOCK = new ButtonBinding(Buttons.DPAD_LEFT, "key.pickItem", "key.categories.gameplay", KeyConflictContext.IN_GAME); + public static final ButtonBinding PLAYER_LIST = new ButtonBinding(Buttons.SELECT, "key.playerlist", "key.categories.multiplayer", KeyConflictContext.IN_GAME); + public static final ButtonBinding TOGGLE_PERSPECTIVE = new ButtonBinding(Buttons.DPAD_UP, "key.togglePerspective", "key.categories.gameplay", KeyConflictContext.IN_GAME); + public static final ButtonBinding SCREENSHOT = new ButtonBinding(-1, "key.screenshot", "key.categories.misc", KeyConflictContext.UNIVERSAL); + public static final ButtonBinding SCROLL_LEFT = new ButtonBinding(Buttons.LEFT_BUMPER, "controllable.key.previousHotbarItem", "key.categories.gameplay", KeyConflictContext.IN_GAME); + public static final ButtonBinding SCROLL_RIGHT = new ButtonBinding(Buttons.RIGHT_BUMPER, "controllable.key.nextHotbarItem", "key.categories.gameplay", KeyConflictContext.IN_GAME); + public static final ButtonBinding PAUSE_GAME = new ButtonBinding(Buttons.START, "controllable.key.pauseGame", "key.categories.misc", KeyConflictContext.UNIVERSAL); + public static final ButtonBinding NEXT_CREATIVE_TAB = new ButtonBinding(Buttons.LEFT_BUMPER, "controllable.key.previousCreativeTab", "key.categories.inventory", KeyConflictContext.GUI); + public static final ButtonBinding PREVIOUS_CREATIVE_TAB = new ButtonBinding(Buttons.RIGHT_BUMPER, "controllable.key.nextCreativeTab", "key.categories.inventory", KeyConflictContext.GUI); + public static final ButtonBinding NEXT_RECIPE_TAB = new ButtonBinding(Buttons.LEFT_TRIGGER, "controllable.key.previousRecipeTab", "key.categories.inventory", KeyConflictContext.GUI); + public static final ButtonBinding PREVIOUS_RECIPE_TAB = new ButtonBinding(Buttons.RIGHT_TRIGGER, "controllable.key.nextRecipeTab", "key.categories.inventory", KeyConflictContext.GUI); + public static final ButtonBinding NAVIGATE_UP = new ButtonBinding(Buttons.DPAD_UP, "controllable.key.moveUp", "key.categories.ui", KeyConflictContext.GUI); + public static final ButtonBinding NAVIGATE_DOWN = new ButtonBinding(Buttons.DPAD_DOWN, "controllable.key.moveDown", "key.categories.ui", KeyConflictContext.GUI); + public static final ButtonBinding NAVIGATE_LEFT = new ButtonBinding(Buttons.DPAD_LEFT, "controllable.key.moveLeft", "key.categories.ui", KeyConflictContext.GUI); + public static final ButtonBinding NAVIGATE_RIGHT = new ButtonBinding(Buttons.DPAD_RIGHT, "controllable.key.moveRight", "key.categories.ui", KeyConflictContext.GUI); + public static final ButtonBinding PICKUP_ITEM = new ButtonBinding(Buttons.A, "controllable.key.pickupItem", "key.categories.ui", KeyConflictContext.GUI, true); + public static final ButtonBinding QUICK_MOVE = new ButtonBinding(Buttons.B, "controllable.key.quickMove", "key.categories.ui", KeyConflictContext.GUI, true); + public static final ButtonBinding SPLIT_STACK = new ButtonBinding(Buttons.X, "controllable.key.splitStack", "key.categories.ui", KeyConflictContext.GUI, true); + //public static final ButtonBinding SOCIAL_INTERACTIONS = new ButtonBinding(-1, "controllable.key.socialInteractions", "key.categories.multiplayer", KeyConflictContext.IN_GAME); + public static final ButtonBinding ADVANCEMENTS = new ButtonBinding(-1, "key.advancements", "key.categories.misc", KeyConflictContext.IN_GAME); + public static final ButtonBinding HIGHLIGHT_PLAYERS = new ButtonBinding(-1, "key.spectatorOutlines", "key.categories.misc", KeyConflictContext.IN_GAME); + public static final ButtonBinding CINEMATIC_CAMERA = new ButtonBinding(-1, "key.smoothCamera", "key.categories.misc", KeyConflictContext.IN_GAME); + public static final ButtonBinding FULLSCREEN = new ButtonBinding(-1, "key.fullscreen", "key.categories.misc", KeyConflictContext.UNIVERSAL); + public static final ButtonBinding DEBUG_INFO = new ButtonBinding(-1, "controllable.key.debugInfo", "key.categories.misc", KeyConflictContext.IN_GAME); } diff --git a/src/main/java/com/mrcrayfish/controllable/client/Buttons.java b/src/main/java/com/mrcrayfish/controllable/client/Buttons.java index 303ecd72..a70bddbb 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/Buttons.java +++ b/src/main/java/com/mrcrayfish/controllable/client/Buttons.java @@ -1,12 +1,14 @@ package com.mrcrayfish.controllable.client; +import org.apache.commons.lang3.ArrayUtils; + +import javax.annotation.Nullable; + /** * Author: MrCrayfish */ public class Buttons { - public static final int LENGTH = 17; - public static final int A = 0; public static final int B = 1; public static final int X = 2; @@ -24,4 +26,38 @@ public class Buttons public static final int DPAD_DOWN = 14; public static final int DPAD_LEFT = 15; public static final int DPAD_RIGHT = 16; + public static final int LENGTH = 17; + public static final int[] BUTTONS = {A, B, X, Y, SELECT, HOME, START, LEFT_THUMB_STICK, RIGHT_THUMB_STICK, LEFT_BUMPER, RIGHT_BUMPER, LEFT_TRIGGER, RIGHT_TRIGGER, DPAD_UP, DPAD_DOWN, DPAD_LEFT, DPAD_RIGHT}; + public static final String[] NAMES = { + "controllable.button.a", + "controllable.button.b", + "controllable.button.x", + "controllable.button.y", + "controllable.button.select", + "controllable.button.home", + "controllable.button.start", + "controllable.button.left_thumb_stick", + "controllable.button.right_thumb_stick", + "controllable.button.left_bumper", + "controllable.button.right_bumper", + "controllable.button.left_trigger", + "controllable.button.right_trigger", + "controllable.button.dpad_up", + "controllable.button.dpad_down", + "controllable.button.dpad_left", + "controllable.button.dpad_right" + }; + + @Nullable + public static String getNameForButton(int button) + { + if(button < 0 || button >= LENGTH) + return null; + return NAMES[button]; + } + + public static int getButtonFromName(String name) + { + return ArrayUtils.indexOf(NAMES, name); + } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/Controller.java b/src/main/java/com/mrcrayfish/controllable/client/Controller.java index 810e45bb..1d6ce76c 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/Controller.java +++ b/src/main/java/com/mrcrayfish/controllable/client/Controller.java @@ -2,12 +2,11 @@ import com.mrcrayfish.controllable.ButtonStates; import net.minecraft.client.resources.I18n; -import uk.co.electronstudio.sdl2gdx.SDL2Controller; +import org.lwjgl.glfw.GLFW; +import org.lwjgl.glfw.GLFWGamepadState; import javax.annotation.Nullable; -import static org.libsdl.SDL.*; - /** * A wrapper class that aims to reduce the exposure to the underlying controller library. This class * provides simple and straight forward methods to retrieve values about the current state of the @@ -15,27 +14,44 @@ */ public class Controller { + private final int jid; + private GLFWGamepadState controller; + private ButtonStates states; private String cachedName; private Mappings.Entry mapping; - private SDL2Controller controller; - private ButtonStates states; - public Controller(SDL2Controller controller) + public Controller(int jid) { - this.controller = controller; + this.jid = jid; + this.controller = GLFWGamepadState.create(); this.states = new ButtonStates(); this.getName(); //cache the name straight away } + public int getJid() + { + return this.jid; + } + /** - * Gets the underlying {@link SDL2Controller} of this this controller instance. + * Gets the underlying {@link GLFWGamepadState} of this this controller instance. * This is gives you direct access to the controller state. * * @return the sdl2controller controller instance */ - public SDL2Controller getSDL2Controller() + public GLFWGamepadState getGamepadState() + { + return this.controller; + } + + /** + * Updates the state of the gamepad. + * + * @return True if successfully updated otherwise controller is disconnected + */ + public boolean updateGamepadState() { - return controller; + return GLFW.glfwGetGamepadState(this.jid, this.controller); } /** @@ -43,7 +59,7 @@ public SDL2Controller getSDL2Controller() */ public ButtonStates getButtonsStates() { - return states; + return this.states; } /** @@ -53,11 +69,11 @@ public ButtonStates getButtonsStates() */ public String getName() { - if(this.controller.isConnected()) + if(GLFW.glfwJoystickPresent(this.jid)) { if(this.cachedName == null) { - this.cachedName = this.controller.getName().replace("SDL GameController ", "").replace("SDL Joystick ", ""); + this.cachedName = GLFW.glfwGetGamepadName(this.jid); } return this.cachedName; } @@ -74,7 +90,7 @@ public String getName() */ public boolean isButtonPressed(int button) { - return states.getState(button); + return this.states.getState(button); } /** @@ -84,7 +100,7 @@ public boolean isButtonPressed(int button) */ public float getLTriggerValue() { - return controller.getAxis(SDL_CONTROLLER_AXIS_TRIGGERLEFT); + return (this.controller.axes(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER) + 1.0F) / 2.0F; } /** @@ -94,7 +110,7 @@ public float getLTriggerValue() */ public float getRTriggerValue() { - return controller.getAxis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT); + return (this.controller.axes(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER) + 1.0F) / 2.0F; } /** @@ -104,7 +120,8 @@ public float getRTriggerValue() */ public float getLThumbStickXValue() { - return controller.getAxis(SDL_CONTROLLER_AXIS_LEFTX); + int axis = this.isThumbsticksSwitched() ? GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X : GLFW.GLFW_GAMEPAD_AXIS_LEFT_X; + return this.controller.axes(axis) * (this.isFlipLeftX() ? -1 : 1); } /** @@ -114,7 +131,8 @@ public float getLThumbStickXValue() */ public float getLThumbStickYValue() { - return controller.getAxis(SDL_CONTROLLER_AXIS_LEFTY); + int axis = this.isThumbsticksSwitched() ? GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y : GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y; + return this.controller.axes(axis) * (this.isFlipLeftY() ? -1 : 1); } /** @@ -124,7 +142,8 @@ public float getLThumbStickYValue() */ public float getRThumbStickXValue() { - return controller.getAxis(SDL_CONTROLLER_AXIS_RIGHTX); + int axis = this.isThumbsticksSwitched() ? GLFW.GLFW_GAMEPAD_AXIS_LEFT_X : GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X; + return this.controller.axes(axis) * (this.isFlipRightX() ? -1 : 1); } /** @@ -134,7 +153,8 @@ public float getRThumbStickXValue() */ public float getRThumbStickYValue() { - return controller.getAxis(SDL_CONTROLLER_AXIS_RIGHTY); + int axis = this.isThumbsticksSwitched() ? GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y : GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y ; + return this.controller.axes(axis) * (this.isFlipRightY() ? -1 : 1); } /** @@ -155,6 +175,31 @@ public void setMapping(Mappings.Entry mapping) @Nullable public Mappings.Entry getMapping() { - return mapping; + return this.mapping; + } + + private boolean isThumbsticksSwitched() + { + return this.mapping != null && this.mapping.isThumbsticksSwitched(); + } + + public boolean isFlipLeftX() + { + return this.mapping != null && this.mapping.isFlipLeftX(); + } + + public boolean isFlipLeftY() + { + return this.mapping != null && this.mapping.isFlipLeftY(); + } + + public boolean isFlipRightX() + { + return this.mapping != null && this.mapping.isFlipRightX(); + } + + public boolean isFlipRightY() + { + return this.mapping != null && this.mapping.isFlipRightY(); } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/ControllerEvents.java b/src/main/java/com/mrcrayfish/controllable/client/ControllerEvents.java index 61727f8e..a28cf1b7 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/ControllerEvents.java +++ b/src/main/java/com/mrcrayfish/controllable/client/ControllerEvents.java @@ -1,5 +1,6 @@ package com.mrcrayfish.controllable.client; +import com.mrcrayfish.controllable.Config; import com.mrcrayfish.controllable.Controllable; import net.minecraft.client.Minecraft; import net.minecraft.item.UseAction; @@ -18,7 +19,12 @@ public class ControllerEvents @SubscribeEvent(receiveCanceled = true) public void onPlayerUsingItem(LivingEntityUseItemEvent.Tick event) { - if(!Controllable.getOptions().useForceFeedback()) + if(event.getEntity() != Minecraft.getInstance().player) + { + return; + } + + if(!Config.CLIENT.options.forceFeedback.get()) { return; } @@ -49,7 +55,7 @@ public void onPlayerUsingItem(LivingEntityUseItemEvent.Tick event) magnitudeFactor = MathHelper.clamp((event.getItem().getUseDuration() - event.getDuration()) / 20F, 0.0F, 1.5F) / 1.5F; break; } - controller.getSDL2Controller().rumble(0.5F * magnitudeFactor, 0.5F * magnitudeFactor, 50); //50ms is one tick + //controller.getGamepadState().rumble(0.5F * magnitudeFactor, 0.5F * magnitudeFactor, 50); //50ms is one tick } } @@ -68,27 +74,27 @@ public void onClientTick(TickEvent.ClientTickEvent event) } Minecraft mc = Minecraft.getInstance(); - if(mc.world != null && Controllable.getOptions().useForceFeedback()) + if(mc.world != null && Config.CLIENT.options.forceFeedback.get()) { - if(prevHealth == -1) + if(this.prevHealth == -1) { - prevHealth = mc.player.getHealth(); + this.prevHealth = mc.player.getHealth(); } - else if(prevHealth > mc.player.getHealth()) + else if(this.prevHealth > mc.player.getHealth()) { - float difference = prevHealth - mc.player.getHealth(); + float difference = this.prevHealth - mc.player.getHealth(); float magnitude = difference / mc.player.getMaxHealth(); - controller.getSDL2Controller().rumble(1.0F, 1.0F, (int) (800 * magnitude)); - prevHealth = mc.player.getHealth(); + //controller.getGamepadState().rumble(1.0F, 1.0F, (int) (800 * magnitude)); + this.prevHealth = mc.player.getHealth(); } else { - prevHealth = mc.player.getHealth(); + this.prevHealth = mc.player.getHealth(); } } - else if(prevHealth != -1) + else if(this.prevHealth != -1) { - prevHealth = -1; + this.prevHealth = -1; } } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/ControllerType.java b/src/main/java/com/mrcrayfish/controllable/client/ControllerIcons.java similarity index 59% rename from src/main/java/com/mrcrayfish/controllable/client/ControllerType.java rename to src/main/java/com/mrcrayfish/controllable/client/ControllerIcons.java index 5b7683e4..afbd1957 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/ControllerType.java +++ b/src/main/java/com/mrcrayfish/controllable/client/ControllerIcons.java @@ -5,7 +5,7 @@ /** * Author: MrCrayfish */ -public enum ControllerType implements IStringSerializable +public enum ControllerIcons implements IStringSerializable { DEFAULT("default"), PLAYSTATION("playstation"), @@ -13,7 +13,7 @@ public enum ControllerType implements IStringSerializable String name; - ControllerType(String name) + ControllerIcons(String name) { this.name = name; } @@ -24,13 +24,13 @@ public String getName() return this.name; } - public static ControllerType byName(String name) + public static ControllerIcons byName(String name) { - for(ControllerType controllerType : values()) + for(ControllerIcons controllerIcons : values()) { - if(controllerType.name.equals(name)) + if(controllerIcons.name.equals(name)) { - return controllerType; + return controllerIcons; } } return DEFAULT; diff --git a/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java b/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java index acdfbbe7..4c2c88ac 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java +++ b/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java @@ -1,26 +1,46 @@ package com.mrcrayfish.controllable.client; import com.mojang.blaze3d.systems.RenderSystem; +import com.mrcrayfish.controllable.Config; import com.mrcrayfish.controllable.Controllable; import com.mrcrayfish.controllable.Reference; import com.mrcrayfish.controllable.client.gui.ControllerLayoutScreen; +import com.mrcrayfish.controllable.client.gui.navigation.BasicNavigationPoint; +import com.mrcrayfish.controllable.client.gui.navigation.NavigationPoint; +import com.mrcrayfish.controllable.client.gui.navigation.SlotNavigationPoint; +import com.mrcrayfish.controllable.client.gui.navigation.WidgetNavigationPoint; import com.mrcrayfish.controllable.event.ControllerEvent; +import com.mrcrayfish.controllable.event.GatherNavigationPointsEvent; +import com.mrcrayfish.controllable.integration.JustEnoughItems; +import com.mrcrayfish.controllable.mixin.client.CreativeScreenMixin; +import com.mrcrayfish.controllable.mixin.client.RecipeBookGuiMixin; +import com.mrcrayfish.controllable.mixin.client.RecipeBookPageAccessor; import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.SimpleSound; import net.minecraft.client.gui.IGuiEventListener; +import net.minecraft.client.gui.advancements.AdvancementsScreen; +import net.minecraft.client.gui.recipebook.*; import net.minecraft.client.gui.screen.IngameMenuScreen; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.client.gui.screen.inventory.CreativeScreen; import net.minecraft.client.gui.screen.inventory.InventoryScreen; +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.client.gui.widget.list.AbstractList; import net.minecraft.client.util.NativeUtil; +import net.minecraft.entity.item.BoatEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.container.RecipeBookContainer; import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemGroup; import net.minecraft.network.play.client.CPlayerDiggingPacket; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.ScreenShotHelper; +import net.minecraft.util.SoundEvents; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.ForgeHooksClient; @@ -36,9 +56,12 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; - -import static org.libsdl.SDL.SDL_CONTROLLER_BUTTON_DPAD_DOWN; -import static org.libsdl.SDL.SDL_CONTROLLER_BUTTON_DPAD_UP; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.stream.Collectors; /** * Author: MrCrayfish @@ -53,10 +76,10 @@ public class ControllerInput private boolean sneaking = false; private boolean isFlying = false; private boolean nearSlot = false; + private boolean moving = false; + private boolean preventReset; private double virtualMouseX; private double virtualMouseY; - private float prevXAxis; - private float prevYAxis; private int prevTargetMouseX; private int prevTargetMouseY; private int targetMouseX; @@ -71,17 +94,36 @@ public class ControllerInput public double getVirtualMouseX() { - return virtualMouseX; + return this.virtualMouseX; } public double getVirtualMouseY() { - return virtualMouseY; + return this.virtualMouseY; + } + + private void setControllerInUse() + { + this.lastUse = 100; + } + + public boolean isControllerInUse() + { + return this.lastUse > 0; } public int getLastUse() { - return lastUse; + return this.lastUse; + } + + public void resetLastUse() + { + if(!this.preventReset) + { + this.lastUse = 0; + } + this.preventReset = false; } @SubscribeEvent @@ -89,21 +131,21 @@ public void onClientTick(TickEvent.ClientTickEvent event) { if(event.phase == TickEvent.Phase.START) { - prevTargetMouseX = targetMouseX; - prevTargetMouseY = targetMouseY; + this.prevTargetMouseX = this.targetMouseX; + this.prevTargetMouseY = this.targetMouseY; - if(lastUse > 0) + if(this.lastUse > 0) { - lastUse--; + this.lastUse--; } Controller controller = Controllable.getController(); if(controller == null) return; - if(Math.abs(controller.getLTriggerValue()) >= 0.1F || Math.abs(controller.getRTriggerValue()) >= 0.1F) + if((Math.abs(controller.getLTriggerValue()) >= 0.2F || Math.abs(controller.getRTriggerValue()) >= 0.2F) && !(Minecraft.getInstance().currentScreen instanceof ControllerLayoutScreen)) { - lastUse = 100; + this.setControllerInUse(); } Minecraft mc = Minecraft.getInstance(); @@ -113,99 +155,99 @@ public void onClientTick(TickEvent.ClientTickEvent event) if(mc.currentScreen == null || mc.currentScreen instanceof ControllerLayoutScreen) return; - float deadZone = (float) Controllable.getOptions().getDeadZone(); + float deadZone = (float) Math.min(1.0F, Config.CLIENT.options.deadZone.get() + 0.25F); /* Only need to run code if left thumb stick has input */ - boolean moving = Math.abs(controller.getLThumbStickXValue()) >= deadZone || Math.abs(controller.getLThumbStickYValue()) >= deadZone; - if(moving) + boolean lastMoving = this.moving; + this.moving = Math.abs(controller.getLThumbStickXValue()) >= deadZone || Math.abs(controller.getLThumbStickYValue()) >= deadZone; + if(this.moving) { /* Updates the target mouse position when the initial thumb stick movement is * detected. This fixes an issue when the user moves the cursor with the mouse then * switching back to controller, the cursor would jump to old target mouse position. */ - if(Math.abs(prevXAxis) < deadZone && Math.abs(prevYAxis) < deadZone) + if(!lastMoving) { double mouseX = mc.mouseHelper.getMouseX(); double mouseY = mc.mouseHelper.getMouseY(); - if(Controllable.getController() != null && Controllable.getOptions().isVirtualMouse()) + if(Controllable.getController() != null && Config.CLIENT.options.virtualMouse.get()) { - mouseX = virtualMouseX; - mouseY = virtualMouseY; + mouseX = this.virtualMouseX; + mouseY = this.virtualMouseY; } - prevTargetMouseX = targetMouseX = (int) mouseX; - prevTargetMouseY = targetMouseY = (int) mouseY; + this.prevTargetMouseX = this.targetMouseX = (int) mouseX; + this.prevTargetMouseY = this.targetMouseY = (int) mouseY; } - float xAxis = (controller.getLThumbStickXValue() > 0.0F ? 1 : -1) * Math.abs(controller.getLThumbStickXValue()); - if(Math.abs(xAxis) >= deadZone) - { - mouseSpeedX = xAxis; - } - else + float xAxis = controller.getLThumbStickXValue(); + this.mouseSpeedX = Math.abs(xAxis) >= deadZone ? Math.signum(xAxis) * (Math.abs(xAxis) - deadZone) / (1.0F - deadZone) : 0.0F; + + float yAxis = controller.getLThumbStickYValue(); + this.mouseSpeedY = Math.abs(yAxis) >= deadZone ? Math.signum(yAxis) * (Math.abs(yAxis) - deadZone) / (1.0F - deadZone) : 0.0F; + + this.setControllerInUse(); + } + + if(this.lastUse <= 0) + { + this.mouseSpeedX = 0F; + this.mouseSpeedY = 0F; + return; + } + + if(Math.abs(this.mouseSpeedX) > 0F || Math.abs(this.mouseSpeedY) > 0F) + { + double mouseSpeed = Config.CLIENT.options.mouseSpeed.get() * mc.getMainWindow().getGuiScaleFactor(); + + // When hovering over slots, slows down the mouse speed to make it easier + if(mc.currentScreen instanceof ContainerScreen) { - mouseSpeedX = 0.0F; + ContainerScreen screen = (ContainerScreen) mc.currentScreen; + if(screen.getSlotUnderMouse() != null) + { + mouseSpeed *= 0.5; + } } - float yAxis = (controller.getLThumbStickYValue() > 0.0F ? 1 : -1) * Math.abs(controller.getLThumbStickYValue()); - if(Math.abs(yAxis) >= deadZone) + double mouseX = this.virtualMouseX * (double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth(); + double mouseY = this.virtualMouseY * (double) mc.getMainWindow().getScaledHeight() / (double) mc.getMainWindow().getHeight(); + List eventListeners = new ArrayList<>(mc.currentScreen.children()); + if(mc.currentScreen instanceof IRecipeShownListener) { - mouseSpeedY = yAxis; + RecipeBookGui recipeBook = ((IRecipeShownListener) mc.currentScreen).getRecipeGui(); + if(recipeBook.isVisible()) + { + eventListeners.add(((RecipeBookGuiMixin) recipeBook).getToggleRecipesBtn()); + eventListeners.addAll(((RecipeBookGuiMixin) recipeBook).getRecipeTabs()); + RecipeBookPage recipeBookPage = ((RecipeBookGuiMixin) recipeBook).getRecipeBookPage(); + eventListeners.addAll(((RecipeBookPageAccessor) recipeBookPage).getButtons()); + eventListeners.add(((RecipeBookPageAccessor) recipeBookPage).getForwardButton()); + eventListeners.add(((RecipeBookPageAccessor) recipeBookPage).getBackButton()); + } } - else + IGuiEventListener hoveredListener = eventListeners.stream().filter(o -> o != null && o.isMouseOver(mouseX, mouseY)).findFirst().orElse(null); + if(hoveredListener != null && !(hoveredListener instanceof AbstractList)) { - mouseSpeedY = 0.0F; + mouseSpeed *= 0.6; } - } - if(Math.abs(mouseSpeedX) > 0.05F || Math.abs(mouseSpeedY) > 0.05F) - { - double mouseSpeed = Controllable.getOptions().getMouseSpeed() * mc.getMainWindow().getGuiScaleFactor(); - targetMouseX += mouseSpeed * mouseSpeedX; - targetMouseX = MathHelper.clamp(targetMouseX, 0, mc.getMainWindow().getWidth()); - targetMouseY += mouseSpeed * mouseSpeedY; - targetMouseY = MathHelper.clamp(targetMouseY, 0, mc.getMainWindow().getHeight()); - lastUse = 100; - moved = true; + this.targetMouseX += mouseSpeed * this.mouseSpeedX; + this.targetMouseX = MathHelper.clamp(this.targetMouseX, 0, mc.getMainWindow().getWidth()); + this.targetMouseY += mouseSpeed * this.mouseSpeedY; + this.targetMouseY = MathHelper.clamp(this.targetMouseY, 0, mc.getMainWindow().getHeight()); + this.setControllerInUse(); + this.moved = true; } - prevXAxis = controller.getLThumbStickXValue(); - prevYAxis = controller.getLThumbStickYValue(); - - this.moveMouseToClosestSlot(moving, mc.currentScreen); + this.moveMouseToClosestSlot(this.moving, mc.currentScreen); if(mc.currentScreen instanceof CreativeScreen) { this.handleCreativeScrolling((CreativeScreen) mc.currentScreen, controller); } - if(Controllable.getController() != null && Controllable.getOptions().isVirtualMouse()) + if(Config.CLIENT.options.virtualMouse.get() && (this.targetMouseX != this.prevTargetMouseX || this.targetMouseY != this.prevTargetMouseY)) { - Screen screen = mc.currentScreen; - if(screen != null && (targetMouseX != prevTargetMouseX || targetMouseY != prevTargetMouseY)) - { - if(mc.loadingGui == null) - { - double mouseX = virtualMouseX * (double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth(); - double mouseY = virtualMouseY * (double) mc.getMainWindow().getScaledHeight() / (double) mc.getMainWindow().getHeight(); - Screen.wrapScreenError(() -> screen.mouseMoved(mouseX, mouseY), "mouseMoved event handler", ((IGuiEventListener) screen).getClass().getCanonicalName()); - if(mc.mouseHelper.activeButton != -1 && mc.mouseHelper.eventTime > 0.0D) - { - double dragX = (targetMouseX - prevTargetMouseX) * (double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth(); - double dragY = (targetMouseY - prevTargetMouseY) * (double) mc.getMainWindow().getScaledHeight() / (double) mc.getMainWindow().getHeight(); - Screen.wrapScreenError(() -> - { - if(net.minecraftforge.client.ForgeHooksClient.onGuiMouseDragPre(screen, mouseX, mouseY, mc.mouseHelper.activeButton, dragX, dragY)) - { - return; - } - if(((IGuiEventListener) screen).mouseDragged(mouseX, mouseY, mc.mouseHelper.activeButton, dragX, dragY)) - { - return; - } - net.minecraftforge.client.ForgeHooksClient.onGuiMouseDragPost(screen, mouseX, mouseY, mc.mouseHelper.activeButton, dragX, dragY); - }, "mouseDragged event handler", ((IGuiEventListener) screen).getClass().getCanonicalName()); - } - } - } + this.performMouseDrag(this.virtualMouseX, this.virtualMouseY, this.targetMouseX - this.prevTargetMouseX, this.targetMouseY - this.prevTargetMouseY); } } } @@ -216,12 +258,12 @@ public void onScreenInit(GuiOpenEvent event) Minecraft mc = Minecraft.getInstance(); if(mc.currentScreen == null) { - nearSlot = false; - moved = false; - mouseSpeedX = 0.0; - mouseSpeedY = 0.0; - virtualMouseX = targetMouseX = prevTargetMouseX = (int) (mc.getMainWindow().getWidth() / 2F); - virtualMouseY = targetMouseY = prevTargetMouseY = (int) (mc.getMainWindow().getHeight() / 2F); + this.nearSlot = false; + this.moved = false; + this.mouseSpeedX = 0.0; + this.mouseSpeedY = 0.0; + this.virtualMouseX = this.targetMouseX = this.prevTargetMouseX = (int) (mc.getMainWindow().getWidth() / 2F); + this.virtualMouseY = this.targetMouseY = this.prevTargetMouseY = (int) (mc.getMainWindow().getHeight() / 2F); } } @@ -232,21 +274,48 @@ public void onRenderScreen(GuiScreenEvent.DrawScreenEvent.Pre event) * mouse position is different to the previous tick's position. This allows for the mouse * to still be used as input. */ Minecraft mc = Minecraft.getInstance(); - if(mc.currentScreen != null && (targetMouseX != prevTargetMouseX || targetMouseY != prevTargetMouseY)) + if(mc.currentScreen != null && (this.targetMouseX != this.prevTargetMouseX || this.targetMouseY != this.prevTargetMouseY)) { if(!(mc.currentScreen instanceof ControllerLayoutScreen)) { float partialTicks = Minecraft.getInstance().getRenderPartialTicks(); - double mouseX = (prevTargetMouseX + (targetMouseX - prevTargetMouseX) * partialTicks + 0.5); - double mouseY = (prevTargetMouseY + (targetMouseY - prevTargetMouseY) * partialTicks + 0.5); - if(Controllable.getOptions().isVirtualMouse()) - { - virtualMouseX = mouseX; - virtualMouseY = mouseY; - } - else + double mouseX = (this.prevTargetMouseX + (this.targetMouseX - this.prevTargetMouseX) * partialTicks + 0.5); + double mouseY = (this.prevTargetMouseY + (this.targetMouseY - this.prevTargetMouseY) * partialTicks + 0.5); + this.setMousePosition(mouseX, mouseY); + } + } + } + + private void performMouseDrag(double mouseX, double mouseY, double dragX, double dragY) + { + if(Controllable.getController() != null) + { + Minecraft mc = Minecraft.getInstance(); + Screen screen = mc.currentScreen; + if(screen != null) + { + if(mc.loadingGui == null) { - GLFW.glfwSetCursorPos(mc.getMainWindow().getHandle(), mouseX, mouseY); + double finalMouseX = mouseX * (double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth(); + double finalMouseY = mouseY * (double) mc.getMainWindow().getScaledHeight() / (double) mc.getMainWindow().getHeight(); + Screen.wrapScreenError(() -> screen.mouseMoved(finalMouseX, finalMouseY), "mouseMoved event handler", ((IGuiEventListener) screen).getClass().getCanonicalName()); + if(mc.mouseHelper.activeButton != -1 && mc.mouseHelper.eventTime > 0.0D) + { + Screen.wrapScreenError(() -> + { + double finalDragX = dragX * (double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth(); + double finalDragY = dragY * (double) mc.getMainWindow().getScaledHeight() / (double) mc.getMainWindow().getHeight(); + if(net.minecraftforge.client.ForgeHooksClient.onGuiMouseDragPre(screen, finalMouseX, finalMouseY, mc.mouseHelper.activeButton, finalDragX, finalDragY)) + { + return; + } + if(((IGuiEventListener) screen).mouseDragged(finalMouseX, finalMouseY, mc.mouseHelper.activeButton, finalDragX, finalDragY)) + { + return; + } + net.minecraftforge.client.ForgeHooksClient.onGuiMouseDragPost(screen, finalMouseX, finalMouseY, mc.mouseHelper.activeButton, finalDragX, finalDragY); + }, "mouseDragged event handler", ((IGuiEventListener) screen).getClass().getCanonicalName()); + } } } } @@ -255,16 +324,16 @@ public void onRenderScreen(GuiScreenEvent.DrawScreenEvent.Pre event) @SubscribeEvent(receiveCanceled = true) public void onRenderScreen(GuiScreenEvent.DrawScreenEvent.Post event) { - if(Controllable.getController() != null && Controllable.getOptions().isVirtualMouse() && lastUse > 0) + if(Controllable.getController() != null && Config.CLIENT.options.virtualMouse.get() && lastUse > 0) { RenderSystem.pushMatrix(); { - CursorType type = Controllable.getOptions().getCursorType(); + CursorType type = Config.CLIENT.options.cursorType.get(); Minecraft minecraft = event.getGui().getMinecraft(); if(minecraft.player == null || (minecraft.player.inventory.getItemStack().isEmpty() || type == CursorType.CONSOLE)) { - double mouseX = (prevTargetMouseX + (targetMouseX - prevTargetMouseX) * Minecraft.getInstance().getRenderPartialTicks()); - double mouseY = (prevTargetMouseY + (targetMouseY - prevTargetMouseY) * Minecraft.getInstance().getRenderPartialTicks()); + double mouseX = (this.prevTargetMouseX + (this.targetMouseX - this.prevTargetMouseX) * Minecraft.getInstance().getRenderPartialTicks()); + double mouseY = (this.prevTargetMouseY + (this.targetMouseY - this.prevTargetMouseY) * Minecraft.getInstance().getRenderPartialTicks()); RenderSystem.translated(mouseX / minecraft.getMainWindow().getGuiScaleFactor(), mouseY / minecraft.getMainWindow().getGuiScaleFactor(), 500); RenderSystem.color3f(1.0F, 1.0F, 1.0F); RenderSystem.disableLighting(); @@ -273,7 +342,7 @@ public void onRenderScreen(GuiScreenEvent.DrawScreenEvent.Post event) { RenderSystem.scaled(0.5, 0.5, 0.5); } - Screen.blit(-8, -8, 16, 16, nearSlot ? 16 : 0, type.ordinal() * 16, 16, 16, 32, CursorType.values().length * 16); + Screen.blit(-8, -8, 16, 16, this.nearSlot ? 16 : 0, type.ordinal() * 16, 16, 16, 32, CursorType.values().length * 16); } } RenderSystem.popMatrix(); @@ -291,14 +360,25 @@ public void onRender(TickEvent.RenderTickEvent event) return; Minecraft mc = Minecraft.getInstance(); + double mouseX = this.virtualMouseX * (double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth(); + double mouseY = this.virtualMouseY * (double) mc.getMainWindow().getScaledHeight() / (double) mc.getMainWindow().getHeight(); + if(mc.currentScreen != null && this.lastUse > 0) + { + IGuiEventListener hoveredListener = mc.currentScreen.children().stream().filter(o -> o.isMouseOver(mouseX, mouseY)).findFirst().orElse(null); + if(hoveredListener instanceof AbstractList) + { + this.handleListScrolling((AbstractList) hoveredListener, controller); + } + } + PlayerEntity player = mc.player; if(player == null) return; - if(mc.currentScreen == null && (targetYaw != 0F || targetPitch != 0F)) + if(mc.currentScreen == null && (this.targetYaw != 0F || this.targetPitch != 0F)) { float elapsedTicks = Minecraft.getInstance().getTickLength(); - player.rotateTowards((targetYaw / 0.15) * elapsedTicks, (targetPitch / 0.15) * (Controllable.getOptions().isInvertLook() ? -1 : 1) * elapsedTicks); + player.rotateTowards((this.targetYaw / 0.15) * elapsedTicks, (this.targetPitch / 0.15) * (Config.CLIENT.options.invertLook.get() ? -1 : 1) * elapsedTicks); if(player.getRidingEntity() != null) { player.getRidingEntity().applyOrientationToEntity(player); @@ -312,8 +392,8 @@ public void onRender(TickEvent.ClientTickEvent event) if(event.phase == TickEvent.Phase.END) return; - targetYaw = 0F; - targetPitch = 0F; + this.targetYaw = 0F; + this.targetPitch = 0F; Minecraft mc = Minecraft.getInstance(); PlayerEntity player = mc.player; @@ -326,31 +406,30 @@ public void onRender(TickEvent.ClientTickEvent event) if(mc.currentScreen == null) { - float deadZone = (float) Controllable.getOptions().getDeadZone(); + float deadZone = Config.CLIENT.options.deadZone.get().floatValue(); /* Handles rotating the yaw of player */ if(Math.abs(controller.getRThumbStickXValue()) >= deadZone) { - lastUse = 100; - double rotationSpeed = Controllable.getOptions().getRotationSpeed(); + this.setControllerInUse(); + double rotationSpeed = Config.CLIENT.options.rotationSpeed.get(); ControllerEvent.Turn turnEvent = new ControllerEvent.Turn(controller, (float) rotationSpeed, (float) rotationSpeed * 0.75F); if(!MinecraftForge.EVENT_BUS.post(turnEvent)) { - float deadZoneTrim = (controller.getRThumbStickXValue() > 0 ? 1 : -1) * deadZone; - float rotationYaw = (turnEvent.getYawSpeed() * (controller.getRThumbStickXValue() - deadZoneTrim) / (1.0F - deadZone)) * 0.33F; - targetYaw = rotationYaw; + float deadZoneTrimX = (controller.getRThumbStickXValue() > 0 ? 1 : -1) * deadZone; + this.targetYaw = (turnEvent.getYawSpeed() * (controller.getRThumbStickXValue() - deadZoneTrimX) / (1.0F - deadZone)) * 0.33F; } } + if(Math.abs(controller.getRThumbStickYValue()) >= deadZone) { - lastUse = 100; - double rotationSpeed = Controllable.getOptions().getRotationSpeed(); + this.setControllerInUse(); + double rotationSpeed = Config.CLIENT.options.rotationSpeed.get(); ControllerEvent.Turn turnEvent = new ControllerEvent.Turn(controller, (float) rotationSpeed, (float) rotationSpeed * 0.75F); if(!MinecraftForge.EVENT_BUS.post(turnEvent)) { - float deadZoneTrim = (controller.getRThumbStickYValue() > 0 ? 1 : -1) * deadZone; - float rotationPitch = (turnEvent.getPitchSpeed() * (controller.getRThumbStickYValue() - deadZoneTrim) / (1.0F - deadZone)) * 0.33F; - targetPitch = rotationPitch; + float deadZoneTrimY = (controller.getRThumbStickYValue() > 0 ? 1 : -1) * deadZone; + this.targetPitch = (turnEvent.getPitchSpeed() * (controller.getRThumbStickYValue() - deadZoneTrimY) / (1.0F - deadZone)) * 0.33F; } } } @@ -359,26 +438,26 @@ public void onRender(TickEvent.ClientTickEvent event) { if(ButtonBindings.DROP_ITEM.isButtonDown()) { - lastUse = 100; - dropCounter++; + this.setControllerInUse(); + this.dropCounter++; } } - if(dropCounter > 20) + if(this.dropCounter > 20) { if (!mc.player.isSpectator()) { mc.player.func_225609_n_(true); } - dropCounter = 0; + this.dropCounter = 0; } - else if(dropCounter > 0 && !ButtonBindings.DROP_ITEM.isButtonDown()) + else if(this.dropCounter > 0 && !ButtonBindings.DROP_ITEM.isButtonDown()) { if (!mc.player.isSpectator()) { mc.player.func_225609_n_(false); } - dropCounter = 0; + this.dropCounter = 0; } } @@ -395,42 +474,45 @@ public void onInputUpdate(InputUpdateEvent event) Minecraft mc = Minecraft.getInstance(); - if(keyboardSneaking && !mc.gameSettings.keyBindSneak.isKeyDown()) + if(this.keyboardSneaking && !mc.gameSettings.keyBindSneak.isKeyDown()) { - sneaking = false; - keyboardSneaking = false; + this.sneaking = false; + this.keyboardSneaking = false; } if(mc.gameSettings.keyBindSneak.isKeyDown()) { - sneaking = true; - keyboardSneaking = true; + this.sneaking = true; + this.keyboardSneaking = true; } if(mc.player.abilities.isFlying || mc.player.isPassenger()) { - lastUse = 100; - sneaking = mc.gameSettings.keyBindSneak.isKeyDown(); - sneaking |= ButtonBindings.SNEAK.isButtonDown(); - isFlying = true; + this.sneaking = mc.gameSettings.keyBindSneak.isKeyDown(); + this.sneaking |= ButtonBindings.SNEAK.isButtonDown(); + if(ButtonBindings.SNEAK.isButtonDown()) + { + this.setControllerInUse(); + } + this.isFlying = true; } - else if(isFlying) + else if(this.isFlying) { - sneaking = false; - isFlying = false; + this.sneaking = false; + this.isFlying = false; } - event.getMovementInput().field_228350_h_ = sneaking; + event.getMovementInput().field_228350_h_ = this.sneaking; if(mc.currentScreen == null) { if(!MinecraftForge.EVENT_BUS.post(new ControllerEvent.Move(controller))) { - float deadZone = (float) Controllable.getOptions().getDeadZone(); + float deadZone = Config.CLIENT.options.deadZone.get().floatValue(); if(Math.abs(controller.getLThumbStickYValue()) >= deadZone) { - lastUse = 100; + this.setControllerInUse(); int dir = controller.getLThumbStickYValue() > 0.0F ? -1 : 1; event.getMovementInput().forwardKeyDown = dir > 0; event.getMovementInput().backKeyDown = dir < 0; @@ -442,9 +524,14 @@ else if(isFlying) } } + if(player.getRidingEntity() instanceof BoatEntity) + { + deadZone = 0.5F; + } + if(Math.abs(controller.getLThumbStickXValue()) >= deadZone) { - lastUse = 100; + this.setControllerInUse(); int dir = controller.getLThumbStickXValue() > 0.0F ? -1 : 1; event.getMovementInput().rightKeyDown = dir < 0; event.getMovementInput().leftKeyDown = dir > 0; @@ -471,12 +558,7 @@ else if(isFlying) public void handleButtonInput(Controller controller, int button, boolean state) { - if(Minecraft.getInstance().currentScreen instanceof ControllerLayoutScreen) - { - return; - } - - lastUse = 100; + this.setControllerInUse(); ControllerEvent.ButtonInput eventInput = new ControllerEvent.ButtonInput(controller, button, state); if(MinecraftForge.EVENT_BUS.post(eventInput)) @@ -492,7 +574,22 @@ public void handleButtonInput(Controller controller, int button, boolean state) Minecraft mc = Minecraft.getInstance(); if(state) { - if(mc.currentScreen == null) + if(ButtonBindings.FULLSCREEN.isButtonPressed()) + { + mc.getMainWindow().toggleFullscreen(); + mc.gameSettings.fullscreen = mc.getMainWindow().isFullscreen(); + mc.gameSettings.saveOptions(); + } + else if(ButtonBindings.SCREENSHOT.isButtonPressed()) + { + if(mc.world != null) + { + ScreenShotHelper.saveScreenshot(mc.gameDir, mc.getMainWindow().getFramebufferWidth(), mc.getMainWindow().getFramebufferHeight(), mc.getFramebuffer(), (textComponent) -> { + mc.execute(() -> mc.ingameGUI.getChatGUI().printChatMessage(textComponent)); + }); + } + } + else if(mc.currentScreen == null) { if(ButtonBindings.INVENTORY.isButtonPressed()) { @@ -506,11 +603,18 @@ public void handleButtonInput(Controller controller, int button, boolean state) mc.displayGuiScreen(new InventoryScreen(mc.player)); } } + else if(ButtonBindings.SPRINT.isButtonPressed()) + { + if(mc.player != null) + { + mc.player.setSprinting(true); + } + } else if(ButtonBindings.SNEAK.isButtonPressed()) { if(mc.player != null && !mc.player.abilities.isFlying && !mc.player.isPassenger()) { - sneaking = !sneaking; + this.sneaking = !this.sneaking; } } else if(ButtonBindings.SCROLL_RIGHT.isButtonPressed()) @@ -531,7 +635,6 @@ else if(ButtonBindings.SWAP_HANDS.isButtonPressed()) { if(mc.player != null && !mc.player.isSpectator() && mc.getConnection() != null) { - mc.getConnection().sendPacket(new CPlayerDiggingPacket(CPlayerDiggingPacket.Action.SWAP_HELD_ITEMS, BlockPos.ZERO, Direction.DOWN)); } } @@ -546,6 +649,24 @@ else if(ButtonBindings.PAUSE_GAME.isButtonPressed()) mc.displayInGameMenu(false); } } + else if(ButtonBindings.ADVANCEMENTS.isButtonPressed()) + { + if(mc.player != null) + { + mc.displayGuiScreen(new AdvancementsScreen(mc.player.connection.getAdvancementManager())); + } + } + else if(ButtonBindings.CINEMATIC_CAMERA.isButtonPressed()) + { + if(mc.player != null) + { + mc.gameSettings.smoothCamera = !mc.gameSettings.smoothCamera; + } + } + else if(ButtonBindings.DEBUG_INFO.isButtonPressed()) + { + mc.gameSettings.showDebugInfo = !mc.gameSettings.showDebugInfo; + } else if(mc.player != null && !mc.player.isHandActive()) { if(ButtonBindings.ATTACK.isButtonPressed()) @@ -571,18 +692,46 @@ else if(ButtonBindings.PICK_BLOCK.isButtonPressed()) mc.player.closeScreen(); } } - else if(ButtonBindings.SCROLL_RIGHT.isButtonPressed()) + else if(ButtonBindings.PREVIOUS_CREATIVE_TAB.isButtonPressed()) { if(mc.currentScreen instanceof CreativeScreen) { - scrollCreativeTabs((CreativeScreen) mc.currentScreen, 1); + this.scrollCreativeTabs((CreativeScreen) mc.currentScreen, 1); + Minecraft.getInstance().getSoundHandler().play(SimpleSound.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + } + else if(mc.currentScreen instanceof IRecipeShownListener) + { + IRecipeShownListener recipeShownListener = (IRecipeShownListener) mc.currentScreen; + this.scrollRecipePage(recipeShownListener.getRecipeGui(), 1); } } - else if(ButtonBindings.SCROLL_LEFT.isButtonPressed()) + else if(ButtonBindings.NEXT_CREATIVE_TAB.isButtonPressed()) { if(mc.currentScreen instanceof CreativeScreen) { - scrollCreativeTabs((CreativeScreen) mc.currentScreen, -1); + this.scrollCreativeTabs((CreativeScreen) mc.currentScreen, -1); + Minecraft.getInstance().getSoundHandler().play(SimpleSound.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + } + else if(mc.currentScreen instanceof IRecipeShownListener) + { + IRecipeShownListener recipeShownListener = (IRecipeShownListener) mc.currentScreen; + this.scrollRecipePage(recipeShownListener.getRecipeGui(), -1); + } + } + else if(ButtonBindings.NEXT_RECIPE_TAB.isButtonPressed()) + { + if(mc.currentScreen instanceof IRecipeShownListener) + { + IRecipeShownListener recipeShownListener = (IRecipeShownListener) mc.currentScreen; + this.scrollRecipeTab(recipeShownListener.getRecipeGui(), -1); + } + } + else if(ButtonBindings.PREVIOUS_RECIPE_TAB.isButtonPressed()) + { + if(mc.currentScreen instanceof IRecipeShownListener) + { + IRecipeShownListener recipeShownListener = (IRecipeShownListener) mc.currentScreen; + this.scrollRecipeTab(recipeShownListener.getRecipeGui(), 1); } } else if(ButtonBindings.PAUSE_GAME.isButtonPressed()) @@ -592,17 +741,45 @@ else if(ButtonBindings.PAUSE_GAME.isButtonPressed()) mc.displayGuiScreen(null); } } - else if(button == Buttons.A) + else if(ButtonBindings.NAVIGATE_UP.isButtonPressed()) + { + this.navigateMouse(mc.currentScreen, Navigate.UP); + } + else if(ButtonBindings.NAVIGATE_DOWN.isButtonPressed()) + { + this.navigateMouse(mc.currentScreen, Navigate.DOWN); + } + else if(ButtonBindings.NAVIGATE_LEFT.isButtonPressed()) + { + this.navigateMouse(mc.currentScreen, Navigate.LEFT); + } + else if(ButtonBindings.NAVIGATE_RIGHT.isButtonPressed()) + { + this.navigateMouse(mc.currentScreen, Navigate.RIGHT); + } + else if(button == ButtonBindings.PICKUP_ITEM.getButton()) { invokeMouseClick(mc.currentScreen, 0); + + if(Config.CLIENT.options.quickCraft.get()) + { + this.craftRecipeBookItem(); + } } - else if(button == Buttons.X) + else if(button == ButtonBindings.SPLIT_STACK.getButton()) { invokeMouseClick(mc.currentScreen, 1); } - else if(button == Buttons.B && mc.player != null && mc.player.inventory.getItemStack().isEmpty()) + else if(button == ButtonBindings.QUICK_MOVE.getButton() && mc.player != null) { - invokeMouseClick(mc.currentScreen, 0); + if(mc.player.inventory.getItemStack().isEmpty()) + { + invokeMouseClick(mc.currentScreen, 0); + } + else + { + invokeMouseReleased(mc.currentScreen, 1); + } } } } @@ -614,11 +791,11 @@ else if(button == Buttons.B && mc.player != null && mc.player.inventory.getItemS } else { - if(button == Buttons.A) + if(button == ButtonBindings.PICKUP_ITEM.getButton()) { invokeMouseReleased(mc.currentScreen, 0); } - else if(button == Buttons.X) + else if(button == ButtonBindings.SPLIT_STACK.getButton()) { invokeMouseReleased(mc.currentScreen, 1); } @@ -632,13 +809,7 @@ else if(button == Buttons.X) private void cycleThirdPersonView() { Minecraft mc = Minecraft.getInstance(); - - mc.gameSettings.thirdPersonView++; - if(mc.gameSettings.thirdPersonView > 2) - { - mc.gameSettings.thirdPersonView = 0; - } - + mc.gameSettings.thirdPersonView = (mc.gameSettings.thirdPersonView + 1) % 3; if(mc.gameSettings.thirdPersonView == 0) { mc.gameRenderer.loadEntityShader(mc.getRenderViewEntity()); @@ -651,7 +822,7 @@ else if(mc.gameSettings.thirdPersonView == 1) private void scrollCreativeTabs(CreativeScreen creative, int dir) { - lastUse = 100; + this.setControllerInUse(); try { @@ -678,25 +849,214 @@ else if(dir < 0) } } + private void scrollRecipeTab(RecipeBookGui recipeBook, int dir) + { + RecipeBookGuiMixin recipeBookMixin = ((RecipeBookGuiMixin) recipeBook); + RecipeTabToggleWidget currentTab = recipeBookMixin.getCurrentTab(); + List tabs = recipeBookMixin.getRecipeTabs(); + int nextTabIndex = tabs.indexOf(currentTab) + dir; + if(nextTabIndex >= 0 && nextTabIndex < tabs.size()) + { + RecipeTabToggleWidget newTab = tabs.get(nextTabIndex); + currentTab.setStateTriggered(false); + recipeBookMixin.setCurrentTab(newTab); + newTab.setStateTriggered(true); + recipeBookMixin.invokeUpdateCollections(true); + Minecraft.getInstance().getSoundHandler().play(SimpleSound.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + } + } + + private void scrollRecipePage(RecipeBookGui recipeBook, int dir) + { + RecipeBookPageAccessor page = (RecipeBookPageAccessor)((RecipeBookGuiMixin) recipeBook).getRecipeBookPage(); + if(dir > 0 && page.getForwardButton().visible || dir < 0 && page.getBackButton().visible) + { + int currentPage = page.getCurrentPage(); + page.setCurrentPage(currentPage + dir); + page.invokeUpdateButtonsForPage(); + Minecraft.getInstance().getSoundHandler().play(SimpleSound.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + } + } + + private void navigateMouse(Screen screen, Navigate navigate) + { + Minecraft mc = Minecraft.getInstance(); + int mouseX = (int) (this.targetMouseX * (double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth()); + int mouseY = (int) (this.targetMouseY * (double) mc.getMainWindow().getScaledHeight() / (double) mc.getMainWindow().getHeight()); + + List points = this.gatherNavigationPoints(screen); + + // Gather any extra navigation points from event + GatherNavigationPointsEvent event = new GatherNavigationPointsEvent(); + MinecraftForge.EVENT_BUS.post(event); + points.addAll(event.getPoints()); + + // Get only the points that are in the target direction + List targetPoints = points.stream().filter(point -> navigate.getPredicate().test(point, mouseX, mouseY)).collect(Collectors.toList()); + if(targetPoints.isEmpty()) + return; + + Vec3d mousePos = new Vec3d(mouseX, mouseY, 0); + Optional minimumPointOptional = targetPoints.stream().min(navigate.getMinComparator(mouseX, mouseY)); + double minimumDelta = navigate.getKeyExtractor().apply(minimumPointOptional.get(), mousePos) + 10; + Optional targetPointOptional = targetPoints.stream().filter(point -> navigate.getKeyExtractor().apply(point, mousePos) <= minimumDelta).min(Comparator.comparing(p -> p.distanceTo(mouseX, mouseY))); + if(targetPointOptional.isPresent()) + { + this.performMouseDrag(this.targetMouseX, this.targetMouseY, 0, 0); + NavigationPoint targetPoint = targetPointOptional.get(); + int screenX = (int) (targetPoint.getX() / ((double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth())); + int screenY = (int) (targetPoint.getY() / ((double) mc.getMainWindow().getScaledHeight() / (double) mc.getMainWindow().getHeight())); + double lastTargetMouseX = this.targetMouseX; + double lastTargetMouseY = this.targetMouseY; + this.targetMouseX = this.prevTargetMouseX = screenX; + this.targetMouseY = this.prevTargetMouseY = screenY; + this.setMousePosition(screenX, screenY); + mc.getSoundHandler().play(SimpleSound.master(SoundEvents.ENTITY_ITEM_PICKUP, 2.0F)); + this.performMouseDrag(this.targetMouseX, this.targetMouseY, screenX - lastTargetMouseX, screenY - lastTargetMouseY); + } + } + + private List gatherNavigationPoints(Screen screen) + { + List points = new ArrayList<>(); + + if(screen instanceof ContainerScreen) + { + ContainerScreen containerScreen = (ContainerScreen) screen; + int guiLeft = containerScreen.getGuiLeft(); + int guiTop = containerScreen.getGuiTop(); + for(Slot slot : containerScreen.getContainer().inventorySlots) + { + if(containerScreen.getSlotUnderMouse() == slot) + continue; + int posX = guiLeft + slot.xPos + 8; + int posY = guiTop + slot.yPos + 8; + points.add(new SlotNavigationPoint(posX, posY, slot)); + } + } + + List widgets = new ArrayList<>(); + for(IGuiEventListener listener : screen.children()) + { + if(listener instanceof Widget) + { + widgets.add((Widget) listener); + } + } + + if(screen instanceof IRecipeShownListener) + { + RecipeBookGui recipeBook = ((IRecipeShownListener) screen).getRecipeGui(); + if(recipeBook.isVisible()) + { + widgets.add(((RecipeBookGuiMixin) recipeBook).getToggleRecipesBtn()); + widgets.addAll(((RecipeBookGuiMixin) recipeBook).getRecipeTabs()); + RecipeBookPage recipeBookPage = ((RecipeBookGuiMixin) recipeBook).getRecipeBookPage(); + widgets.addAll(((RecipeBookPageAccessor) recipeBookPage).getButtons()); + widgets.add(((RecipeBookPageAccessor) recipeBookPage).getForwardButton()); + widgets.add(((RecipeBookPageAccessor) recipeBookPage).getBackButton()); + } + } + + for(Widget widget : widgets) + { + if(widget == null || widget.isHovered() || !widget.visible) + continue; + int posX = widget.x + widget.getWidth() / 2; + int posY = widget.y + widget.getHeight() / 2; + points.add(new WidgetNavigationPoint(posX, posY, widget)); + } + + if(screen instanceof CreativeScreen) + { + int tabPage = CreativeScreenMixin.getTabPage(); + int start = tabPage * 10; + int end = Math.min(ItemGroup.GROUPS.length, ((tabPage + 1) * 10 + 2)); + for(int i = start; i < end; i++) + { + ItemGroup group = ItemGroup.GROUPS[i]; + if(group != null) + { + points.add(this.getCreativeTabPoint((CreativeScreen) screen, group)); + } + } + } + + if(Controllable.isJeiLoaded()) + { + points.addAll(JustEnoughItems.getNavigationPoints()); + } + + return points; + } + + /** + * Gets the navigation point of a creative tab. + */ + private BasicNavigationPoint getCreativeTabPoint(ContainerScreen screen, ItemGroup group) + { + boolean topRow = group.isOnTopRow(); + int column = group.getColumn(); + int width = 28; + int height = 32; + int x = screen.getGuiLeft() + width * column; + int y = screen.getGuiTop(); + x = group.isAlignedRight() ? screen.getGuiLeft() + screen.getXSize() - width * (6 - column) : (column > 0 ? x + column : x); + y = topRow ? y - width : y + (screen.getYSize() - 4); + return new BasicNavigationPoint(x + width / 2.0, y + height / 2.0); + } + + private void craftRecipeBookItem() + { + Minecraft mc = Minecraft.getInstance(); + if(mc.player == null) + return; + + if(!(mc.currentScreen instanceof ContainerScreen) || !(mc.currentScreen instanceof IRecipeShownListener)) + return; + + IRecipeShownListener listener = (IRecipeShownListener) mc.currentScreen; + if(!listener.getRecipeGui().isVisible()) + return; + + ContainerScreen screen = (ContainerScreen) mc.currentScreen; + if(!(screen.getContainer() instanceof RecipeBookContainer)) + return; + + RecipeBookPage recipeBookPage = ((RecipeBookGuiMixin) listener.getRecipeGui()).getRecipeBookPage(); + RecipeWidget recipe = ((RecipeBookPageAccessor) recipeBookPage).getButtons().stream().filter(Widget::isHovered).findFirst().orElse(null); + if(recipe != null) + { + RecipeBookContainer container = (RecipeBookContainer) screen.getContainer(); + Slot slot = container.getSlot(container.getOutputSlot()); + if(mc.player.inventory.getItemStack().isEmpty()) + { + this.invokeMouseClick(screen, GLFW.GLFW_MOUSE_BUTTON_LEFT, screen.getGuiLeft() + slot.xPos + 8, screen.getGuiTop() + slot.yPos + 8); + } + else + { + this.invokeMouseReleased(screen, GLFW.GLFW_MOUSE_BUTTON_LEFT, screen.getGuiLeft() + slot.xPos + 8, screen.getGuiTop() + slot.yPos + 8); + } + } + } + private void moveMouseToClosestSlot(boolean moving, Screen screen) { - nearSlot = false; + this.nearSlot = false; /* Makes the mouse attracted to slots. This helps with selecting items when using * a controller. */ if(screen instanceof ContainerScreen) { /* Prevents cursor from moving until at least some input is detected */ - if(!moved) return; + if(!this.moved) return; Minecraft mc = Minecraft.getInstance(); ContainerScreen guiContainer = (ContainerScreen) screen; - int guiLeft = (guiContainer.width - guiContainer.getXSize()) / 2; - int guiTop = (guiContainer.height - guiContainer.getYSize()) / 2; - int mouseX = (int) (targetMouseX * (double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth()); - int mouseY = (int) (targetMouseY * (double) mc.getMainWindow().getScaledHeight() / (double) mc.getMainWindow().getHeight()); - - //Slot closestSlot = guiContainer.getSlotUnderMouse(); + int guiLeft = guiContainer.getGuiLeft(); + int guiTop = guiContainer.getGuiTop(); + int mouseX = (int) (this.targetMouseX * (double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth()); + int mouseY = (int) (this.targetMouseY * (double) mc.getMainWindow().getScaledHeight() / (double) mc.getMainWindow().getHeight()); /* Finds the closest slot in the GUI within 14 pixels (inclusive) */ Slot closestSlot = null; @@ -716,7 +1076,7 @@ private void moveMouseToClosestSlot(boolean moving, Screen screen) if(closestSlot != null && (closestSlot.getHasStack() || !mc.player.inventory.getItemStack().isEmpty())) { - nearSlot = true; + this.nearSlot = true; int slotCenterXScaled = guiLeft + closestSlot.xPos + 8; int slotCenterYScaled = guiTop + closestSlot.yPos + 8; int slotCenterX = (int) (slotCenterXScaled / ((double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth())); @@ -728,29 +1088,44 @@ private void moveMouseToClosestSlot(boolean moving, Screen screen) { if(mouseX != slotCenterXScaled || mouseY != slotCenterYScaled) { - targetMouseX += deltaX * 0.75; - targetMouseY += deltaY * 0.75; + this.targetMouseX += deltaX * 0.75; + this.targetMouseY += deltaY * 0.75; } else { - mouseSpeedX = 0.0F; - mouseSpeedY = 0.0F; + this.mouseSpeedX = 0.0F; + this.mouseSpeedY = 0.0F; } } - mouseSpeedX *= 0.75F; - mouseSpeedY *= 0.75F; + this.mouseSpeedX *= 0.75F; + this.mouseSpeedY *= 0.75F; } else { - mouseSpeedX *= 0.1F; - mouseSpeedY *= 0.1F; + this.mouseSpeedX = 0.0F; + this.mouseSpeedY = 0.0F; } } else { - mouseSpeedX = 0.0F; - mouseSpeedY = 0.0F; + this.mouseSpeedX = 0.0F; + this.mouseSpeedY = 0.0F; + } + } + + private void setMousePosition(double mouseX, double mouseY) + { + if(Config.CLIENT.options.virtualMouse.get()) + { + this.virtualMouseX = mouseX; + this.virtualMouseY = mouseY; + } + else + { + Minecraft mc = Minecraft.getInstance(); + GLFW.glfwSetCursorPos(mc.getMainWindow().getHandle(), mouseX, mouseY); + this.preventReset = true; } } @@ -761,11 +1136,11 @@ private void handleCreativeScrolling(CreativeScreen creative, Controller control int i = (creative.getContainer().itemList.size() + 9 - 1) / 9 - 5; int dir = 0; - if(controller.getSDL2Controller().getButton(SDL_CONTROLLER_BUTTON_DPAD_UP) || controller.getRThumbStickYValue() <= -0.8F) + if(controller.getRThumbStickYValue() <= -0.8F) { dir = 1; } - else if(controller.getSDL2Controller().getButton(SDL_CONTROLLER_BUTTON_DPAD_DOWN) || controller.getRThumbStickYValue() >= 0.8F) + else if(controller.getRThumbStickYValue() >= 0.8F) { dir = -1; } @@ -785,6 +1160,40 @@ else if(controller.getSDL2Controller().getButton(SDL_CONTROLLER_BUTTON_DPAD_DOWN } } + private void handleListScrolling(AbstractList list, Controller controller) + { + double dir = 0; + if(Math.abs(controller.getRThumbStickYValue()) >= 0.2F) + { + this.setControllerInUse(); + dir = controller.getRThumbStickYValue(); + } + dir *= Minecraft.getInstance().getTickLength(); + list.setScrollAmount(list.getScrollAmount() + dir * 10); + } + + private double getMouseX() + { + Minecraft mc = Minecraft.getInstance(); + double mouseX = mc.mouseHelper.getMouseX(); + if(Controllable.getController() != null && Config.CLIENT.options.virtualMouse.get() && this.lastUse > 0) + { + mouseX = this.virtualMouseX; + } + return mouseX * (double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth(); + } + + private double getMouseY() + { + Minecraft mc = Minecraft.getInstance(); + double mouseY = mc.mouseHelper.getMouseY(); + if(Controllable.getController() != null && Config.CLIENT.options.virtualMouse.get() && this.lastUse > 0) + { + mouseY = this.virtualMouseY; + } + return mouseY * (double) mc.getMainWindow().getScaledHeight() / (double) mc.getMainWindow().getHeight(); + } + /** * Invokes a mouse click in a GUI. This is modified version that is designed for controllers. * Upon clicking, mouse released is called straight away to make sure dragging doesn't happen. @@ -794,34 +1203,32 @@ else if(controller.getSDL2Controller().getButton(SDL_CONTROLLER_BUTTON_DPAD_DOWN */ private void invokeMouseClick(Screen screen, int button) { - Minecraft mc = Minecraft.getInstance(); if(screen != null) { - double mouseX = mc.mouseHelper.getMouseX(); - double mouseY = mc.mouseHelper.getMouseY(); - if(Controllable.getController() != null && Controllable.getOptions().isVirtualMouse() && lastUse > 0) - { - mouseX = virtualMouseX; - mouseY = virtualMouseY; - } - mouseX = mouseX * (double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth(); - mouseY = mouseY * (double) mc.getMainWindow().getScaledHeight() / (double) mc.getMainWindow().getHeight(); + double mouseX = this.getMouseX(); + double mouseY = this.getMouseY(); + this.invokeMouseClick(screen, button, mouseX, mouseY); + } + } + private void invokeMouseClick(Screen screen, int button, double mouseX, double mouseY) + { + Minecraft mc = Minecraft.getInstance(); + if(screen != null) + { mc.mouseHelper.activeButton = button; mc.mouseHelper.eventTime = NativeUtil.getTime(); - double finalMouseX = mouseX; - double finalMouseY = mouseY; Screen.wrapScreenError(() -> { - boolean cancelled = ForgeHooksClient.onGuiMouseClickedPre(screen, finalMouseX, finalMouseY, button); + boolean cancelled = ForgeHooksClient.onGuiMouseClickedPre(screen, mouseX, mouseY, button); if(!cancelled) { - cancelled = screen.mouseClicked(finalMouseX, finalMouseY, button); + cancelled = screen.mouseClicked(mouseX, mouseY, button); } if(!cancelled) { - ForgeHooksClient.onGuiMouseClickedPost(screen, finalMouseX, finalMouseY, button); + ForgeHooksClient.onGuiMouseClickedPost(screen, mouseX, mouseY, button); } }, "mouseClicked event handler", screen.getClass().getCanonicalName()); } @@ -836,35 +1243,85 @@ private void invokeMouseClick(Screen screen, int button) */ private void invokeMouseReleased(Screen screen, int button) { - Minecraft mc = Minecraft.getInstance(); if(screen != null) { - double mouseX = mc.mouseHelper.getMouseX(); - double mouseY = mc.mouseHelper.getMouseY(); - if(Controllable.getController() != null && Controllable.getOptions().isVirtualMouse() && lastUse > 0) - { - mouseX = virtualMouseX; - mouseY = virtualMouseY; - } - mouseX = mouseX * (double) mc.getMainWindow().getScaledWidth() / (double) mc.getMainWindow().getWidth(); - mouseY = mouseY * (double) mc.getMainWindow().getScaledHeight() / (double) mc.getMainWindow().getHeight(); + double mouseX = this.getMouseX(); + double mouseY = this.getMouseY(); + this.invokeMouseReleased(screen, button, mouseX, mouseY); + } + } + private void invokeMouseReleased(Screen screen, int button, double mouseX, double mouseY) + { + Minecraft mc = Minecraft.getInstance(); + if(screen != null) + { mc.mouseHelper.activeButton = -1; - double finalMouseX = mouseX; - double finalMouseY = mouseY; Screen.wrapScreenError(() -> { - boolean cancelled = ForgeHooksClient.onGuiMouseReleasedPre(screen, finalMouseX, finalMouseY, button); + boolean cancelled = ForgeHooksClient.onGuiMouseReleasedPre(screen, mouseX, mouseY, button); if(!cancelled) { - cancelled = screen.mouseReleased(finalMouseX, finalMouseY, button); + cancelled = screen.mouseReleased(mouseX, mouseY, button); } if(!cancelled) { - ForgeHooksClient.onGuiMouseReleasedPost(screen, finalMouseX, finalMouseY, button); + ForgeHooksClient.onGuiMouseReleasedPost(screen, mouseX, mouseY, button); } }, "mouseReleased event handler", screen.getClass().getCanonicalName()); } } + + private enum Navigate + { + UP((p, x, y) -> p.getY() < y, (p, v) -> Math.abs(p.getX() - v.x)), + DOWN((p, x, y) -> p.getY() > y + 1, (p, v) -> Math.abs(p.getX() - v.x)), + LEFT((p, x, y) -> p.getX() < x, (p, v) -> Math.abs(p.getY() - v.y)), + RIGHT((p, x, y) -> p.getX() > x + 1, (p, v) -> Math.abs(p.getY() - v.y)); + + private NavigatePredicate predicate; + private BiFunction keyExtractor; + + Navigate(NavigatePredicate predicate, BiFunction keyExtractor) + { + this.predicate = predicate; + this.keyExtractor = keyExtractor; + } + + public NavigatePredicate getPredicate() + { + return this.predicate; + } + + public BiFunction getKeyExtractor() + { + return this.keyExtractor; + } + + public Comparator getMinComparator(int mouseX, int mouseY) + { + return Comparator.comparing(p -> this.keyExtractor.apply(p, new Vec3d(mouseX, mouseY, 0))); + } + + public static void main(String[] args) + { + int slotX = 10; + int slotY = 20; + int mouseX = 50; + int mouseY = 20; + angle(new SlotNavigationPoint(slotX, slotY, null), mouseX, mouseY, 0); + } + + private static boolean angle(NavigationPoint point, int mouseX, int mouseY, double offset) + { + double angle = Math.toDegrees(Math.atan2(point.getY() - mouseY, point.getX() - mouseX)) + offset; + return angle > -45 && angle < 45; + } + } + + private interface NavigatePredicate + { + boolean test(NavigationPoint point, int mouseX, int mouseY); + } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/ControllerManager.java b/src/main/java/com/mrcrayfish/controllable/client/ControllerManager.java new file mode 100644 index 00000000..92fe1494 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/ControllerManager.java @@ -0,0 +1,76 @@ +package com.mrcrayfish.controllable.client; + +import org.lwjgl.glfw.GLFW; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Author: MrCrayfish + */ +public class ControllerManager +{ + private Set listeners = new HashSet<>(); + private Map controllers = new HashMap<>(); + + public void update() + { + int connectedCount = 0; + for(int jid = GLFW.GLFW_JOYSTICK_1; jid <= GLFW.GLFW_JOYSTICK_LAST; jid++) + { + if(GLFW.glfwJoystickIsGamepad(jid)) + { + connectedCount++; + } + } + + if(connectedCount == this.controllers.size()) + return; + + Map oldControllers = this.controllers; + Map newControllers = new HashMap<>(); + for(int jid = GLFW.GLFW_JOYSTICK_1; jid <= GLFW.GLFW_JOYSTICK_LAST; jid++) + { + if(GLFW.glfwJoystickIsGamepad(jid)) + { + String controllerName = GLFW.glfwGetGamepadName(jid); + newControllers.put(jid, controllerName); + } + } + + this.controllers = newControllers; + + newControllers.forEach((jid, name) -> + { + if(!oldControllers.containsKey(jid)) + { + this.listeners.forEach(listener -> listener.connected(jid)); + } + }); + + oldControllers.forEach((jid, name) -> + { + if(!newControllers.containsKey(jid)) + { + this.listeners.forEach(listener -> listener.disconnected(jid)); + } + }); + } + + public Map getControllers() + { + return this.controllers; + } + + public int getControllerCount() + { + return this.controllers.size(); + } + + public void addControllerListener(IControllerListener listener) + { + this.listeners.add(listener); + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/client/ControllerProperties.java b/src/main/java/com/mrcrayfish/controllable/client/ControllerProperties.java index 20bc6cd2..dd4e36be 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/ControllerProperties.java +++ b/src/main/java/com/mrcrayfish/controllable/client/ControllerProperties.java @@ -32,9 +32,12 @@ public static void load(File configFolder) } if(file.exists()) { - properties.load(new FileInputStream(file)); - lastController = properties.getProperty("CurrentController", ""); - selectedMapping = properties.getProperty("SelectedMapping", ""); + try(FileInputStream is = new FileInputStream(file)) + { + properties.load(is); + lastController = properties.getProperty("CurrentController", ""); + selectedMapping = properties.getProperty("SelectedMapping", ""); + } } } catch(IOException e) diff --git a/src/main/java/com/mrcrayfish/controllable/client/ControllerToast.java b/src/main/java/com/mrcrayfish/controllable/client/ControllerToast.java index 3aefc3e2..f48f98de 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/ControllerToast.java +++ b/src/main/java/com/mrcrayfish/controllable/client/ControllerToast.java @@ -1,6 +1,6 @@ package com.mrcrayfish.controllable.client; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.mrcrayfish.controllable.client.gui.ControllerLayoutScreen; import net.minecraft.client.gui.toasts.IToast; @@ -32,10 +32,10 @@ public Visibility draw(ToastGui toastGui, long delta) toastGui.getMinecraft().getTextureManager().bindTexture(ControllerLayoutScreen.TEXTURE); toastGui.blit(8, 8, 20, 43, 20, 16); - String title = toastGui.getMinecraft().fontRenderer.trimStringToWidth(controllerName, 120); + String title = toastGui.getMinecraft().fontRenderer.trimStringToWidth(this.controllerName, 120); //TODO test toastGui.getMinecraft().fontRenderer.drawString(TextFormatting.DARK_GRAY + title, 35, 7, 0); - String message = connected ? + String message = this.connected ? TextFormatting.DARK_GREEN.toString() + TextFormatting.BOLD.toString() + I18n.format("controllable.toast.connected") : TextFormatting.RED.toString() + TextFormatting.BOLD.toString() + I18n.format("controllable.toast.disconnected"); toastGui.getMinecraft().fontRenderer.drawString(TextFormatting.BOLD + message, 35, 18, 0); diff --git a/src/main/java/com/mrcrayfish/controllable/client/CursorType.java b/src/main/java/com/mrcrayfish/controllable/client/CursorType.java index 095c65d2..314bf40b 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/CursorType.java +++ b/src/main/java/com/mrcrayfish/controllable/client/CursorType.java @@ -21,7 +21,7 @@ public enum CursorType implements IStringSerializable @Override public String getName() { - return id; + return this.id; } public static CursorType byId(String id) diff --git a/src/main/java/com/mrcrayfish/controllable/client/GuiEvents.java b/src/main/java/com/mrcrayfish/controllable/client/GuiEvents.java index ded42f32..d91a56a9 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/GuiEvents.java +++ b/src/main/java/com/mrcrayfish/controllable/client/GuiEvents.java @@ -1,9 +1,8 @@ package com.mrcrayfish.controllable.client; import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; -import com.mrcrayfish.controllable.Controllable; +import com.mrcrayfish.controllable.Config; import com.mrcrayfish.controllable.client.gui.ControllerSelectionScreen; import com.mrcrayfish.controllable.client.gui.widget.ControllerButton; import net.minecraft.client.Minecraft; @@ -12,7 +11,6 @@ import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; -import uk.co.electronstudio.sdl2gdx.SDL2ControllerManager; import java.util.List; @@ -41,9 +39,9 @@ public class GuiEvents EXCLUDED_TYPES = builder.build(); } - private SDL2ControllerManager manager; + private ControllerManager manager; - public GuiEvents(SDL2ControllerManager manager) + public GuiEvents(ControllerManager manager) { this.manager = manager; } @@ -64,7 +62,7 @@ public void onOpenGui(GuiScreenEvent.InitGuiEvent.Post event) @SubscribeEvent(priority = EventPriority.LOWEST) public void onRenderOverlay(RenderGameOverlayEvent.Pre event) { - if(Controllable.getOptions().useConsoleHotbar()) + if(Config.CLIENT.options.consoleHotbar.get()) { if(EXCLUDED_TYPES.contains(event.getType())) { @@ -77,7 +75,7 @@ public void onRenderOverlay(RenderGameOverlayEvent.Pre event) @SubscribeEvent public void onRenderOverlay(RenderGameOverlayEvent.Post event) { - if(Controllable.getOptions().useConsoleHotbar()) + if(Config.CLIENT.options.consoleHotbar.get()) { if(EXCLUDED_TYPES.contains(event.getType())) { diff --git a/src/main/java/com/mrcrayfish/controllable/client/Hooks.java b/src/main/java/com/mrcrayfish/controllable/client/Hooks.java deleted file mode 100644 index cd9fc1e1..00000000 --- a/src/main/java/com/mrcrayfish/controllable/client/Hooks.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.mrcrayfish.controllable.client; - -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mrcrayfish.controllable.Controllable; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.util.InputMappings; -import net.minecraftforge.client.event.GuiScreenEvent; -import net.minecraftforge.common.MinecraftForge; -import org.lwjgl.glfw.GLFW; - -/** - * Author: MrCrayfish - */ -@SuppressWarnings("unused") -public class Hooks -{ - /** - * Used in order to fix block breaking progress. This method is linked via ASM. - */ - @SuppressWarnings("unused") - public static boolean isLeftClicking() - { - Minecraft mc = Minecraft.getInstance(); - boolean isLeftClicking = mc.gameSettings.keyBindAttack.isKeyDown(); - Controller controller = Controllable.getController(); - if(controller != null) - { - if(ButtonBindings.ATTACK.isButtonDown()) - { - isLeftClicking = true; - } - } - boolean usingVirtualMouse = (Controllable.getOptions().isVirtualMouse() && Controllable.getInput().getLastUse() > 0); - return mc.currentScreen == null && isLeftClicking && (mc.mouseHelper.isMouseGrabbed() || usingVirtualMouse); - } - - /** - * Used in order to fix actions like eating or pulling bow back. This method is linked via ASM. - */ - @SuppressWarnings("unused") - public static boolean isRightClicking() - { - Minecraft mc = Minecraft.getInstance(); - boolean isRightClicking = mc.gameSettings.keyBindUseItem.isKeyDown(); - Controller controller = Controllable.getController(); - if(controller != null) - { - if(ButtonBindings.USE_ITEM.isButtonDown()) - { - isRightClicking = true; - } - } - return isRightClicking; - } - - /** - * Used in order to fix the quick move check in inventories. This method is linked via ASM. - */ - @SuppressWarnings("unused") - public static boolean canQuickMove() - { - boolean canQuickMove = InputMappings.isKeyDown(Minecraft.getInstance().getMainWindow().getHandle(), GLFW.GLFW_KEY_LEFT_SHIFT) || InputMappings.isKeyDown(Minecraft.getInstance().getMainWindow().getHandle(), GLFW.GLFW_KEY_RIGHT_SHIFT); - Controller controller = Controllable.getController(); - if(controller != null) - { - if(ButtonBindings.QUICK_MOVE.isButtonDown()) - { - canQuickMove = true; - } - } - return canQuickMove; - } - - /** - * Allows the player list to be shown. This method is linked via ASM. - */ - @SuppressWarnings("unused") - public static boolean canShowPlayerList() - { - Minecraft mc = Minecraft.getInstance(); - boolean canShowPlayerList = mc.gameSettings.keyBindPlayerList.isKeyDown(); - Controller controller = Controllable.getController(); - if(controller != null) - { - if(ButtonBindings.PLAYER_LIST.isButtonDown()) - { - canShowPlayerList = true; - } - } - return canShowPlayerList; - } - - /** - * Fixes the mouse position when virtual mouse is turned on for controllers. This method is linked via ASM. - */ - @SuppressWarnings("unused") - public static void drawScreen(Screen screen, int mouseX, int mouseY, float partialTicks) - { - ControllerInput input = Controllable.getInput(); - if(Controllable.getController() != null && Controllable.getOptions().isVirtualMouse() && input.getLastUse() > 0) - { - Minecraft minecraft = Minecraft.getInstance(); - mouseX = (int) (input.getVirtualMouseX() * (double) minecraft.getMainWindow().getScaledWidth() / (double) minecraft.getMainWindow().getWidth()); - mouseY = (int) (input.getVirtualMouseY() * (double) minecraft.getMainWindow().getScaledHeight() / (double) minecraft.getMainWindow().getHeight()); - } - if(!MinecraftForge.EVENT_BUS.post(new GuiScreenEvent.DrawScreenEvent.Pre(screen, mouseX, mouseY, partialTicks))) - { - screen.render(mouseX, mouseY, partialTicks); - } - MinecraftForge.EVENT_BUS.post(new GuiScreenEvent.DrawScreenEvent.Post(screen, mouseX, mouseY, partialTicks)); - } - - /** - * Fixes selected item name rendering not being offset by console hotbar - */ - @SuppressWarnings("unused") - public static void applyHotbarOffset() - { - if(Controllable.getOptions().useConsoleHotbar()) - { - RenderSystem.translated(0, -20, 0); - } - } -} diff --git a/src/main/java/com/mrcrayfish/controllable/client/IControllerListener.java b/src/main/java/com/mrcrayfish/controllable/client/IControllerListener.java new file mode 100644 index 00000000..0b393cb9 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/IControllerListener.java @@ -0,0 +1,11 @@ +package com.mrcrayfish.controllable.client; + +/** + * Author: MrCrayfish + */ +public interface IControllerListener +{ + void connected(int jid); + + void disconnected(int jid); +} diff --git a/src/main/java/com/mrcrayfish/controllable/client/IToolTip.java b/src/main/java/com/mrcrayfish/controllable/client/IToolTip.java new file mode 100644 index 00000000..7c1016e3 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/IToolTip.java @@ -0,0 +1,12 @@ +package com.mrcrayfish.controllable.client; + +import java.util.List; + +/** + * Author: MrCrayfish + */ +public interface IToolTip +{ + List getToolTip(); +} + diff --git a/src/main/java/com/mrcrayfish/controllable/client/Mappings.java b/src/main/java/com/mrcrayfish/controllable/client/Mappings.java index 1ef3a61f..d448131a 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/Mappings.java +++ b/src/main/java/com/mrcrayfish/controllable/client/Mappings.java @@ -1,7 +1,5 @@ package com.mrcrayfish.controllable.client; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; import com.google.gson.*; import com.mrcrayfish.controllable.Controllable; import net.minecraft.client.Minecraft; @@ -17,6 +15,8 @@ */ public class Mappings { + private static final Gson GSON = new GsonBuilder().registerTypeAdapter(Entry.class, new Entry.Serializer()).create(); + private static final Map MAPPINGS = new HashMap<>(); private static boolean loaded = false; @@ -97,7 +97,9 @@ private static void loadInternalMapping(String mappingName) { try(Reader reader = new InputStreamReader(Mappings.class.getResourceAsStream("/mappings/" + mappingName + ".json"))) { - loadMapping(reader).internal = true; + Entry entry = GSON.fromJson(reader, Entry.class); + entry.internal = true; + MAPPINGS.put(entry.getId(), entry); } catch(IOException e) { @@ -109,7 +111,8 @@ private static void loadMapping(File file) { try(Reader reader = new InputStreamReader(new FileInputStream(file))) { - loadMapping(reader); + Entry entry = GSON.fromJson(reader, Entry.class); + MAPPINGS.put(entry.getId(), entry); } catch(IOException e) { @@ -117,27 +120,6 @@ private static void loadMapping(File file) } } - private static Entry loadMapping(Reader reader) - { - JsonElement element = new JsonParser().parse(reader); - String id = element.getAsJsonObject().get("id").getAsString(); - String name = element.getAsJsonObject().get("name").getAsString(); - Map reassignments = new HashMap<>(); - if(element.getAsJsonObject().has("reassign")) - { - JsonArray array = element.getAsJsonObject().get("reassign").getAsJsonArray(); - array.forEach(jsonElement -> - { - int index = jsonElement.getAsJsonObject().get("index").getAsInt(); - int with = jsonElement.getAsJsonObject().get("with").getAsInt(); - reassignments.put(index, with); - }); - } - Entry entry = new Entry(id, name, reassignments); - MAPPINGS.put(id, entry); - return entry; - } - public static void updateControllerMappings(Controller controller) { controller.setMapping(MAPPINGS.get(controller.getName())); @@ -147,14 +129,21 @@ public static class Entry { private String id; private String name; - private BiMap reassignments; + private Map reassignments; + private boolean switchThumbsticks; + private boolean flipLeftX; + private boolean flipLeftY; + private boolean flipRightX; + private boolean flipRightY; private boolean internal; + private Entry() {} + public Entry(String id, String name, Map reassignments) { this.id = id; this.name = name; - this.reassignments = HashBiMap.create(reassignments); + this.reassignments = reassignments; } public String getId() @@ -167,19 +156,69 @@ public String getName() return name; } - public BiMap getReassignments() + public Map getReassignments() + { + return this.reassignments; + } + + public boolean isThumbsticksSwitched() + { + return switchThumbsticks; + } + + public void setSwitchThumbsticks(boolean switchThumbsticks) + { + this.switchThumbsticks = switchThumbsticks; + } + + public boolean isFlipLeftX() { - return reassignments; + return this.flipLeftX; + } + + public void setFlipLeftX(boolean flipLeftX) + { + this.flipLeftX = flipLeftX; + } + + public boolean isFlipLeftY() + { + return this.flipLeftY; + } + + public void setFlipLeftY(boolean flipLeftY) + { + this.flipLeftY = flipLeftY; + } + + public boolean isFlipRightX() + { + return this.flipRightX; + } + + public void setFlipRightX(boolean flipRightX) + { + this.flipRightX = flipRightX; + } + + public boolean isFlipRightY() + { + return this.flipRightY; + } + + public void setFlipRightY(boolean flipRightY) + { + this.flipRightY = flipRightY; } public boolean isInternal() { - return internal; + return this.internal; } public int remap(int button) { - Integer value = reassignments.get(button); + Integer value = this.reassignments.get(button); if(value != null) { return value; @@ -187,6 +226,20 @@ public int remap(int button) return button; } + public Entry copy() + { + Entry entry = new Entry(); + entry.id = this.id; + entry.name = this.name; + entry.reassignments = new HashMap<>(this.reassignments); + entry.switchThumbsticks = this.switchThumbsticks; + entry.flipLeftX = this.flipLeftX; + entry.flipLeftY = this.flipLeftY; + entry.flipRightX = this.flipRightX; + entry.flipRightY = this.flipRightY; + return entry; + } + public void save() { try @@ -194,10 +247,7 @@ public void save() File mappingsFolder = new File(Minecraft.getInstance().gameDir, "config/controllable/mappings"); mappingsFolder.mkdirs(); String name = id.replaceAll("\\s+", "_").toLowerCase(Locale.ENGLISH) + ".json"; - GsonBuilder builder = new GsonBuilder(); - builder.registerTypeAdapter(Entry.class, new Serializer()); - Gson gson = builder.create(); - String json = gson.toJson(this); + String json = GSON.toJson(this); FileOutputStream fos = new FileOutputStream(new File(mappingsFolder, name)); fos.write(json.getBytes()); fos.close(); @@ -208,7 +258,7 @@ public void save() } } - public static class Serializer implements JsonSerializer + public static class Serializer implements JsonSerializer, JsonDeserializer { @Override public JsonElement serialize(Entry src, Type typeOfSrc, JsonSerializationContext context) @@ -216,6 +266,13 @@ public JsonElement serialize(Entry src, Type typeOfSrc, JsonSerializationContext JsonObject object = new JsonObject(); object.addProperty("id", src.id); object.addProperty("name", src.name); + JsonObject thumbsticks = new JsonObject(); + thumbsticks.addProperty("switch", src.switchThumbsticks); + thumbsticks.addProperty("flipLeftX", src.flipLeftX); + thumbsticks.addProperty("flipLeftY", src.flipLeftY); + thumbsticks.addProperty("flipRightX", src.flipRightX); + thumbsticks.addProperty("flipRightY", src.flipRightY); + object.add("thumbsticks", thumbsticks); JsonArray array = new JsonArray(); src.reassignments.forEach((index, with) -> { JsonObject entry = new JsonObject(); @@ -226,6 +283,40 @@ public JsonElement serialize(Entry src, Type typeOfSrc, JsonSerializationContext object.add("reassign", array); return object; } + + @Override + public Entry deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException + { + Entry entry = new Entry(); + JsonObject object = json.getAsJsonObject(); + entry.id = object.get("id").getAsString(); + entry.name = object.get("name").getAsString(); + JsonObject thumbsticks = object.getAsJsonObject("thumbsticks"); + if(thumbsticks != null) + { + entry.switchThumbsticks = this.getBoolean(thumbsticks, "switchThumbsticks", false); + entry.flipLeftX = this.getBoolean(thumbsticks, "flipLeftX", false); + entry.flipLeftY = this.getBoolean(thumbsticks, "flipLeftY", false); + entry.flipRightX = this.getBoolean(thumbsticks, "flipRightX", false); + entry.flipRightY = this.getBoolean(thumbsticks, "flipRightY", false); + } + Map reassignments = new HashMap<>(); + object.getAsJsonArray("reassign").forEach(e -> { + JsonObject o = e.getAsJsonObject(); + reassignments.put(o.get("index").getAsInt(), o.get("with").getAsInt()); + }); + entry.reassignments = reassignments; + return entry; + } + + private boolean getBoolean(JsonObject object, String name, boolean defaultVal) + { + if(object.has(name)) + { + return object.get(name).getAsBoolean(); + } + return defaultVal; + } } } } \ No newline at end of file diff --git a/src/main/java/com/mrcrayfish/controllable/client/RenderEvents.java b/src/main/java/com/mrcrayfish/controllable/client/RenderEvents.java index e713f8e5..ade50e8c 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/RenderEvents.java +++ b/src/main/java/com/mrcrayfish/controllable/client/RenderEvents.java @@ -1,10 +1,12 @@ package com.mrcrayfish.controllable.client; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; +import com.mrcrayfish.controllable.Config; import com.mrcrayfish.controllable.Controllable; import com.mrcrayfish.controllable.Reference; import com.mrcrayfish.controllable.event.AvailableActionsEvent; +import com.mrcrayfish.controllable.event.GatherActionsEvent; import com.mrcrayfish.controllable.event.RenderAvailableActionsEvent; import com.mrcrayfish.controllable.event.RenderPlayerPreviewEvent; import net.minecraft.block.ContainerBlock; @@ -27,6 +29,7 @@ import java.awt.*; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; /** @@ -34,7 +37,7 @@ */ public class RenderEvents { - private static final ResourceLocation CONTROLLER_BUTTONS = new ResourceLocation(Reference.MOD_ID, "textures/gui/buttons.png"); + public static final ResourceLocation CONTROLLER_BUTTONS = new ResourceLocation(Reference.MOD_ID, "textures/gui/buttons.png"); private Map actions = new HashMap<>(); @@ -44,7 +47,15 @@ public void onClientTick(TickEvent.ClientTickEvent event) Minecraft mc = Minecraft.getInstance(); if(event.phase == TickEvent.Phase.START && mc.player != null && !mc.gameSettings.hideGUI) { - actions = new HashMap<>(); + this.actions.clear(); + + Map actionMap = new LinkedHashMap<>(); + + ActionVisibility visibility = Config.CLIENT.options.showActions.get(); + if(visibility == ActionVisibility.NONE) + return; + + boolean verbose = visibility == ActionVisibility.ALL; if(mc.currentScreen instanceof ContainerScreen) { @@ -56,19 +67,19 @@ public void onClientTick(TickEvent.ClientTickEvent event) Slot slot = container.getSlotUnderMouse(); if(slot.getHasStack()) { - actions.put(Buttons.A, new Action(I18n.format("controllable.action.pickup_stack"), Action.Side.LEFT)); - actions.put(Buttons.X, new Action(I18n.format("controllable.action.pickup_item"), Action.Side.LEFT)); - actions.put(Buttons.B, new Action(I18n.format("controllable.action.quick_move"), Action.Side.LEFT)); + actionMap.put(ButtonBindings.PICKUP_ITEM, new Action(I18n.format("controllable.action.pickup_stack"), Action.Side.LEFT)); + actionMap.put(ButtonBindings.SPLIT_STACK, new Action(I18n.format("controllable.action.pickup_item"), Action.Side.LEFT)); + actionMap.put(ButtonBindings.QUICK_MOVE, new Action(I18n.format("controllable.action.quick_move"), Action.Side.LEFT)); } } } else { - actions.put(Buttons.A, new Action(I18n.format("controllable.action.place_stack"), Action.Side.LEFT)); - actions.put(Buttons.X, new Action(I18n.format("controllable.action.place_item"), Action.Side.LEFT)); + actionMap.put(ButtonBindings.PICKUP_ITEM, new Action(I18n.format("controllable.action.place_stack"), Action.Side.LEFT)); + actionMap.put(ButtonBindings.SPLIT_STACK, new Action(I18n.format("controllable.action.place_item"), Action.Side.LEFT)); } - actions.put(Buttons.Y, new Action(I18n.format("controllable.action.close_inventory"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.INVENTORY, new Action(I18n.format("controllable.action.close_inventory"), Action.Side.RIGHT)); } else if(mc.currentScreen == null) { @@ -84,11 +95,11 @@ else if(mc.currentScreen == null) { if(blockHit) { - actions.put(Buttons.RIGHT_TRIGGER, new Action(I18n.format("controllable.action.break"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.ATTACK, new Action(I18n.format("controllable.action.break"), Action.Side.RIGHT)); } else { - actions.put(Buttons.RIGHT_TRIGGER, new Action(I18n.format("controllable.action.attack"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.ATTACK, new Action(I18n.format("controllable.action.attack"), Action.Side.RIGHT)); } } @@ -100,17 +111,17 @@ else if(mc.currentScreen == null) case EAT: if(mc.player.getFoodStats().needFood()) { - actions.put(Buttons.LEFT_TRIGGER, new Action(I18n.format("controllable.action.eat"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.USE_ITEM, new Action(I18n.format("controllable.action.eat"), Action.Side.RIGHT)); } break; case DRINK: - actions.put(Buttons.LEFT_TRIGGER, new Action(I18n.format("controllable.action.drink"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.USE_ITEM, new Action(I18n.format("controllable.action.drink"), Action.Side.RIGHT)); break; case BLOCK: - actions.put(Buttons.LEFT_TRIGGER, new Action(I18n.format("controllable.action.block"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.USE_ITEM, new Action(I18n.format("controllable.action.block"), Action.Side.RIGHT)); break; case BOW: - actions.put(Buttons.LEFT_TRIGGER, new Action(I18n.format("controllable.action.pull_bow"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.USE_ITEM, new Action(I18n.format("controllable.action.pull_bow"), Action.Side.RIGHT)); break; } } @@ -123,17 +134,17 @@ else if(mc.currentScreen == null) case EAT: if(mc.player.getFoodStats().needFood()) { - actions.put(Buttons.LEFT_TRIGGER, new Action(I18n.format("controllable.action.eat"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.USE_ITEM, new Action(I18n.format("controllable.action.eat"), Action.Side.RIGHT)); } break; case DRINK: - actions.put(Buttons.LEFT_TRIGGER, new Action(I18n.format("controllable.action.drink"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.USE_ITEM, new Action(I18n.format("controllable.action.drink"), Action.Side.RIGHT)); break; case BLOCK: - actions.put(Buttons.LEFT_TRIGGER, new Action(I18n.format("controllable.action.block"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.USE_ITEM, new Action(I18n.format("controllable.action.block"), Action.Side.RIGHT)); break; case BOW: - actions.put(Buttons.LEFT_TRIGGER, new Action(I18n.format("controllable.action.pull_bow"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.USE_ITEM, new Action(I18n.format("controllable.action.pull_bow"), Action.Side.RIGHT)); break; } } @@ -155,44 +166,49 @@ else if(currentItem.getItem() instanceof BlockItem) actions.put(Buttons.LEFT_TRIGGER, new Action(I18n.format("controllable.action.place_block"), Action.Side.RIGHT)); } }*/ - actions.put(Buttons.LEFT_TRIGGER, new Action(I18n.format("controllable.action.place_block"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.USE_ITEM, new Action(I18n.format("controllable.action.place_block"), Action.Side.RIGHT)); } } else if(!currentItem.isEmpty() && !mc.player.isHandActive()) { - actions.put(Buttons.LEFT_TRIGGER, new Action(I18n.format("controllable.action.use_item"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.USE_ITEM, new Action(I18n.format("controllable.action.use_item"), Action.Side.RIGHT)); } - if(!mc.player.func_225608_bj_() && blockHit && canOpenBlock && !mc.player.isHandActive()) + if(!mc.player.isCrouching() && blockHit && canOpenBlock && !mc.player.isHandActive()) { - actions.put(Buttons.LEFT_TRIGGER, new Action(I18n.format("controllable.action.interact"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.USE_ITEM, new Action(I18n.format("controllable.action.interact"), Action.Side.RIGHT)); } - //actions.put(Buttons.A, new Action(I18n.format("controllable.action.jump"), Action.Side.LEFT)); //TODO make a verbose action config option + if(verbose) + { + actionMap.put(ButtonBindings.JUMP, new Action(I18n.format("controllable.action.jump"), Action.Side.LEFT)); + } - actions.put(Buttons.Y, new Action(I18n.format("controllable.action.inventory"), Action.Side.LEFT)); + actionMap.put(ButtonBindings.INVENTORY, new Action(I18n.format("controllable.action.inventory"), Action.Side.LEFT)); - if(!mc.player.getHeldItemOffhand().isEmpty() || !mc.player.inventory.getCurrentItem().isEmpty()) + if(verbose && (!mc.player.getHeldItemOffhand().isEmpty() || !mc.player.inventory.getCurrentItem().isEmpty())) { - //actions.put(Buttons.X, new Action(I18n.format("controllable.action.swap_hands"), Action.Side.LEFT)); //TODO make a verbose action config option + actionMap.put(ButtonBindings.SWAP_HANDS, new Action(I18n.format("controllable.action.swap_hands"), Action.Side.LEFT)); } if(mc.player.isPassenger()) { - actions.put(Buttons.LEFT_THUMB_STICK, new Action(I18n.format("controllable.action.dismount"), Action.Side.RIGHT)); + actionMap.put(ButtonBindings.SNEAK, new Action(I18n.format("controllable.action.dismount"), Action.Side.RIGHT)); } - else + else if(verbose) { - //actions.put(Buttons.LEFT_THUMB_STICK, new Action(I18n.format("controllable.action.sneak"), Action.Side.RIGHT)); //TODO make a verbose action config option + actionMap.put(ButtonBindings.SNEAK, new Action(I18n.format("controllable.action.sneak"), Action.Side.RIGHT)); } if(!mc.player.inventory.getCurrentItem().isEmpty()) { - actions.put(Buttons.DPAD_DOWN, new Action(I18n.format("controllable.action.drop_item"), Action.Side.LEFT)); + actionMap.put(ButtonBindings.DROP_ITEM, new Action(I18n.format("controllable.action.drop_item"), Action.Side.LEFT)); } } - MinecraftForge.EVENT_BUS.post(new AvailableActionsEvent(actions)); + MinecraftForge.EVENT_BUS.post(new AvailableActionsEvent(this.actions)); + MinecraftForge.EVENT_BUS.post(new GatherActionsEvent(actionMap, visibility)); + actionMap.forEach((binding, action) -> this.actions.put(binding.getButton(), action)); } } @@ -221,11 +237,12 @@ public void onRenderScreen(TickEvent.RenderTickEvent event) int leftIndex = 0; int rightIndex = 0; - for(Integer button : actions.keySet()) + for(int button : this.actions.keySet()) { - Action action = actions.get(button); + Action action = this.actions.get(button); Action.Side side = action.getSide(); +/* int remappedButton = button; Controller controller = Controllable.getController(); Mappings.Entry mapping = controller.getMapping(); @@ -233,9 +250,10 @@ public void onRenderScreen(TickEvent.RenderTickEvent event) { remappedButton = mapping.remap(button); } +*/ - int texU = remappedButton * 13; - int texV = Controllable.getOptions().getControllerType().ordinal() * 13; + int texU = button * 13; + int texV = Config.CLIENT.options.controllerIcons.get().ordinal() * 13; int size = 13; int x = side == Action.Side.LEFT ? 5 : mc.getMainWindow().getScaledWidth() - 5 - size; @@ -266,7 +284,7 @@ public void onRenderScreen(TickEvent.RenderTickEvent event) } } - if(mc.player != null && mc.currentScreen == null && Controllable.getOptions().isRenderMiniPlayer()) + if(mc.player != null && mc.currentScreen == null && Config.CLIENT.options.renderMiniPlayer.get()) { if(!MinecraftForge.EVENT_BUS.post(new RenderPlayerPreviewEvent())) { diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/ButtonBindingList.java b/src/main/java/com/mrcrayfish/controllable/client/gui/ButtonBindingList.java new file mode 100644 index 00000000..2618e67c --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/ButtonBindingList.java @@ -0,0 +1,158 @@ +package com.mrcrayfish.controllable.client.gui; + +import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mrcrayfish.controllable.client.BindingRegistry; +import com.mrcrayfish.controllable.client.ButtonBinding; +import com.mrcrayfish.controllable.client.gui.widget.ButtonBindingButton; +import com.mrcrayfish.controllable.client.gui.widget.ImageButton; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.IGuiEventListener; +import net.minecraft.client.gui.widget.list.AbstractOptionList; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; +import org.lwjgl.glfw.GLFW; + +import java.util.*; + +/** + * Author: MrCrayfish + */ +public class ButtonBindingList extends AbstractOptionList +{ + private ButtonBindingScreen screen; + private Map> categories = new LinkedHashMap<>(); + + public ButtonBindingList(ButtonBindingScreen screen, Minecraft mc, int widthIn, int heightIn, int topIn, int bottomIn, int itemHeightIn) + { + super(mc, widthIn, heightIn, topIn, bottomIn, itemHeightIn); + this.screen = screen; + + // Initialize map with categories to have a predictable order (map is linked) + this.categories.put("key.categories.movement", new ArrayList<>()); + this.categories.put("key.categories.gameplay", new ArrayList<>()); + this.categories.put("key.categories.inventory", new ArrayList<>()); + this.categories.put("key.categories.creative", new ArrayList<>()); + this.categories.put("key.categories.multiplayer", new ArrayList<>()); + this.categories.put("key.categories.ui", new ArrayList<>()); + this.categories.put("key.categories.misc", new ArrayList<>()); + + // Add all button bindings to the appropriate category or create a new one + BindingRegistry.getInstance().getBindings().stream().filter(ButtonBinding::isNotReserved).forEach(binding -> + { + List list = this.categories.computeIfAbsent(binding.getCategory(), category -> new ArrayList<>()); + list.add(binding); + }); + + // Sorts the button binding list then adds new entries to the option list for each category + this.categories.forEach((category, list) -> + { + if(!list.isEmpty()) + { + Collections.sort(list); + this.addEntry(new CategoryEntry(new TranslationTextComponent(category))); + list.forEach(binding -> this.addEntry(new BindingEntry(binding))); + } + }); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) + { + if(this.screen.isWaitingForButtonInput()) + return true; + return super.mouseClicked(mouseX, mouseY, button); + } + + abstract class Entry extends AbstractOptionList.Entry {} + + protected class CategoryEntry extends Entry + { + private final ITextComponent label; + private final int labelWidth; + + protected CategoryEntry(ITextComponent label) + { + this.label = label; + this.labelWidth = ButtonBindingList.this.minecraft.fontRenderer.getStringWidth(this.label.getFormattedText()); + } + + @Override + public boolean changeFocus(boolean focus) + { + return false; + } + + @Override + public List children() + { + return Collections.emptyList(); + } + + @Override + public void render(int x, int y, int p_230432_4_, int p_230432_5_, int itemHeight, int p_230432_7_, int p_230432_8_, boolean selected, float partialTicks) + { + float labelX = ButtonBindingList.this.minecraft.currentScreen.width / 2F - this.labelWidth / 2F; + float labelY = y + itemHeight - 9 - 1; + ButtonBindingList.this.minecraft.fontRenderer.drawString(this.label.getFormattedText(), labelX, labelY, 0xFFFFFFFF); + } + } + + protected class BindingEntry extends Entry + { + private ButtonBinding binding; + private TextComponent label; + private ButtonBindingButton bindingButton; + private ImageButton deleteButton; + + protected BindingEntry(ButtonBinding binding) + { + this.binding = binding; + this.label = new TranslationTextComponent(binding.getDescription()); + this.bindingButton = new ButtonBindingButton(0, 0, binding, button -> { + ButtonBindingList.this.screen.setSelectedBinding(this.binding); + }); + this.deleteButton = new ImageButton(0, 0, 20, ControllerLayoutScreen.TEXTURE, 108, 0, 16, 16, button -> { + binding.reset(); + BindingRegistry registry = BindingRegistry.getInstance(); + registry.resetBindingHash(); + registry.save(); + }); + } + + @Override + public List children() + { + return ImmutableList.of(this.bindingButton, this.deleteButton); + } + + @Override + @SuppressWarnings("ConstantConditions") + public void render(int x, int y, int left, int width, int p_230432_6_, int mouseX, int mouseY, boolean selected, float partialTicks) + { + int color = this.binding.isConflictingContext() ? TextFormatting.RED.getColor() : TextFormatting.GRAY.getColor(); + ButtonBindingList.this.minecraft.fontRenderer.drawString(this.label.getFormattedText(), left - 15, y + 6, color); + this.bindingButton.x = left + width - 45; + this.bindingButton.y = y; + this.bindingButton.render(mouseX,mouseY, partialTicks); + this.deleteButton.x = left + width - 20; + this.deleteButton.y = y; + this.deleteButton.active = !this.binding.isDefault(); + this.deleteButton.render(mouseX, mouseY, partialTicks); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) + { + if(button == GLFW.GLFW_MOUSE_BUTTON_RIGHT && this.bindingButton.isHovered()) + { + this.binding.setButton(-1); + this.bindingButton.playDownSound(Minecraft.getInstance().getSoundHandler()); + return true; + } + return super.mouseClicked(mouseX, mouseY, button); + } + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/ButtonBindingScreen.java b/src/main/java/com/mrcrayfish/controllable/client/gui/ButtonBindingScreen.java new file mode 100644 index 00000000..66eebb7c --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/ButtonBindingScreen.java @@ -0,0 +1,117 @@ +package com.mrcrayfish.controllable.client.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mrcrayfish.controllable.client.BindingRegistry; +import com.mrcrayfish.controllable.client.ButtonBinding; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.text.TranslationTextComponent; +import org.lwjgl.glfw.GLFW; + +/** + * Author: MrCrayfish + */ +public class ButtonBindingScreen extends Screen +{ + private Screen parentScreen; + private Button buttonReset; + private ButtonBindingList bindingList; + private ButtonBinding selectedBinding = null; + + protected ButtonBindingScreen(Screen parentScreen) + { + super(new TranslationTextComponent("controllable.gui.title.button_binding")); + this.parentScreen = parentScreen; + } + + void setSelectedBinding(ButtonBinding selectedBinding) + { + this.selectedBinding = selectedBinding; + } + + boolean isWaitingForButtonInput() + { + return this.selectedBinding != null; + } + + @Override + protected void init() + { + this.bindingList = new ButtonBindingList(this, this.minecraft, this.width + 10, this.height, 32, this.height - 44, 20); + this.children.add(this.bindingList); + + this.buttonReset = this.addButton(new Button(this.width / 2 - 155, this.height - 29, 150, 20, I18n.format("controllable.gui.resetBinds"), (button) -> { + BindingRegistry registry = BindingRegistry.getInstance(); + registry.getBindings().forEach(ButtonBinding::reset); + registry.resetBindingHash(); + registry.save(); + })); + this.buttonReset.active = BindingRegistry.getInstance().getBindings().stream().noneMatch(ButtonBinding::isDefault); + + this.addButton(new Button(this.width / 2 - 155 + 160, this.height - 29, 150, 20, I18n.format("gui.done"), (button) -> { + this.minecraft.displayGuiScreen(this.parentScreen); + BindingRegistry registry = BindingRegistry.getInstance(); + registry.resetBindingHash(); + registry.save(); + })); + } + + @Override + public void tick() + { + this.buttonReset.active = !BindingRegistry.getInstance().getBindings().stream().allMatch(ButtonBinding::isDefault); + } + + @Override + public void render(int mouseX, int mouseY, float partialTicks) + { + this.renderBackground(); + this.bindingList.render(this.selectedBinding == null ? mouseX : -1, this.selectedBinding == null ? mouseY : -1, partialTicks); + drawCenteredString(this.font, this.title.getFormattedText(), this.width / 2, 20, 0xFFFFFF); + super.render(this.selectedBinding == null ? mouseX : -1, this.selectedBinding == null ? mouseY : -1, partialTicks); + + if(this.selectedBinding != null) + { + RenderSystem.disableDepthTest(); + this.fillGradient(0, 0, this.width, this.height, -1072689136, -804253680); + drawCenteredString(this.font, new TranslationTextComponent("controllable.gui.layout.press_button").getFormattedText(), this.width / 2, this.height / 2, 0xFFFFFFFF); + RenderSystem.enableDepthTest(); + } + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) + { + if(this.selectedBinding != null) + { + return true; + } + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean keyPressed(int key, int scanCode, int mods) + { + if(key == GLFW.GLFW_KEY_ESCAPE && this.selectedBinding != null) + { + this.selectedBinding = null; + return true; + } + return super.keyPressed(key, scanCode, mods); + } + + public boolean processButton(int index) + { + if(this.selectedBinding != null) + { + this.selectedBinding.setButton(index); + this.selectedBinding = null; + BindingRegistry registry = BindingRegistry.getInstance(); + registry.resetBindingHash(); + registry.save(); + return true; + } + return false; + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerAxis.java b/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerAxis.java index f7764501..caa27621 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerAxis.java +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerAxis.java @@ -1,18 +1,21 @@ package com.mrcrayfish.controllable.client.gui; +import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.mrcrayfish.controllable.Controllable; import com.mrcrayfish.controllable.client.Buttons; import com.mrcrayfish.controllable.client.Controller; +import org.lwjgl.glfw.GLFW; +import org.lwjgl.glfw.GLFWGamepadState; /** * Author: MrCrayfish */ public class ControllerAxis extends ControllerButton { - public ControllerAxis(int button, int x, int y, int u, int v, int width, int height, int scale) + public ControllerAxis(ControllerLayoutScreen screen, int button, int x, int y, int u, int v, int width, int height, int scale) { - super(button, x, y, u, v, width, height, scale); + super(screen, button, x, y, u, v, width, height, scale); } @Override @@ -22,19 +25,28 @@ public void draw(int x, int y, int mouseX, int mouseY, boolean selected) Controller controller = Controllable.getController(); if(controller != null) { - switch(button) + GLFWGamepadState gamepad = controller.getGamepadState(); + switch(this.button) { case Buttons.LEFT_THUMB_STICK: - RenderSystem.translatef(controller.getLThumbStickXValue() * 5, -controller.getLThumbStickYValue() * 5, 0); + float leftX = gamepad.axes(this.screen.getEntry().isThumbsticksSwitched() ? GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X : GLFW.GLFW_GAMEPAD_AXIS_LEFT_X); + float leftY = gamepad.axes(this.screen.getEntry().isThumbsticksSwitched() ? GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y : GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y); + leftX *= this.screen.getEntry().isFlipLeftX() ? -1 : 1; + leftY *= this.screen.getEntry().isFlipLeftY() ? -1 : 1; + RenderSystem.translatef(leftX * 5, leftY * 5, 0); break; case Buttons.RIGHT_THUMB_STICK: - RenderSystem.translatef(controller.getRThumbStickXValue() * 5, -controller.getRThumbStickYValue() * 5, 0); + float rightX = gamepad.axes(this.screen.getEntry().isThumbsticksSwitched() ? GLFW.GLFW_GAMEPAD_AXIS_LEFT_X : GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X); + float rightY = gamepad.axes(this.screen.getEntry().isThumbsticksSwitched() ? GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y : GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y); + rightX *= this.screen.getEntry().isFlipRightX() ? -1 : 1; + rightY *= this.screen.getEntry().isFlipRightY() ? -1 : 1; + RenderSystem.translatef(rightX * 5, rightY * 5, 0); break; } - if(!Controllable.isButtonPressed(button)) + if(!this.screen.isButtonPressed(this.button)) { - RenderSystem.translated(0, -2.5, 0); + RenderSystem.translated(0, -5, 0); } } super.draw(x, y, mouseX, mouseY, selected); diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerButton.java b/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerButton.java index 9d7f4c33..5596ba17 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerButton.java +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerButton.java @@ -1,7 +1,9 @@ package com.mrcrayfish.controllable.client.gui; +import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.mrcrayfish.controllable.Controllable; +import com.mrcrayfish.controllable.client.Controller; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.AbstractGui; @@ -10,6 +12,7 @@ */ public class ControllerButton extends AbstractGui { + protected ControllerLayoutScreen screen; protected int button; private int x, y; private int u, v; @@ -17,8 +20,9 @@ public class ControllerButton extends AbstractGui private int scale; private boolean hovered; - public ControllerButton(int button, int x, int y, int u, int v, int width, int height, int scale) + public ControllerButton(ControllerLayoutScreen screen, int button, int x, int y, int u, int v, int width, int height, int scale) { + this.screen = screen; this.button = button; this.x = x; this.y = y; @@ -33,32 +37,45 @@ public void draw(int x, int y, int mouseX, int mouseY, boolean selected) { RenderSystem.enableBlend(); Minecraft.getInstance().getTextureManager().bindTexture(ControllerLayoutScreen.TEXTURE); - int buttonU = u; - int buttonV = v; + int buttonU = this.u; + int buttonV = this.v; int buttonX = x + this.x * this.scale; int buttonY = y + this.y * this.scale; int buttonWidth = this.width * this.scale; int buttonHeight = this.height * this.scale; - hovered = mouseX >= buttonX && mouseY >= buttonY && mouseX < buttonX + buttonWidth && mouseY < buttonY + buttonHeight; - if(hovered) + Controller controller = Controllable.getController(); + this.hovered = mouseX >= buttonX && mouseY >= buttonY && mouseX < buttonX + buttonWidth && mouseY < buttonY + buttonHeight; + if(this.hovered) { buttonV += this.height * 2; } - else if(Controllable.getController() != null && Controllable.isButtonPressed(button) || selected) + else if(controller != null && this.screen.isButtonPressed(this.button) || selected) { buttonV += this.height; } blit(buttonX, buttonY, this.width * this.scale, this.height * this.scale, buttonU, buttonV, this.width, this.height, 256, 256); RenderSystem.disableBlend(); + + // Draws an exclamation if the button has no button assigned to it! + if(this.isMissingMapping()) + { + Minecraft.getInstance().getTextureManager().bindTexture(ControllerLayoutScreen.TEXTURE); + blit(buttonX + (buttonWidth - 4) / 2, buttonY + (buttonHeight - 15) / 2, 4, 15, 88, 0, 4, 15, 256, 256); + } } public int getButton() { - return button; + return this.button; } public boolean isHovered() { - return hovered; + return this.hovered; + } + + public boolean isMissingMapping() + { + return !this.screen.getReassignments().values().contains(this.button) && this.screen.remap(this.button) != this.button; } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerEntry.java b/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerEntry.java index 5fd71fca..96a90edc 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerEntry.java +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerEntry.java @@ -1,5 +1,6 @@ package com.mrcrayfish.controllable.client.gui; +import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.mrcrayfish.controllable.Controllable; import com.mrcrayfish.controllable.client.Controller; @@ -7,7 +8,7 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.list.ExtendedList; import net.minecraft.util.ResourceLocation; -import uk.co.electronstudio.sdl2gdx.SDL2Controller; +import org.lwjgl.glfw.GLFW; import java.awt.*; @@ -17,45 +18,45 @@ public final class ControllerEntry extends ExtendedList.AbstractListEntry { private ControllerList controllerList; - private Controller controller; + private int jid; - public ControllerEntry(ControllerList controllerList, SDL2Controller sdl2Controller) + public ControllerEntry(ControllerList controllerList, int jid) { this.controllerList = controllerList; - this.controller = new Controller(sdl2Controller); + this.jid = jid; } - SDL2Controller getSdl2Controller() + public int getJid() { - return this.controller.getSDL2Controller(); + return this.jid; } @Override public void render(int slotIndex, int top, int left, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected, float partialTicks) { - if(!controller.getSDL2Controller().isConnected()) + String controllerName = GLFW.glfwGetGamepadName(this.jid); + if(controllerName == null) return; - - Minecraft.getInstance().fontRenderer.drawString(controller.getName(), left + 20, top + 4, Color.WHITE.getRGB()); - if(controllerList.getSelected() == this) + Minecraft.getInstance().fontRenderer.drawStringWithShadow(controllerName, left + 20, top + 4, Color.WHITE.getRGB()); + if(this.controllerList.getSelected() == this) { RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); Minecraft.getInstance().getTextureManager().bindTexture(new ResourceLocation("textures/gui/container/beacon.png")); - Screen.blit(left + 2, top + 2, 91, 224, 14, 12, 256, 256); + Screen.blit(left + 2, top + 2, 91, 224, 14, 12, 256, 256); //TODO test } } @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - if(controllerList.getSelected() != this) + if(this.controllerList.getSelected() != this) { - controllerList.setSelected(this); - Controllable.setController(this.controller.getSDL2Controller()); + this.controllerList.setSelected(this); + Controllable.setController(new Controller(this.jid)); } else { - controllerList.setSelected(null); + this.controllerList.setSelected(null); Controllable.setController(null); } return true; diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerLayoutScreen.java b/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerLayoutScreen.java index 410631fe..e95a7f9c 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerLayoutScreen.java +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerLayoutScreen.java @@ -1,23 +1,31 @@ package com.mrcrayfish.controllable.client.gui; -import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; +import com.mrcrayfish.controllable.ButtonStates; import com.mrcrayfish.controllable.Controllable; import com.mrcrayfish.controllable.Reference; import com.mrcrayfish.controllable.client.Buttons; import com.mrcrayfish.controllable.client.Controller; import com.mrcrayfish.controllable.client.Mappings; +import com.mrcrayfish.controllable.client.gui.widget.ImageButton; import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.SimpleSound; +import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.button.Button; import net.minecraft.client.resources.I18n; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundEvents; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TranslationTextComponent; import org.lwjgl.glfw.GLFW; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Author: MrCrayfish @@ -29,67 +37,176 @@ public class ControllerLayoutScreen extends Screen private List controllerButtons = new ArrayList<>(); private int configureButton = -1; + private boolean validLayout; private Screen parentScreen; + private LayoutButtonStates states = new LayoutButtonStates(); + private Mappings.Entry entry; + private Button doneButton; + private Button resetButton; + private Button thumbstickButton; protected ControllerLayoutScreen(Screen parentScreen) { super(new TranslationTextComponent("controllable.gui.title.layout")); this.parentScreen = parentScreen; + + Controller controller = Controllable.getController(); + if(controller != null) + { + Mappings.Entry entry = controller.getMapping(); + if(entry != null) + { + this.entry = entry.copy(); + } + else + { + this.entry = new Mappings.Entry(controller.getName(), controller.getName(), new HashMap<>()); + } + } } @Override protected void init() { - controllerButtons.add(new ControllerButton(Buttons.A, 29, 9, 7, 0, 3, 3, 5)); - controllerButtons.add(new ControllerButton(Buttons.B, 32, 6, 13, 0, 3, 3, 5)); - controllerButtons.add(new ControllerButton(Buttons.X, 26, 6, 16, 0, 3, 3, 5)); - controllerButtons.add(new ControllerButton(Buttons.Y, 29, 3, 10, 0, 3, 3, 5)); - controllerButtons.add(new ControllerButton(Buttons.LEFT_BUMPER, 5, -2, 25, 0, 7, 3, 5)); - controllerButtons.add(new ControllerButton(Buttons.RIGHT_BUMPER, 26, -2, 32, 0, 7, 3, 5)); - controllerButtons.add(new ControllerButton(Buttons.LEFT_TRIGGER, 5, -10, 39, 0, 7, 6, 5)); - controllerButtons.add(new ControllerButton(Buttons.RIGHT_TRIGGER, 26, -10, 39, 0, 7, 6, 5)); - controllerButtons.add(new ControllerButton(Buttons.DPAD_DOWN, 6, 9, 19, 0, 3, 3, 5)); - controllerButtons.add(new ControllerButton(Buttons.DPAD_RIGHT, 9, 6, 19, 0, 3, 3, 5)); - controllerButtons.add(new ControllerButton(Buttons.DPAD_LEFT, 3, 6, 19, 0, 3, 3, 5)); - controllerButtons.add(new ControllerButton(Buttons.DPAD_UP, 6, 3, 19, 0, 3, 3, 5)); - controllerButtons.add(new ControllerButton(Buttons.SELECT, 14, 4, 22, 0, 3, 2, 5)); - controllerButtons.add(new ControllerButton(Buttons.START, 21, 4, 22, 0, 3, 2, 5)); - controllerButtons.add(new ControllerButton(Buttons.HOME, 17, 8, 46, 0, 4, 4, 5)); - controllerButtons.add(new ControllerAxis(Buttons.LEFT_THUMB_STICK, 9, 12, 0, 0, 7, 7, 5)); - controllerButtons.add(new ControllerAxis(Buttons.RIGHT_THUMB_STICK, 22, 12, 0, 0, 7, 7, 5)); - - this.addButton(new Button(this.width / 2 - 100, this.height - 32, 200, 20, I18n.format("gui.done"), (button) -> { + this.controllerButtons.clear(); + this.controllerButtons.add(new ControllerButton(this, Buttons.A, 29, 9, 7, 0, 3, 3, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.B, 32, 6, 13, 0, 3, 3, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.X, 26, 6, 16, 0, 3, 3, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.Y, 29, 3, 10, 0, 3, 3, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.LEFT_BUMPER, 5, -2, 25, 0, 7, 3, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.RIGHT_BUMPER, 26, -2, 32, 0, 7, 3, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.LEFT_TRIGGER, -10, 0, 39, 0, 7, 6, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.RIGHT_TRIGGER, 41, 0, 39, 0, 7, 6, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.DPAD_DOWN, 6, 9, 19, 0, 3, 3, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.DPAD_RIGHT, 9, 6, 19, 0, 3, 3, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.DPAD_LEFT, 3, 6, 19, 0, 3, 3, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.DPAD_UP, 6, 3, 19, 0, 3, 3, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.SELECT, 14, 4, 22, 0, 3, 2, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.START, 21, 4, 22, 0, 3, 2, 5)); + this.controllerButtons.add(new ControllerButton(this, Buttons.HOME, 17, 8, 46, 0, 4, 4, 5)); + this.controllerButtons.add(new ControllerAxis(this, Buttons.LEFT_THUMB_STICK, 9, 12, 0, 0, 7, 7, 5)); + this.controllerButtons.add(new ControllerAxis(this, Buttons.RIGHT_THUMB_STICK, 22, 12, 0, 0, 7, 7, 5)); + + this.doneButton = this.addButton(new Button(this.width / 2 - 154, this.height - 32, 100, 20, I18n.format("controllable.gui.save"), (button) -> { + this.updateControllerMapping(); + this.minecraft.displayGuiScreen(this.parentScreen); + })); + + this.resetButton = this.addButton(new Button(this.width / 2 - 50, this.height - 32, 100, 20, I18n.format("controllable.gui.reset"), (button) -> { + this.entry.getReassignments().clear(); + this.entry.setSwitchThumbsticks(false); + this.entry.setFlipLeftX(false); + this.entry.setFlipLeftY(false); + this.entry.setFlipRightX(false); + this.entry.setFlipRightY(false); + })); + + this.addButton(new Button(this.width / 2 + 54, this.height - 32, 100, 20, I18n.format("gui.cancel"), (button) -> { this.minecraft.displayGuiScreen(this.parentScreen); })); + + int width = 38 * 5; + int x = this.width / 2 - width / 2; + int y = this.height / 2 - 50 - 35; + + this.thumbstickButton = this.addButton(new ImageButton(x + width / 2 - 10, y + 90, 20, TEXTURE, 92, 0, 16, 16, button -> { + this.minecraft.displayGuiScreen(new ThumbstickSettingsScreen(this)); + })); + } + + @Override + public void tick() + { + boolean changed = !this.entry.getReassignments().isEmpty(); + changed |= this.entry.isThumbsticksSwitched(); + changed |= this.entry.isFlipLeftX(); + changed |= this.entry.isFlipLeftY(); + changed |= this.entry.isFlipRightX(); + changed |= this.entry.isFlipRightY(); + this.resetButton.active = changed; + this.validLayout = this.entry.getReassignments().values().stream().noneMatch(b -> b == -1); + this.doneButton.setMessage(new TranslationTextComponent("controllable.gui.save").applyTextStyle(this.validLayout ? TextFormatting.WHITE : TextFormatting.RED).getFormattedText()); } @Override public void render(int mouseX, int mouseY, float partialTicks) { - this.renderBackground(); + this.renderDirtBackground(0); RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); RenderSystem.enableBlend(); Minecraft.getInstance().getTextureManager().bindTexture(TEXTURE); int width = 38 * 5; - int height = 29 * 5; + int height = 24 * 5; int x = this.width / 2 - width / 2; - int y = this.height / 2 - 50; - blit(x, y, width, height, 50, 0, 38, 29, 256, 256); - RenderSystem.disableBlend(); - controllerButtons.forEach(controllerButton -> controllerButton.draw(x, y, mouseX, mouseY, configureButton == controllerButton.button)); - this.drawCenteredString(this.font, this.title.getFormattedText(), this.width / 2, 20, 0xFFFFFF); + int y = this.height / 2 - 50 - 35; + blit(x, y, width, height, 50, 0, 38, 24, 256, 256); + this.controllerButtons.forEach(controllerButton -> controllerButton.draw(x, y, mouseX, mouseY, this.configureButton == controllerButton.button)); + drawCenteredString(this.font, this.title.getFormattedText(), this.width / 2, 20, 0xFFFFFF); + this.drawMultiLineCenteredString(this.font, new TranslationTextComponent("controllable.gui.layout.info").applyTextStyle(TextFormatting.GRAY), x + width / 2, y + 135, width + 190, 0xFFFFFFFF); super.render(mouseX, mouseY, partialTicks); + + if(this.configureButton != -1) + { + RenderSystem.disableDepthTest(); + this.fillGradient(0, 0, this.width, this.height, -1072689136, -804253680); + this.drawCenteredString(this.font, I18n.format("controllable.gui.layout.press_button"), this.width / 2, this.height / 2, 0xFFFFFFFF); + RenderSystem.enableDepthTest(); + return; + } + + ControllerButton button = this.controllerButtons.stream().filter(ControllerButton::isHovered).findFirst().orElse(null); + if(button != null) + { + List components = new ArrayList<>(); + components.add(new TranslationTextComponent("controllable.gui.layout.button", new TranslationTextComponent(Buttons.NAMES[button.getButton()]).applyTextStyle(TextFormatting.BLUE).getFormattedText()).getFormattedText()); + if(button.isMissingMapping()) + { + components.add(new TranslationTextComponent("controllable.gui.layout.missing_mapping").applyTextStyle(TextFormatting.RED).getFormattedText()); + } + else + { + int remappedButton = button.getButton(); + if(!button.isMissingMapping()) + { + Map reassignments = this.entry.getReassignments(); + for(Integer key : reassignments.keySet()) + { + if(reassignments.get(key) == remappedButton) + { + remappedButton = key; + break; + } + } + } + components.add(new TranslationTextComponent("controllable.gui.layout.mapped_to", new StringTextComponent(String.valueOf(remappedButton)).applyTextStyle(TextFormatting.BLUE)).getFormattedText()); + } + components.add(new TranslationTextComponent("controllable.gui.layout.remap").applyTextStyle(TextFormatting.GRAY).getFormattedText()); + this.renderTooltip(components, mouseX, mouseY); + } + + if(!this.validLayout && this.doneButton.isHovered()) + { + List components = new ArrayList<>(); + components.add(new TranslationTextComponent("controllable.gui.layout.warning").applyTextStyle(TextFormatting.RED).getFormattedText()); + components.addAll(this.font.listFormattedStringToWidth(new TranslationTextComponent("controllable.gui.layout.invalid_layout").applyTextStyle(TextFormatting.GRAY).getFormattedText(), 180)); + this.renderTooltip(components, mouseX, mouseY - 50); + } + + if(this.thumbstickButton.isHovered()) + { + this.renderTooltip(new TranslationTextComponent("controllable.gui.layout.thumbsticks").getFormattedText(), mouseX, mouseY); + } } @Override public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) { - if(mouseButton == 0) + if(mouseButton == 0 && this.configureButton == -1) { - ControllerButton button = controllerButtons.stream().filter(ControllerButton::isHovered).findFirst().orElse(null); + ControllerButton button = this.controllerButtons.stream().filter(ControllerButton::isHovered).findFirst().orElse(null); if(button != null) { - configureButton = button.getButton(); + this.configureButton = button.getButton(); return true; } } @@ -99,9 +216,9 @@ public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) @Override public boolean keyPressed(int key, int scanCode, int mods) { - if(key == GLFW.GLFW_KEY_ESCAPE && configureButton != -1) + if(key == GLFW.GLFW_KEY_ESCAPE && this.configureButton != -1) { - configureButton = -1; + this.configureButton = -1; return true; } return super.keyPressed(key, scanCode, mods); @@ -109,36 +226,129 @@ public boolean keyPressed(int key, int scanCode, int mods) public boolean onButtonInput(int button) { - if(configureButton != -1) + if(this.configureButton != -1) { - Controller controller = Controllable.getController(); - if(controller != null) + Map reassignments = this.entry.getReassignments(); + if(button != this.configureButton) { - Mappings.Entry entry = controller.getMapping(); - if(entry == null) - { - entry = new Mappings.Entry(controller.getName(), controller.getName(), new HashMap<>()); - controller.setMapping(entry); - } - if(button != configureButton) + // Sets the target + reassignments.putIfAbsent(this.configureButton, -1); + + // Reset any assignments that targets the configuration button and set to -1 + for(Integer key : reassignments.keySet()) { - entry.getReassignments().putIfAbsent(configureButton, -1); - entry.getReassignments().put(button, configureButton); + if(reassignments.get(key) == this.configureButton) + { + reassignments.put(key, -1); + } } - else + + // Finally set the new mapping + reassignments.put(button, this.configureButton); + } + else + { + // Remove reassignment because button is back to it's default mapping + reassignments.remove(button); + + // Reset any assignments that targets the button and set to -1 + for(Integer key : reassignments.keySet()) { - Integer originalButton = entry.getReassignments().inverse().get(configureButton); - if(originalButton != null) + if(reassignments.get(key) == button) { - entry.getReassignments().remove(originalButton); + reassignments.put(key, -1); } - entry.getReassignments().remove(button); } - configureButton = -1; - entry.save(); - return true; } + this.configureButton = -1; + return true; } return false; } + + private void updateControllerMapping() + { + Controller controller = Controllable.getController(); + if(controller != null) + { + controller.setMapping(this.entry); + this.entry.save(); + } + } + + public void processButton(int index, ButtonStates newStates) + { + boolean state = newStates.getState(index); + + if(state && this.onButtonInput(index)) + { + return; + } + + Controller controller = Controllable.getController(); + if(controller == null) + { + return; + } + + index = this.remap(index); + + //No binding so don't perform any action + if(index == -1) + { + return; + } + + if(state) + { + if(!this.states.getState(index)) + { + this.states.setState(index, true); + Minecraft.getInstance().getSoundHandler().play(SimpleSound.master(SoundEvents.BLOCK_WOODEN_BUTTON_CLICK_ON, 1.0F)); + } + } + else if(this.states.getState(index)) + { + this.states.setState(index, false); + Minecraft.getInstance().getSoundHandler().play(SimpleSound.master(SoundEvents.BLOCK_WOODEN_BUTTON_CLICK_ON, 0.9F)); + } + } + + public int remap(int button) + { + return this.entry.remap(button); + } + + public boolean isButtonPressed(int button) + { + return this.states.getState(button); + } + + public Map getReassignments() + { + return this.entry.getReassignments(); + } + + public Mappings.Entry getEntry() + { + return this.entry; + } + + private void drawMultiLineCenteredString(FontRenderer font, ITextComponent component, int x, int y, int width, int color) + { + for(String s : font.listFormattedStringToWidth(component.getFormattedText(), width)) + { + font.drawString(s, (float) (x - font.getStringWidth(s) / 2.0), y, color); + y += font.FONT_HEIGHT; + } + } + + public static class LayoutButtonStates extends ButtonStates + { + @Override + public void setState(int index, boolean state) + { + super.setState(index, state); + } + } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerList.java b/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerList.java index 73308b5d..7ba9235e 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerList.java +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerList.java @@ -1,16 +1,15 @@ package com.mrcrayfish.controllable.client.gui; -import com.badlogic.gdx.utils.Array; import com.mrcrayfish.controllable.Controllable; import com.mrcrayfish.controllable.client.Controller; +import com.mrcrayfish.controllable.client.ControllerManager; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.widget.list.ExtendedList; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import uk.co.electronstudio.sdl2gdx.SDL2Controller; -import uk.co.electronstudio.sdl2gdx.SDL2ControllerManager; import java.util.List; +import java.util.Map; /** * Author: MrCrayfish @@ -18,9 +17,9 @@ @OnlyIn(Dist.CLIENT) public class ControllerList extends ExtendedList { - private SDL2ControllerManager manager; + private ControllerManager manager; - public ControllerList(SDL2ControllerManager manager, Minecraft mcIn, int widthIn, int heightIn, int topIn, int bottomIn, int slotHeightIn) + public ControllerList(ControllerManager manager, Minecraft mcIn, int widthIn, int heightIn, int topIn, int bottomIn, int slotHeightIn) { super(mcIn, widthIn, heightIn, topIn, bottomIn, slotHeightIn); this.manager = manager; @@ -30,15 +29,14 @@ public ControllerList(SDL2ControllerManager manager, Minecraft mcIn, int widthIn public void reload() { this.clearEntries(); - Array controllers = manager.getControllers(); - for(int i = 0; i < controllers.size; i++) - { - this.addEntry(new ControllerEntry(this, (SDL2Controller) controllers.get(i))); - } + Map controllers = this.manager.getControllers(); + controllers.forEach((jid, name) -> { + this.addEntry(new ControllerEntry(this, jid)); + }); this.updateSelected(); } - private void updateSelected() + public void updateSelected() { Controller controller = Controllable.getController(); if(controller == null) @@ -50,7 +48,7 @@ private void updateSelected() List entries = this.children(); for(ControllerEntry entry : entries) { - if(entry.getSdl2Controller() == controller.getSDL2Controller()) + if(entry.getJid() == controller.getJid()) { this.setSelected(entry); break; diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerSelectionScreen.java b/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerSelectionScreen.java index 3a60001b..7af12fc4 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerSelectionScreen.java +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerSelectionScreen.java @@ -1,10 +1,11 @@ package com.mrcrayfish.controllable.client.gui; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mrcrayfish.controllable.client.ControllerManager; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.button.Button; import net.minecraft.client.resources.I18n; import net.minecraft.util.text.TranslationTextComponent; -import uk.co.electronstudio.sdl2gdx.SDL2ControllerManager; /** * Author: MrCrayfish @@ -12,19 +13,20 @@ public class ControllerSelectionScreen extends Screen { private int controllerCount; - private SDL2ControllerManager manager; + private ControllerManager manager; private ControllerList listControllers; private Screen previousScreen; private Button btnSettings; private Button btnRemap; + private Button btnLayout; private Button btnBack; - public ControllerSelectionScreen(SDL2ControllerManager manager, Screen previousScreen) + public ControllerSelectionScreen(ControllerManager manager, Screen previousScreen) { - super(new TranslationTextComponent("controllable.selectController.title")); + super(new TranslationTextComponent("controllable.gui.title.select_controller")); this.manager = manager; this.previousScreen = previousScreen; - this.controllerCount = manager.getControllers().size; + this.controllerCount = manager.getControllerCount(); } @Override @@ -32,22 +34,24 @@ protected void init() { this.listControllers = new ControllerList(this.manager, this.minecraft, this.width, this.height, 32, this.height - 44, 20); this.children.add(this.listControllers); - this.btnSettings = this.addButton(new Button(this.width / 2 - 154, this.height - 32, 100, 20, I18n.format("controllable.gui.settings"), this::handleSettings)); - this.btnRemap = this.addButton(new Button(this.width / 2 - 50, this.height - 32, 100, 20, I18n.format("controllable.gui.remap"), this::handleConfigure)); - this.btnBack = this.addButton(new Button(this.width / 2 + 54, this.height - 32, 100, 20, I18n.format("controllable.gui.back"), this::handleCancel)); - //this.btnRemap.active = this.listControllers.getSelected() != null; - this.btnRemap.active = false; + this.btnSettings = this.addButton(new Button(this.width / 2 - 154, this.height - 32, 72, 20, I18n.format("controllable.gui.settings"), this::handleSettings)); + this.btnRemap = this.addButton(new Button(this.width / 2 - 76, this.height - 32, 72, 20, I18n.format("controllable.gui.binding"), this::handleConfigure)); + this.btnLayout = this.addButton(new Button(this.width / 2 + 4, this.height - 32, 72, 20, I18n.format("controllable.gui.layout"), this::handleLayout)); + this.btnBack = this.addButton(new Button(this.width / 2 + 82, this.height - 32, 72, 20, I18n.format("controllable.gui.back"), this::handleCancel)); + this.btnRemap.active = this.listControllers.getSelected() != null; } @Override public void tick() { - if(this.controllerCount != this.manager.getControllers().size) + if(this.controllerCount != this.manager.getControllerCount()) { - this.controllerCount = this.manager.getControllers().size; + this.controllerCount = this.manager.getControllerCount(); this.listControllers.reload(); - //this.btnRemap.active = this.listControllers.getSelected() != null; } + this.listControllers.updateSelected(); + this.btnRemap.active = this.listControllers.getSelected() != null; + this.btnLayout.active = this.listControllers.getSelected() != null; } @Override @@ -55,7 +59,7 @@ public void render(int mouseX, int mouseY, float partialTicks) { this.renderBackground(); this.listControllers.render(mouseX, mouseY, partialTicks); - this.drawCenteredString(this.font, I18n.format("controllable.gui.title.select_controller"), this.width / 2, 20, 16777215); + this.drawCenteredString(this.font, this.title.getFormattedText(), this.width / 2, 20, 0xFFFFFF); super.render(mouseX, mouseY, partialTicks); } @@ -65,6 +69,11 @@ private void handleSettings(Button button) } private void handleConfigure(Button button) + { + this.minecraft.displayGuiScreen(new ButtonBindingScreen(this)); + } + + private void handleLayout(Button button) { this.minecraft.displayGuiScreen(new ControllerLayoutScreen(this)); } diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/SettingsScreen.java b/src/main/java/com/mrcrayfish/controllable/client/gui/SettingsScreen.java index e6a82d6c..9add5a01 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/gui/SettingsScreen.java +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/SettingsScreen.java @@ -1,6 +1,7 @@ package com.mrcrayfish.controllable.client.gui; -import com.mrcrayfish.controllable.Controllable; +import com.mrcrayfish.controllable.Config; +import com.mrcrayfish.controllable.client.IToolTip; import com.mrcrayfish.controllable.client.settings.ControllerOptions; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.button.Button; @@ -8,13 +9,17 @@ import net.minecraft.client.settings.AbstractOption; import net.minecraft.util.text.TranslationTextComponent; +import javax.annotation.Nullable; + /** * Author: MrCrayfish */ public class SettingsScreen extends Screen { - private static final AbstractOption[] OPTIONS = new AbstractOption[]{ControllerOptions.FORCE_FEEDBACK, ControllerOptions.AUTO_SELECT, ControllerOptions.RENDER_MINI_PLAYER, ControllerOptions.VIRTUAL_MOUSE, ControllerOptions.CONSOLE_HOTBAR, ControllerOptions.CONTROLLER_TYPE, ControllerOptions.CURSOR_TYPE, ControllerOptions.INVERT_LOOK, ControllerOptions.DEAD_ZONE, ControllerOptions.ROTATION_SPEED, ControllerOptions.MOUSE_SPEED}; + private static final AbstractOption[] OPTIONS = new AbstractOption[]{ControllerOptions.AUTO_SELECT, ControllerOptions.RENDER_MINI_PLAYER, ControllerOptions.VIRTUAL_MOUSE, ControllerOptions.CONSOLE_HOTBAR, ControllerOptions.CONTROLLER_ICONS, ControllerOptions.CURSOR_TYPE, ControllerOptions.INVERT_LOOK, ControllerOptions.DEAD_ZONE, ControllerOptions.ROTATION_SPEED, ControllerOptions.MOUSE_SPEED, ControllerOptions.SHOW_ACTIONS, ControllerOptions.QUICK_CRAFT}; private final Screen parentScreen; + private IToolTip hoveredTooltip; + private int hoveredCounter; protected SettingsScreen(Screen parentScreen) { @@ -33,15 +38,31 @@ protected void init() this.addButton(option.createWidget(this.minecraft.gameSettings, x, y, 150)); } - this.addButton(new Button(this.width / 2 - 100, this.height / 6 + 24 * (OPTIONS.length + 1) / 2, 200, 20, I18n.format("gui.done"), (button) -> { + this.addButton(new Button(this.width / 2 - 100, this.height / 6 + 24 * (OPTIONS.length + 1) / 2, 200, 20, I18n.format("gui.back"), (button) -> { this.minecraft.displayGuiScreen(this.parentScreen); })); } @Override - public void removed() + public void onClose() { - Controllable.getOptions().saveOptions(); + Config.save(); + } + + @Override + public void tick() + { + if(this.hoveredTooltip != null) + { + if(this.hoveredCounter < 20) + { + this.hoveredCounter++; + } + } + else + { + this.hoveredCounter = 0; + } } @Override @@ -50,5 +71,29 @@ public void render(int mouseX, int mouseY, float partialTicks) this.renderBackground(); this.drawCenteredString(this.font, this.title.getFormattedText(), this.width / 2, 20, 0xFFFFFF); super.render(mouseX, mouseY, partialTicks); + + this.hoveredTooltip = this.getHoveredToolTip(mouseX, mouseY); + if(this.hoveredTooltip != null && this.hoveredCounter >= 20) + { + this.renderTooltip(this.hoveredTooltip.getToolTip(), mouseX, mouseY); + } + } + + @Nullable + private IToolTip getHoveredToolTip(int mouseX, int mouseY) + { + for(int i = 0; i < OPTIONS.length; i++) + { + AbstractOption option = OPTIONS[i]; + if(!(option instanceof IToolTip)) + continue; + int x = this.width / 2 - 155 + i % 2 * 160; + int y = this.height / 6 + 24 * (i >> 1); + if(mouseX >= x && mouseY >= y && mouseX < x + 150 && mouseY < y + 20) + { + return (IToolTip) option; + } + } + return null; } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/ThumbstickSettingsScreen.java b/src/main/java/com/mrcrayfish/controllable/client/gui/ThumbstickSettingsScreen.java new file mode 100644 index 00000000..eb06220e --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/ThumbstickSettingsScreen.java @@ -0,0 +1,70 @@ +package com.mrcrayfish.controllable.client.gui; + +import com.mrcrayfish.controllable.client.settings.ControllableBooleanOption; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.client.gui.widget.list.OptionsRowList; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.text.TranslationTextComponent; + +/** + * Author: MrCrayfish + */ +public class ThumbstickSettingsScreen extends Screen +{ + private OptionsRowList optionsRowList; + private final ControllerLayoutScreen layoutScreen; + + protected ThumbstickSettingsScreen(ControllerLayoutScreen layoutScreen) + { + super(new TranslationTextComponent("controllable.gui.title.thumbstick_settings")); + this.layoutScreen = layoutScreen; + } + + @Override + protected void init() + { + this.optionsRowList = new OptionsRowList(this.minecraft, this.width, this.height, 32, this.height - 32, 25); + + this.optionsRowList.addOption(new ControllableBooleanOption("controllable.options.switchThumbsticks", gameSettings -> { + return this.layoutScreen.getEntry().isThumbsticksSwitched(); + }, (gameSettings, value) -> { + this.layoutScreen.getEntry().setSwitchThumbsticks(value); + })); + + this.optionsRowList.addOption(new ControllableBooleanOption("controllable.options.flipLeftThumbstickX", gameSettings -> { + return this.layoutScreen.getEntry().isFlipLeftX(); + }, (gameSettings, value) -> { + this.layoutScreen.getEntry().setFlipLeftX(value); + }), new ControllableBooleanOption("controllable.options.flipRightThumbstickX", gameSettings -> { + return this.layoutScreen.getEntry().isFlipRightX(); + }, (gameSettings, value) -> { + this.layoutScreen.getEntry().setFlipRightX(value); + })); + + this.optionsRowList.addOption(new ControllableBooleanOption("controllable.options.flipLeftThumbstickY", gameSettings -> { + return this.layoutScreen.getEntry().isFlipLeftY(); + }, (gameSettings, value) -> { + this.layoutScreen.getEntry().setFlipLeftY(value); + }), new ControllableBooleanOption("controllable.options.flipRightThumbstickY", gameSettings -> { + return this.layoutScreen.getEntry().isFlipRightY(); + }, (gameSettings, value) -> { + this.layoutScreen.getEntry().setFlipRightY(value); + })); + + this.children.add(this.optionsRowList); + + this.addButton(new Button(this.width / 2 - 100, this.height - 27, 200, 20, I18n.format("gui.back"), (button) -> { + this.minecraft.displayGuiScreen(this.layoutScreen); + })); + } + + @Override + public void render(int mouseX, int mouseY, float partialTicks) + { + this.renderBackground(); + this.optionsRowList.render(mouseX, mouseY, partialTicks); + this.drawCenteredString(this.font, this.title.getFormattedText(), this.width / 2, 20, 0xFFFFFF); + super.render(mouseX, mouseY, partialTicks); + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/BasicNavigationPoint.java b/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/BasicNavigationPoint.java new file mode 100644 index 00000000..3252f4ec --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/BasicNavigationPoint.java @@ -0,0 +1,12 @@ +package com.mrcrayfish.controllable.client.gui.navigation; + +/** + * Author: MrCrayfish + */ +public class BasicNavigationPoint extends NavigationPoint +{ + public BasicNavigationPoint(double x, double y) + { + super(x, y, Type.BASIC); + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/NavigationPoint.java b/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/NavigationPoint.java new file mode 100644 index 00000000..dfb95f16 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/NavigationPoint.java @@ -0,0 +1,44 @@ +package com.mrcrayfish.controllable.client.gui.navigation; + +/** + * Author: MrCrayfish + */ +public abstract class NavigationPoint +{ + private final double x, y; + private final Type type; + + public NavigationPoint(double x, double y, Type type) + { + this.x = x; + this.y = y; + this.type = type; + } + + public double distanceTo(double x, double y) + { + return Math.sqrt(Math.pow(this.x - x, 2) + Math.pow(this.y - y, 2)); + } + + public double getX() + { + return this.x; + } + + public double getY() + { + return this.y; + } + + public Type getType() + { + return this.type; + } + + protected enum Type + { + BASIC, + WIDGET, + SLOT; + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/SlotNavigationPoint.java b/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/SlotNavigationPoint.java new file mode 100644 index 00000000..4e24b8c0 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/SlotNavigationPoint.java @@ -0,0 +1,22 @@ +package com.mrcrayfish.controllable.client.gui.navigation; + +import net.minecraft.inventory.container.Slot; + +/** + * Author: MrCrayfish + */ +public class SlotNavigationPoint extends NavigationPoint +{ + private Slot slot; + + public SlotNavigationPoint(double x, double y, Slot slot) + { + super(x, y, Type.SLOT); + this.slot = slot; + } + + public Slot getSlot() + { + return this.slot; + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/WidgetNavigationPoint.java b/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/WidgetNavigationPoint.java new file mode 100644 index 00000000..8c50684d --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/WidgetNavigationPoint.java @@ -0,0 +1,22 @@ +package com.mrcrayfish.controllable.client.gui.navigation; + +import net.minecraft.client.gui.widget.Widget; + +/** + * Author: MrCrayfish + */ +public class WidgetNavigationPoint extends NavigationPoint +{ + private Widget widget; + + public WidgetNavigationPoint(double x, double y, Widget widget) + { + super(x, y, Type.WIDGET); + this.widget = widget; + } + + public Widget getWidget() + { + return this.widget; + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ButtonBindingButton.java b/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ButtonBindingButton.java new file mode 100644 index 00000000..f13a0f02 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ButtonBindingButton.java @@ -0,0 +1,46 @@ +package com.mrcrayfish.controllable.client.gui.widget; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mrcrayfish.controllable.Config; +import com.mrcrayfish.controllable.Controllable; +import com.mrcrayfish.controllable.client.ButtonBinding; +import com.mrcrayfish.controllable.client.Controller; +import com.mrcrayfish.controllable.client.RenderEvents; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.util.text.StringTextComponent; + +/** + * Author: MrCrayfish + */ +public class ButtonBindingButton extends Button +{ + private ButtonBinding binding; + + public ButtonBindingButton(int x, int y, ButtonBinding binding, IPressable onPress) + { + super(x, y, 20, 20, "", onPress); + this.binding = binding; + } + + public ButtonBinding getBinding() + { + return this.binding; + } + + @Override + public void renderButton(int mouseX, int mouseY, float partialTicks) + { + super.renderButton( mouseX, mouseY, partialTicks); + + Controller controller = Controllable.getController(); + if(controller == null) + return; + + int texU = this.binding.getButton() * 13; + int texV = Config.CLIENT.options.controllerIcons.get().ordinal() * 13; + int size = 13; + Minecraft.getInstance().getTextureManager().bindTexture(RenderEvents.CONTROLLER_BUTTONS); + this.blit(this.x + (this.width - size) / 2 + 1, this.y + 3, texU, texV, size, size); + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ControllableOptionSlider.java b/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ControllableOptionSlider.java index c767c9a7..97b7491d 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ControllableOptionSlider.java +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ControllableOptionSlider.java @@ -1,6 +1,5 @@ package com.mrcrayfish.controllable.client.gui.widget; -import com.mrcrayfish.controllable.Controllable; import net.minecraft.client.GameSettings; import net.minecraft.client.gui.widget.OptionSlider; import net.minecraft.client.settings.SliderPercentageOption; @@ -22,6 +21,5 @@ public ControllableOptionSlider(GameSettings settings, int x, int y, int width, protected void applyValue() { this.option.set(this.options, this.option.denormalizeValue(this.value)); - Controllable.getOptions().saveOptions(); } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ControllerButton.java b/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ControllerButton.java index 2f66c7ef..9c7a1469 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ControllerButton.java +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ControllerButton.java @@ -1,10 +1,11 @@ package com.mrcrayfish.controllable.client.gui.widget; -import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.matrix.MatrixStack; import com.mrcrayfish.controllable.Reference; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.widget.button.Button; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.StringTextComponent; /** * Author: MrCrayfish @@ -21,17 +22,14 @@ public ControllerButton(int x, int y, IPressable pressable) @Override public void renderButton(int mouseX, int mouseY, float partialTicks) { - if (this.visible) + super.renderButton(mouseX, mouseY, partialTicks); + Minecraft.getInstance().getTextureManager().bindTexture(TEXTURE); + boolean mouseOver = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height; + int textureV = 43; + if(mouseOver) { - RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); - Minecraft.getInstance().getTextureManager().bindTexture(TEXTURE); - boolean mouseOver = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height; - int textureV = 43; - if (mouseOver) - { - textureV += this.height; - } - this.blit(this.x, this.y, 0, textureV, this.width, this.height); + textureV += this.height; } + this.blit(this.x, this.y, 0, textureV, this.width, this.height); } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ImageButton.java b/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ImageButton.java new file mode 100644 index 00000000..c85fca0d --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ImageButton.java @@ -0,0 +1,38 @@ +package com.mrcrayfish.controllable.client.gui.widget; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.StringTextComponent; + +/** + * Author: MrCrayfish + */ +public class ImageButton extends Button +{ + private ResourceLocation texture; + private int imageU, imageV; + private int imageWidth, imageHeight; + + public ImageButton(int x, int y, int width, ResourceLocation texture, int imageU, int imageV, int imageWidth, int imageHeight, IPressable onPress) + { + super(x, y, width, 20, "", onPress); + this.texture = texture; + this.imageU = imageU; + this.imageV = imageV; + this.imageWidth = imageWidth; + this.imageHeight = imageHeight; + } + + @Override + public void renderButton(int mouseX, int mouseY, float partialTicks) + { + super.renderButton(mouseX, mouseY, partialTicks); + Minecraft.getInstance().getTextureManager().bindTexture(this.texture); + if(!this.active) RenderSystem.color4f(0.5F, 0.5F, 0.5F, 1.0F); + this.blit(this.x + (this.width - this.imageWidth) / 2, this.y + 2, this.imageU, this.imageV, this.imageWidth, this.imageHeight); + RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/client/settings/ControllableBooleanOption.java b/src/main/java/com/mrcrayfish/controllable/client/settings/ControllableBooleanOption.java index 3491de39..0964b91c 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/settings/ControllableBooleanOption.java +++ b/src/main/java/com/mrcrayfish/controllable/client/settings/ControllableBooleanOption.java @@ -1,26 +1,37 @@ package com.mrcrayfish.controllable.client.settings; -import com.mrcrayfish.controllable.Controllable; +import com.mrcrayfish.controllable.client.IToolTip; import net.minecraft.client.GameSettings; +import net.minecraft.client.Minecraft; import net.minecraft.client.settings.BooleanOption; +import net.minecraft.util.text.TranslationTextComponent; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.Predicate; /** * Author: MrCrayfish */ -public class ControllableBooleanOption extends BooleanOption +public class ControllableBooleanOption extends BooleanOption implements IToolTip { + private TranslationTextComponent toolTip; + public ControllableBooleanOption(String title, Predicate getter, BiConsumer setter) { super(title, getter, setter); + this.toolTip = new TranslationTextComponent(title + ".desc"); } @Override public void nextValue(GameSettings settings) { this.set(settings, String.valueOf(!this.get(settings))); - Controllable.getOptions().saveOptions(); + } + + @Override + public List getToolTip() + { + return Minecraft.getInstance().fontRenderer.listFormattedStringToWidth(this.toolTip.getFormattedText(), 200); } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/settings/ControllableEnumOption.java b/src/main/java/com/mrcrayfish/controllable/client/settings/ControllableEnumOption.java index dd7dc6a0..a7c7e3a3 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/settings/ControllableEnumOption.java +++ b/src/main/java/com/mrcrayfish/controllable/client/settings/ControllableEnumOption.java @@ -1,12 +1,15 @@ package com.mrcrayfish.controllable.client.settings; -import com.mrcrayfish.controllable.Controllable; +import com.mrcrayfish.controllable.client.IToolTip; import net.minecraft.client.GameSettings; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.widget.Widget; import net.minecraft.client.gui.widget.button.OptionButton; import net.minecraft.client.settings.AbstractOption; import net.minecraft.util.IStringSerializable; +import net.minecraft.util.text.TranslationTextComponent; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; @@ -14,13 +17,14 @@ /** * Author: MrCrayfish */ -public class ControllableEnumOption & IStringSerializable> extends AbstractOption +public class ControllableEnumOption & IStringSerializable> extends AbstractOption implements IToolTip { private Class enumClass; private int ordinal = 0; private Function getter; private BiConsumer setter; private BiFunction, String> displayNameGetter; + private TranslationTextComponent toolTip; public ControllableEnumOption(String title, Class enumClass, Function getter, BiConsumer setter, BiFunction, String> displayNameGetter) { @@ -29,12 +33,12 @@ public ControllableEnumOption(String title, Class enumClass, Function= e.length) ordinal = 0; return e[ordinal]; } + + @Override + public List getToolTip() + { + return Minecraft.getInstance().fontRenderer.listFormattedStringToWidth(this.toolTip.getFormattedText(), 200); + } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/settings/ControllableSliderPercentageOption.java b/src/main/java/com/mrcrayfish/controllable/client/settings/ControllableSliderPercentageOption.java index 881ae71d..e23f9ce3 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/settings/ControllableSliderPercentageOption.java +++ b/src/main/java/com/mrcrayfish/controllable/client/settings/ControllableSliderPercentageOption.java @@ -1,10 +1,15 @@ package com.mrcrayfish.controllable.client.settings; +import com.mrcrayfish.controllable.client.IToolTip; import com.mrcrayfish.controllable.client.gui.widget.ControllableOptionSlider; import net.minecraft.client.GameSettings; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.widget.Widget; import net.minecraft.client.settings.SliderPercentageOption; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; @@ -12,11 +17,14 @@ /** * Author: MrCrayfish */ -public class ControllableSliderPercentageOption extends SliderPercentageOption +public class ControllableSliderPercentageOption extends SliderPercentageOption implements IToolTip { + private TranslationTextComponent toolTip; + public ControllableSliderPercentageOption(String title, double minValue, double maxValue, float stepSize, Function getter, BiConsumer setter, BiFunction displayNameGetter) { super(title, minValue, maxValue, stepSize, getter, setter, displayNameGetter); + this.toolTip = new TranslationTextComponent(title + ".desc"); } @Override @@ -24,4 +32,10 @@ public Widget createWidget(GameSettings settings, int x, int y, int width) { return new ControllableOptionSlider(settings, x, y, width, 20, this); } + + @Override + public List getToolTip() + { + return Minecraft.getInstance().fontRenderer.listFormattedStringToWidth(this.toolTip.getFormattedText(), 200); + } } diff --git a/src/main/java/com/mrcrayfish/controllable/client/settings/ControllerOptions.java b/src/main/java/com/mrcrayfish/controllable/client/settings/ControllerOptions.java index e3796afd..ca632d84 100644 --- a/src/main/java/com/mrcrayfish/controllable/client/settings/ControllerOptions.java +++ b/src/main/java/com/mrcrayfish/controllable/client/settings/ControllerOptions.java @@ -1,22 +1,15 @@ package com.mrcrayfish.controllable.client.settings; -import com.google.common.base.Charsets; -import com.google.common.base.Splitter; -import com.mrcrayfish.controllable.Controllable; -import com.mrcrayfish.controllable.client.ControllerType; +import com.mrcrayfish.controllable.Config; +import com.mrcrayfish.controllable.client.ActionVisibility; +import com.mrcrayfish.controllable.client.ControllerIcons; import com.mrcrayfish.controllable.client.CursorType; -import net.minecraft.client.resources.I18n; import net.minecraft.client.settings.BooleanOption; import net.minecraft.client.settings.SliderPercentageOption; -import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.math.MathHelper; -import org.apache.commons.io.IOUtils; +import net.minecraft.util.text.TranslationTextComponent; -import java.io.*; -import java.nio.charset.StandardCharsets; import java.text.DecimalFormat; -import java.util.Iterator; -import java.util.List; /** * Author: MrCrayfish @@ -26,263 +19,111 @@ public class ControllerOptions private static final DecimalFormat FORMAT = new DecimalFormat("0.0#"); public static final BooleanOption FORCE_FEEDBACK = new ControllableBooleanOption("controllable.options.forceFeedback", gameSettings -> { - return Controllable.getOptions().forceFeedback; + return Config.CLIENT.options.forceFeedback.get(); }, (gameSettings, value) -> { - Controllable.getOptions().forceFeedback = value; + Config.CLIENT.options.forceFeedback.set(value); + Config.save(); }); public static final BooleanOption AUTO_SELECT = new ControllableBooleanOption("controllable.options.autoSelect", gameSettings -> { - return Controllable.getOptions().autoSelect; + return Config.CLIENT.options.autoSelect.get(); }, (gameSettings, value) -> { - Controllable.getOptions().autoSelect = value; + Config.CLIENT.options.autoSelect.set(value); + Config.save(); }); public static final BooleanOption RENDER_MINI_PLAYER = new ControllableBooleanOption("controllable.options.renderMiniPlayer", gameSettings -> { - return Controllable.getOptions().renderMiniPlayer; + return Config.CLIENT.options.renderMiniPlayer.get(); }, (gameSettings, value) -> { - Controllable.getOptions().renderMiniPlayer = value; + Config.CLIENT.options.renderMiniPlayer.set(value); + Config.save(); }); public static final BooleanOption VIRTUAL_MOUSE = new ControllableBooleanOption("controllable.options.virtualMouse", gameSettings -> { - return Controllable.getOptions().virtualMouse; + return Config.CLIENT.options.virtualMouse.get(); }, (gameSettings, value) -> { - Controllable.getOptions().virtualMouse = value; + Config.CLIENT.options.virtualMouse.set(value); + Config.save(); }); public static final BooleanOption CONSOLE_HOTBAR = new ControllableBooleanOption("controllable.options.consoleHotbar", gameSettings -> { - return Controllable.getOptions().consoleHotbar; + return Config.CLIENT.options.consoleHotbar.get(); }, (gameSettings, value) -> { - Controllable.getOptions().consoleHotbar = value; + Config.CLIENT.options.consoleHotbar.set(value); + Config.save(); }); public static final ControllableEnumOption CURSOR_TYPE = new ControllableEnumOption<>("controllable.options.cursorType", CursorType.class, gameSettings -> { - return Controllable.getOptions().cursorType; + return Config.CLIENT.options.cursorType.get(); }, (gameSettings, cursorType) -> { - Controllable.getOptions().cursorType = cursorType; + Config.CLIENT.options.cursorType.set(cursorType); + Config.save(); }, (gameSettings, controllableEnumOption) -> { CursorType cursorType = controllableEnumOption.get(gameSettings); - return I18n.format("controllable.cursor." + cursorType.getName()); + return new TranslationTextComponent("controllable.options.cursorType.format", new TranslationTextComponent("controllable.cursor." + cursorType.getName())).getFormattedText(); }); - public static final ControllableEnumOption CONTROLLER_TYPE = new ControllableEnumOption<>("controllable.options.controllerType", ControllerType.class, gameSettings -> { - return Controllable.getOptions().controllerType; - }, (gameSettings, controllerType) -> { - Controllable.getOptions().controllerType = controllerType; + public static final ControllableEnumOption CONTROLLER_ICONS = new ControllableEnumOption<>("controllable.options.controllerIcons", ControllerIcons.class, gameSettings -> { + return Config.CLIENT.options.controllerIcons.get(); + }, (gameSettings, controllerIcons) -> { + Config.CLIENT.options.controllerIcons.set(controllerIcons); + Config.save(); }, (gameSettings, controllableEnumOption) -> { - ControllerType controllerType = controllableEnumOption.get(gameSettings); - return I18n.format("controllable.controller." + controllerType.getName()); + ControllerIcons controllerIcons = controllableEnumOption.get(gameSettings); + return new TranslationTextComponent("controllable.options.controllerIcons.format", new TranslationTextComponent("controllable.controller." + controllerIcons.getName())).getFormattedText(); }); public static final BooleanOption INVERT_LOOK = new ControllableBooleanOption("controllable.options.invertLook", gameSettings -> { - return Controllable.getOptions().invertLook; + return Config.CLIENT.options.invertLook.get(); }, (gameSettings, value) -> { - Controllable.getOptions().invertLook = value; + Config.CLIENT.options.invertLook.set(value); + Config.save(); }); public static final SliderPercentageOption DEAD_ZONE = new ControllableSliderPercentageOption("controllable.options.deadZone", 0.0, 1.0, 0.01F, gameSettings -> { - return Controllable.getOptions().deadZone; + return Config.CLIENT.options.deadZone.get(); }, (gameSettings, value) -> { - Controllable.getOptions().deadZone = MathHelper.clamp(value, 0.0, 1.0); + Config.CLIENT.options.deadZone.set(MathHelper.clamp(value, 0.0, 1.0)); + Config.save(); }, (gameSettings, option) -> { - double deadZone = Controllable.getOptions().deadZone; - return I18n.format("controllable.options.deadZone.format", FORMAT.format(deadZone)); + double deadZone = Config.CLIENT.options.deadZone.get(); + return new TranslationTextComponent("controllable.options.deadZone.format", FORMAT.format(deadZone)).getFormattedText(); }); public static final SliderPercentageOption ROTATION_SPEED = new ControllableSliderPercentageOption("controllable.options.rotationSpeed", 1.0, 50.0, 1.0F, gameSettings -> { - return Controllable.getOptions().rotationSpeed; + return Config.CLIENT.options.rotationSpeed.get(); }, (gameSettings, value) -> { - Controllable.getOptions().rotationSpeed = MathHelper.clamp(value, 1.0, 50.0); + Config.CLIENT.options.rotationSpeed.set(MathHelper.clamp(value, 0.0, 50.0)); + Config.save(); }, (gameSettings, option) -> { - double rotationSpeed = Controllable.getOptions().rotationSpeed; - return I18n.format("controllable.options.rotationSpeed.format", FORMAT.format(rotationSpeed)); + double rotationSpeed = Config.CLIENT.options.rotationSpeed.get(); + return new TranslationTextComponent("controllable.options.rotationSpeed.format", FORMAT.format(rotationSpeed)).getFormattedText(); }); public static final SliderPercentageOption MOUSE_SPEED = new ControllableSliderPercentageOption("controllable.options.mouseSpeed", 1.0, 50.0, 1.0F, gameSettings -> { - return Controllable.getOptions().mouseSpeed; + return Config.CLIENT.options.mouseSpeed.get(); }, (gameSettings, value) -> { - Controllable.getOptions().mouseSpeed = MathHelper.clamp(value, 1.0, 50.0); + Config.CLIENT.options.mouseSpeed.set(MathHelper.clamp(value, 0.0, 50.0)); + Config.save(); }, (gameSettings, option) -> { - double mouseSpeed = Controllable.getOptions().mouseSpeed; - return I18n.format("controllable.options.mouseSpeed.format", FORMAT.format(mouseSpeed)); + double mouseSpeed = Config.CLIENT.options.mouseSpeed.get(); + return new TranslationTextComponent("controllable.options.mouseSpeed.format", FORMAT.format(mouseSpeed)).getFormattedText(); }); - public static final Splitter COLON_SPLITTER = Splitter.on(':'); - - private File optionsFile; - private boolean forceFeedback = true; - private boolean autoSelect = true; - private boolean renderMiniPlayer = true; - private boolean virtualMouse = true; - private boolean consoleHotbar = false; - private CursorType cursorType = CursorType.LIGHT; - private ControllerType controllerType = ControllerType.DEFAULT; - private boolean invertLook = false; - private double deadZone = 0.15; - private double rotationSpeed = 25.0; - private double mouseSpeed = 30.0; - - public ControllerOptions(File dataDir) - { - this.optionsFile = new File(dataDir, "controllable-options.txt"); - this.loadOptions(); - } - - private void loadOptions() - { - try - { - if(!this.optionsFile.exists()) - { - return; - } - - List lines = IOUtils.readLines(new FileInputStream(this.optionsFile), Charsets.UTF_8); - CompoundNBT compound = new CompoundNBT(); - - for(String line : lines) - { - try - { - Iterator iterator = COLON_SPLITTER.omitEmptyStrings().limit(2).split(line).iterator(); - compound.putString(iterator.next(), iterator.next()); - } - catch(Exception var10) - { - Controllable.LOGGER.warn("Skipping bad option: {}", line); - } - } - - for(String key : compound.keySet()) - { - String value = compound.getString(key); - - try - { - switch(key) - { - case "forceFeedback": - this.forceFeedback = Boolean.valueOf(value); - break; - case "autoSelect": - this.autoSelect = Boolean.valueOf(value); - break; - case "renderMiniPlayer": - this.renderMiniPlayer = Boolean.valueOf(value); - break; - case "virtualMouse": - this.virtualMouse = Boolean.valueOf(value); - break; - case "consoleHotbar": - this.consoleHotbar = Boolean.valueOf(value); - break; - case "cursorType": - this.cursorType = CursorType.byId(value); - break; - case "controllerType": - this.controllerType = ControllerType.byName(value); - break; - case "invertLook": - this.invertLook = Boolean.valueOf(value); - break; - case "deadZone": - this.deadZone = Double.parseDouble(value); - break; - case "rotationSpeed": - this.rotationSpeed = Double.parseDouble(value); - break; - case "mouseSpeed": - this.mouseSpeed = Double.parseDouble(value); - break; - } - } - catch(Exception e) - { - Controllable.LOGGER.warn("Skipping bad option: {}:{}", key, value); - } - } - } - catch(Exception e) - { - Controllable.LOGGER.error("Failed to load options", e); - } - - } - - public void saveOptions() - { - try(PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(this.optionsFile), StandardCharsets.UTF_8))) - { - writer.println("forceFeedback:" + this.forceFeedback); - writer.println("autoSelect:" + this.autoSelect); - writer.println("renderMiniPlayer:" + this.renderMiniPlayer); - writer.println("virtualMouse:" + this.virtualMouse); - writer.println("consoleHotbar:" + this.consoleHotbar); - writer.println("cursorType:" + this.cursorType.getName()); - writer.println("controllerType:" + this.controllerType.getName()); - writer.println("invertLook:" + this.invertLook); - writer.println("deadZone:" + FORMAT.format(this.deadZone)); - writer.println("rotationSpeed:" + FORMAT.format(this.rotationSpeed)); - writer.println("mouseSpeed:" + FORMAT.format(this.mouseSpeed)); - } - catch(FileNotFoundException e) - { - e.printStackTrace(); - } - } - - public boolean useForceFeedback() - { - return this.forceFeedback; - } - - public boolean isAutoSelect() - { - return this.autoSelect; - } - - public boolean isRenderMiniPlayer() - { - return renderMiniPlayer; - } - - public boolean isVirtualMouse() - { - return virtualMouse; - } - - public boolean useConsoleHotbar() - { - return consoleHotbar; - } - - public CursorType getCursorType() - { - return cursorType; - } - - public ControllerType getControllerType() - { - return controllerType; - } - - public boolean isInvertLook() - { - return invertLook; - } - - public double getDeadZone() - { - return this.deadZone; - } - - public double getRotationSpeed() - { - return this.rotationSpeed; - } - - public double getMouseSpeed() - { - return this.mouseSpeed; - } + public static final ControllableEnumOption SHOW_ACTIONS = new ControllableEnumOption<>("controllable.options.showActions", ActionVisibility.class, gameSettings -> { + return Config.CLIENT.options.showActions.get(); + }, (gameSettings, value) -> { + Config.CLIENT.options.showActions.set(value); + Config.save(); + }, (gameSettings, option) -> { + ActionVisibility visibility = option.get(gameSettings); + return new TranslationTextComponent("controllable.options.showActions.format", new TranslationTextComponent("controllable.actionVisibility." + visibility.getName())).getFormattedText(); + }); + public static final BooleanOption QUICK_CRAFT = new ControllableBooleanOption("controllable.options.quickCraft", gameSettings -> { + return Config.CLIENT.options.quickCraft.get(); + }, (gameSettings, value) -> { + Config.CLIENT.options.quickCraft.set(value); + Config.save(); + }); } diff --git a/src/main/java/com/mrcrayfish/controllable/event/AvailableActionsEvent.java b/src/main/java/com/mrcrayfish/controllable/event/AvailableActionsEvent.java index f397b9a4..5fcf1316 100644 --- a/src/main/java/com/mrcrayfish/controllable/event/AvailableActionsEvent.java +++ b/src/main/java/com/mrcrayfish/controllable/event/AvailableActionsEvent.java @@ -8,6 +8,7 @@ /** * Author: MrCrayfish */ +@Deprecated public class AvailableActionsEvent extends Event { private Map actions; @@ -19,6 +20,6 @@ public AvailableActionsEvent(Map actions) public Map getActions() { - return actions; + return this.actions; } } diff --git a/src/main/java/com/mrcrayfish/controllable/event/ControllerEvent.java b/src/main/java/com/mrcrayfish/controllable/event/ControllerEvent.java index 58533929..76871e8e 100644 --- a/src/main/java/com/mrcrayfish/controllable/event/ControllerEvent.java +++ b/src/main/java/com/mrcrayfish/controllable/event/ControllerEvent.java @@ -18,7 +18,7 @@ public ControllerEvent(Controller controller) public Controller getController() { - return controller; + return this.controller; } @Cancelable @@ -43,7 +43,7 @@ public ButtonInput(Controller controller, int button, boolean state) */ public int getButton() { - return originalButton; + return this.originalButton; } /** @@ -54,7 +54,7 @@ public int getButton() */ public int getModifiedButton() { - return button; + return this.button; } /** @@ -76,7 +76,7 @@ public void setButton(int button) */ public boolean getState() { - return state; + return this.state; } } @@ -119,7 +119,7 @@ public Turn(Controller controller, float yawSpeed, float pitchSpeed) */ public float getYawSpeed() { - return yawSpeed; + return this.yawSpeed; } /** @@ -140,7 +140,7 @@ public void setYawSpeed(float yawSpeed) */ public float getPitchSpeed() { - return pitchSpeed; + return this.pitchSpeed; } /** diff --git a/src/main/java/com/mrcrayfish/controllable/event/GatherActionsEvent.java b/src/main/java/com/mrcrayfish/controllable/event/GatherActionsEvent.java new file mode 100644 index 00000000..e1efb972 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/event/GatherActionsEvent.java @@ -0,0 +1,33 @@ +package com.mrcrayfish.controllable.event; + +import com.mrcrayfish.controllable.client.Action; +import com.mrcrayfish.controllable.client.ActionVisibility; +import com.mrcrayfish.controllable.client.ButtonBinding; +import net.minecraftforge.eventbus.api.Event; + +import java.util.Map; + +/** + * Author: MrCrayfish + */ +public class GatherActionsEvent extends Event +{ + private Map actions; + private ActionVisibility visibility; + + public GatherActionsEvent(Map actions, ActionVisibility visibility) + { + this.actions = actions; + this.visibility = visibility; + } + + public Map getActions() + { + return this.actions; + } + + public ActionVisibility getVisibility() + { + return this.visibility; + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/event/GatherNavigationPointsEvent.java b/src/main/java/com/mrcrayfish/controllable/event/GatherNavigationPointsEvent.java new file mode 100644 index 00000000..45290123 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/event/GatherNavigationPointsEvent.java @@ -0,0 +1,26 @@ +package com.mrcrayfish.controllable.event; + +import com.google.common.collect.ImmutableList; +import com.mrcrayfish.controllable.client.gui.navigation.NavigationPoint; +import net.minecraftforge.eventbus.api.Event; + +import java.util.ArrayList; +import java.util.List; + +/** + * Author: MrCrayfish + */ +public class GatherNavigationPointsEvent extends Event +{ + private List points = new ArrayList<>(); + + public void addPoint(NavigationPoint point) + { + this.points.add(point); + } + + public List getPoints() + { + return ImmutableList.copyOf(this.points); + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/event/RenderAvailableActionsEvent.java b/src/main/java/com/mrcrayfish/controllable/event/RenderAvailableActionsEvent.java index 69bbe383..044454cf 100644 --- a/src/main/java/com/mrcrayfish/controllable/event/RenderAvailableActionsEvent.java +++ b/src/main/java/com/mrcrayfish/controllable/event/RenderAvailableActionsEvent.java @@ -1,10 +1,12 @@ package com.mrcrayfish.controllable.event; +import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; /** * Author: MrCrayfish */ +@Cancelable public class RenderAvailableActionsEvent extends Event { } diff --git a/src/main/java/com/mrcrayfish/controllable/integration/JustEnoughItems.java b/src/main/java/com/mrcrayfish/controllable/integration/JustEnoughItems.java new file mode 100644 index 00000000..6daac3f1 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/integration/JustEnoughItems.java @@ -0,0 +1,54 @@ +package com.mrcrayfish.controllable.integration; + +import com.mrcrayfish.controllable.client.gui.navigation.BasicNavigationPoint; +import com.mrcrayfish.controllable.client.gui.navigation.NavigationPoint; +import com.mrcrayfish.controllable.client.gui.navigation.WidgetNavigationPoint; +import com.mrcrayfish.controllable.mixin.client.jei.IngredientGridMixin; +import com.mrcrayfish.controllable.mixin.client.jei.IngredientGridWithNavigationMixin; +import com.mrcrayfish.controllable.mixin.client.jei.IngredientListOverlayMixin; +import com.mrcrayfish.controllable.mixin.client.jei.PageNavigationMixin; +import mezz.jei.Internal; +import mezz.jei.gui.PageNavigation; +import mezz.jei.gui.overlay.IngredientGrid; +import mezz.jei.gui.overlay.IngredientGridWithNavigation; +import mezz.jei.render.IngredientListBatchRenderer; +import mezz.jei.render.IngredientListSlot; +import mezz.jei.runtime.JeiRuntime; +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.client.renderer.Rectangle2d; + +import java.util.ArrayList; +import java.util.List; + +/** + * Author: MrCrayfish + */ +public class JustEnoughItems +{ + public static List getNavigationPoints() + { + List points = new ArrayList<>(); + JeiRuntime runtime = Internal.getRuntime(); + if(runtime != null && runtime.getIngredientListOverlay().isListDisplayed()) + { + // JEI just needs getters and I wouldn't have to do this mess + IngredientGridWithNavigation ingredientGridWithNavigation = ((IngredientListOverlayMixin) runtime.getIngredientListOverlay()).getContents(); + IngredientGrid ingredientGrid = ((IngredientGridWithNavigationMixin) ingredientGridWithNavigation).getIngredientGrid(); + IngredientListBatchRenderer ingredientListBatchRenderer = ((IngredientGridMixin) ingredientGrid).getGuiIngredientSlots(); + + List slots = ingredientListBatchRenderer.getAllGuiIngredientSlots(); + for(IngredientListSlot slot : slots) + { + Rectangle2d area = slot.getArea(); + points.add(new BasicNavigationPoint(area.getX() + area.getWidth() / 2.0, area.getY() + area.getHeight() / 2.0)); + } + + PageNavigation navigation = ((IngredientGridWithNavigationMixin) ingredientGridWithNavigation).getNavigation(); + Widget backButton = ((PageNavigationMixin) navigation).getBackButton(); + points.add(new WidgetNavigationPoint(backButton.x + backButton.getWidth() / 2.0, backButton.y + backButton.getHeight() / 2.0, backButton)); + Widget nextButton = ((PageNavigationMixin) navigation).getNextButton(); + points.add(new WidgetNavigationPoint(nextButton.x + nextButton.getWidth() / 2.0, nextButton.y + nextButton.getHeight() / 2.0, nextButton)); + } + return points; + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/ControllableMixinPlugin.java b/src/main/java/com/mrcrayfish/controllable/mixin/ControllableMixinPlugin.java new file mode 100644 index 00000000..140d73bd --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/ControllableMixinPlugin.java @@ -0,0 +1,66 @@ +package com.mrcrayfish.controllable.mixin; + +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +/** + * Author: MrCrayfish + */ +public class ControllableMixinPlugin implements IMixinConfigPlugin +{ + private boolean optifineLoaded; + + @Override + public void onLoad(String mixinPackage) + { + try + { + Class.forName("optifine.Installer"); + this.optifineLoaded = true; + } + catch (ClassNotFoundException e) + { + this.optifineLoaded = false; + } + } + + @Override + public String getRefMapperConfig() + { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) + { + return this.optifineLoaded ? !mixinClassName.equals("com.mrcrayfish.controllable.mixin.client.GameRendererMixin") : !mixinClassName.equals("com.mrcrayfish.controllable.mixin.client.OptifineGameRendererMixin"); + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) + { + + } + + @Override + public List getMixins() + { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) + { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) + { + + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/ClientPlayerEntityMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/ClientPlayerEntityMixin.java new file mode 100644 index 00000000..b7ca377a --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/ClientPlayerEntityMixin.java @@ -0,0 +1,26 @@ +package com.mrcrayfish.controllable.mixin.client; + +import com.mrcrayfish.controllable.client.ButtonBindings; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * Author: MrCrayfish + */ +@Mixin(ClientPlayerEntity.class) +public class ClientPlayerEntityMixin +{ + @Inject(method = "func_225510_bt_", at = @At(value = "HEAD"), cancellable = true) + private void isEntityGlowing(CallbackInfoReturnable cir) + { + Minecraft mc = Minecraft.getInstance(); + if(mc.player != null && mc.player.isSpectator() && ButtonBindings.HIGHLIGHT_PLAYERS.isButtonDown()) + { + cir.setReturnValue(true); + } + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/ContainerScreenMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/ContainerScreenMixin.java new file mode 100644 index 00000000..9ba0230a --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/ContainerScreenMixin.java @@ -0,0 +1,82 @@ +package com.mrcrayfish.controllable.mixin.client; + +import com.mrcrayfish.controllable.Controllable; +import com.mrcrayfish.controllable.client.Buttons; +import com.mrcrayfish.controllable.client.Controller; +import net.minecraft.client.gui.screen.inventory.ContainerScreen; +import net.minecraft.inventory.container.ClickType; +import net.minecraft.inventory.container.Slot; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Author: MrCrayfish + */ +@Mixin(ContainerScreen.class) +public abstract class ContainerScreenMixin +{ + @Shadow + private ItemStack shiftClickedSlot; + + @Redirect(method = "mouseClicked", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/inventory/ContainerScreen;handleMouseClick(Lnet/minecraft/inventory/container/Slot;IILnet/minecraft/inventory/container/ClickType;)V", ordinal = 1)) + private void onClicked(ContainerScreen screen, Slot slotIn, int slotId, int mouseButton, ClickType type) + { + if(slotId != -999 && canQuickMove()) + { + this.shiftClickedSlot = slotIn != null && slotIn.getHasStack() ? slotIn.getStack().copy() : ItemStack.EMPTY; + type = ClickType.QUICK_MOVE; + } + this.handleMouseClick(screen, slotIn, slotId, mouseButton, type); + } + + @Redirect(method = "mouseReleased", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/inventory/ContainerScreen;handleMouseClick(Lnet/minecraft/inventory/container/Slot;IILnet/minecraft/inventory/container/ClickType;)V", ordinal = 9)) + private void onReleased(ContainerScreen screen, Slot slotIn, int slotId, int mouseButton, ClickType type) + { + if(slotId != -999 && canQuickMove()) + { + this.shiftClickedSlot = slotIn != null && slotIn.getHasStack() ? slotIn.getStack().copy() : ItemStack.EMPTY; + type = ClickType.QUICK_MOVE; + } + this.handleMouseClick(screen, slotIn, slotId, mouseButton, type); + } + + private Method method; + + /** + * Manually invokes handleMouseClick from ContainerScreen using Java reflection. Mixins does not + * support the ability to invoke methods from sub classes when using Invoker annotation. If I am + * doing something wrong with Invoker, please PR into my repo! + */ + private void handleMouseClick(ContainerScreen screen, Slot slotIn, int slotId, int mouseButton, ClickType type) + { + // Cache the method as it only needs to be found once. + if(this.method == null) + { + this.method = ObfuscationReflectionHelper.findMethod(ContainerScreen.class, "func_184098_a", Slot.class, int.class, int.class, ClickType.class); + } + try + { + this.method.invoke(screen, slotIn, slotId, mouseButton, type); + } + catch(IllegalAccessException | InvocationTargetException e) + { + e.printStackTrace(); + } + } + + /** + * Checks if a controller is connected and the quick move button is down + */ + private static boolean canQuickMove() + { + Controller controller = Controllable.getController(); + return controller != null && Controllable.isButtonPressed(Buttons.B); + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/CreativeScreenMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/CreativeScreenMixin.java new file mode 100644 index 00000000..c159e51f --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/CreativeScreenMixin.java @@ -0,0 +1,17 @@ +package com.mrcrayfish.controllable.mixin.client; + +import net.minecraft.client.gui.screen.inventory.CreativeScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** + * Author: MrCrayfish + */ +@Mixin(CreativeScreen.class) +public interface CreativeScreenMixin +{ + @Accessor(value = "tabPage", remap = false) + static int getTabPage() { + throw new AssertionError(); + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/ForgeIngameGuiMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/ForgeIngameGuiMixin.java new file mode 100644 index 00000000..cf425c97 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/ForgeIngameGuiMixin.java @@ -0,0 +1,52 @@ +package com.mrcrayfish.controllable.mixin.client; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mrcrayfish.controllable.Config; +import com.mrcrayfish.controllable.Controllable; +import com.mrcrayfish.controllable.client.ButtonBindings; +import com.mrcrayfish.controllable.client.Controller; +import net.minecraft.client.settings.KeyBinding; +import net.minecraftforge.client.gui.ForgeIngameGui; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * Author: MrCrayfish + */ +@Mixin(ForgeIngameGui.class) +public class ForgeIngameGuiMixin +{ + /** + * Fixes record name rendering not being offset by console hotbar + */ + @Inject(method = "renderRecordOverlay", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;pushMatrix()V", shift = At.Shift.AFTER)) + private void renderRecordOverlay(int width, int height, float partialTicks, CallbackInfo ci) + { + if(Config.CLIENT.options.consoleHotbar.get()) + { + RenderSystem.translated(0, -20, 0); + } + } + + /** + * Fixes record name rendering not being offset by console hotbar + */ + @Redirect(method = "renderPlayerList", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/settings/KeyBinding;isKeyDown()Z")) + private boolean renderPlayerList(KeyBinding binding) + { + return binding.isKeyDown() || canShowPlayerList(); + } + + /** + * Checks if a controller is connected and the player list button is down + */ + private static boolean canShowPlayerList() + { + Controller controller = Controllable.getController(); + return controller != null && ButtonBindings.PLAYER_LIST.isButtonDown(); + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/GameRendererMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/GameRendererMixin.java new file mode 100644 index 00000000..7bdb6725 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/GameRendererMixin.java @@ -0,0 +1,45 @@ +package com.mrcrayfish.controllable.mixin.client; + +import com.mrcrayfish.controllable.Config; +import com.mrcrayfish.controllable.Controllable; +import com.mrcrayfish.controllable.client.ControllerInput; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArgs; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.invoke.arg.Args; + +/** + * Author: MrCrayfish + */ +@Mixin(GameRenderer.class) +public class GameRendererMixin +{ + /** + * Fixes the mouse position when virtual mouse is turned on for controllers. + */ + @ModifyArgs(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/client/ForgeHooksClient;drawScreen(Lnet/minecraft/client/gui/screen/Screen;IIF)V", remap = false)) + private void drawScreen(Args args) + { + ControllerInput input = Controllable.getInput(); + if(Controllable.getController() != null && Config.CLIENT.options.virtualMouse.get() && input.getLastUse() > 0) + { + Minecraft minecraft = Minecraft.getInstance(); + int mouseX = (int) (input.getVirtualMouseX() * (double) minecraft.getMainWindow().getScaledWidth() / (double) minecraft.getMainWindow().getWidth()); + int mouseY = (int) (input.getVirtualMouseY() * (double) minecraft.getMainWindow().getScaledHeight() / (double) minecraft.getMainWindow().getHeight()); + args.set(1, mouseX); + args.set(2, mouseY); + } + } + + @Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;displayInGameMenu(Z)V")) + private void onPause(Minecraft minecraft, boolean pauseOnly) + { + if(Controllable.getController() == null || !Config.CLIENT.options.virtualMouse.get()) + { + minecraft.displayInGameMenu(false); + } + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/IngameGuiMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/IngameGuiMixin.java new file mode 100644 index 00000000..b33348e5 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/IngameGuiMixin.java @@ -0,0 +1,37 @@ +package com.mrcrayfish.controllable.mixin.client; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mrcrayfish.controllable.Config; +import net.minecraft.client.gui.IngameGui; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * Author: MrCrayfish + */ +@Mixin(IngameGui.class) +public class IngameGuiMixin +{ + /** + * Fixes selected item name rendering not being offset by console hotbar + */ + @Inject(method = "renderHotbar", at = @At(value = "HEAD")) + private void beforeRenderHotbarCall(float partialTicks, CallbackInfo ci) + { + if(Config.CLIENT.options.consoleHotbar.get()) + { + RenderSystem.translated(0, -20, 0); + } + } + + @Inject(method = "renderHotbar", at = @At(value = "TAIL")) + private void afterRenderHotbarCall(float partialTicks, CallbackInfo ci) + { + if(Config.CLIENT.options.consoleHotbar.get()) + { + RenderSystem.translated(0, 20, 0); + } + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/MinecraftMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..2cac7dd8 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/MinecraftMixin.java @@ -0,0 +1,69 @@ +package com.mrcrayfish.controllable.mixin.client; + +import com.mrcrayfish.controllable.Config; +import com.mrcrayfish.controllable.Controllable; +import com.mrcrayfish.controllable.client.ButtonBindings; +import com.mrcrayfish.controllable.client.Controller; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.client.settings.KeyBinding; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.injection.*; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.invoke.arg.Args; + +import javax.annotation.Nullable; + +/** + * Author: MrCrayfish + */ +@Mixin(Minecraft.class) +public class MinecraftMixin +{ + @Shadow + public ClientPlayerEntity player; + + @ModifyArgs(method = "processKeyBinds", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;sendClickBlockToController(Z)V")) + private void sendClickBlockToController(Args args) + { + boolean leftClick = args.get(0); + args.set(0, leftClick || isLeftClicking()); + } + + @Redirect(method = "processKeyBinds", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/settings/KeyBinding;isKeyDown()Z"), slice = @Slice( + from = @At(value = "INVOKE", target = "Lnet/minecraft/client/entity/player/ClientPlayerEntity;isHandActive()Z"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/PlayerController;onStoppedUsingItem(Lnet/minecraft/entity/player/PlayerEntity;)V"))) + private boolean onKeyDown(KeyBinding binding) + { + return binding.isKeyDown() || isRightClicking(); + } + + /** + * Checks if a controller is connected and if the use item button is down. + */ + private static boolean isRightClicking() + { + Controller controller = Controllable.getController(); + return controller != null && ButtonBindings.USE_ITEM.isButtonDown(); + } + + /** + * Checks if a controller is connected and if the attack button is down. A special except is + * added when virtual mouse is enabled and it will ignore if the mouse is grabbed or not. + */ + private static boolean isLeftClicking() + { + Minecraft mc = Minecraft.getInstance(); + Controller controller = Controllable.getController(); + if(controller != null && ButtonBindings.ATTACK.isButtonDown()) + { + boolean usingVirtualMouse = (Config.CLIENT.options.virtualMouse.get() && Controllable.getInput().getLastUse() > 0); + return mc.currentScreen == null && (mc.mouseHelper.isMouseGrabbed() || usingVirtualMouse); + } + return false; + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/MouseHelperMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/MouseHelperMixin.java new file mode 100644 index 00000000..2cb96522 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/MouseHelperMixin.java @@ -0,0 +1,26 @@ +package com.mrcrayfish.controllable.mixin.client; + +import com.mrcrayfish.controllable.Controllable; +import com.mrcrayfish.controllable.client.ControllerInput; +import net.minecraft.client.MouseHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * Author: MrCrayfish + */ +@Mixin(MouseHelper.class) +public class MouseHelperMixin +{ + @Inject(method = "cursorPosCallback", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MouseHelper;updatePlayerLook()V")) + private void beforeUpdateLook(long handle, double x, double y, CallbackInfo ci) + { + ControllerInput input = Controllable.getInput(); + if(input != null) + { + input.resetLastUse(); + } + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/OptifineGameRendererMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/OptifineGameRendererMixin.java new file mode 100644 index 00000000..e43da649 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/OptifineGameRendererMixin.java @@ -0,0 +1,36 @@ +package com.mrcrayfish.controllable.mixin.client; + +import com.mrcrayfish.controllable.Config; +import com.mrcrayfish.controllable.Controllable; +import com.mrcrayfish.controllable.client.ControllerInput; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArgs; +import org.spongepowered.asm.mixin.injection.invoke.arg.Args; + +/** + * Author: MrCrayfish + */ +@Mixin(GameRenderer.class) +public class OptifineGameRendererMixin +{ + /** + * Fixes the mouse position when virtual mouse is turned on for controllers. + */ + @ModifyArgs(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lnet/optifine/reflect/Reflector;callVoid(Lnet/optifine/reflect/ReflectorMethod;[Ljava/lang/Object;)V", remap = false)) + private void drawScreen(Args args) + { + Object[] params = args.get(1); + ControllerInput input = Controllable.getInput(); + if(Controllable.getController() != null && Config.CLIENT.options.virtualMouse.get() && input.getLastUse() > 0) + { + Minecraft minecraft = Minecraft.getInstance(); + int mouseX = (int) (input.getVirtualMouseX() * (double) minecraft.getMainWindow().getScaledWidth() / (double) minecraft.getMainWindow().getWidth()); + int mouseY = (int) (input.getVirtualMouseY() * (double) minecraft.getMainWindow().getScaledHeight() / (double) minecraft.getMainWindow().getHeight()); + params[1] = mouseX; + params[2] = mouseY; + } + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/RecipeBookGuiMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/RecipeBookGuiMixin.java new file mode 100644 index 00000000..225e1fd3 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/RecipeBookGuiMixin.java @@ -0,0 +1,36 @@ +package com.mrcrayfish.controllable.mixin.client; + +import net.minecraft.client.gui.recipebook.RecipeBookGui; +import net.minecraft.client.gui.recipebook.RecipeBookPage; +import net.minecraft.client.gui.recipebook.RecipeTabToggleWidget; +import net.minecraft.client.gui.widget.ToggleWidget; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; + +/** + * Author: MrCrayfish + */ +@Mixin(RecipeBookGui.class) +public interface RecipeBookGuiMixin +{ + @Accessor("toggleRecipesBtn") + ToggleWidget getToggleRecipesBtn(); + + @Accessor("recipeTabs") + List getRecipeTabs(); + + @Accessor("recipeBookPage") + RecipeBookPage getRecipeBookPage(); + + @Accessor("currentTab") + RecipeTabToggleWidget getCurrentTab(); + + @Accessor("currentTab") + void setCurrentTab(RecipeTabToggleWidget tab); + + @Invoker("updateCollections") + void invokeUpdateCollections(boolean resetPages); +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/RecipeBookPageAccessor.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/RecipeBookPageAccessor.java new file mode 100644 index 00000000..4d0b3ba2 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/RecipeBookPageAccessor.java @@ -0,0 +1,35 @@ +package com.mrcrayfish.controllable.mixin.client; + +import net.minecraft.client.gui.recipebook.RecipeBookPage; +import net.minecraft.client.gui.recipebook.RecipeWidget; +import net.minecraft.client.gui.widget.ToggleWidget; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; + +/** + * Author: MrCrayfish + */ +@Mixin(RecipeBookPage.class) +public interface RecipeBookPageAccessor +{ + @Accessor("buttons") + List getButtons(); + + @Accessor("forwardButton") + ToggleWidget getForwardButton(); + + @Accessor("backButton") + ToggleWidget getBackButton(); + + @Accessor("currentPage") + int getCurrentPage(); + + @Accessor("currentPage") + void setCurrentPage(int page); + + @Invoker("updateButtonsForPage") + void invokeUpdateButtonsForPage(); +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/RecipeBookPageMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/RecipeBookPageMixin.java new file mode 100644 index 00000000..e22f4ee7 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/RecipeBookPageMixin.java @@ -0,0 +1,31 @@ +package com.mrcrayfish.controllable.mixin.client; + +import com.mrcrayfish.controllable.Config; +import com.mrcrayfish.controllable.Controllable; +import net.minecraft.client.gui.recipebook.RecipeBookPage; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArgs; +import org.spongepowered.asm.mixin.injection.invoke.arg.Args; + +import java.util.List; + +/** + * Author: MrCrayfish + */ +@Mixin(RecipeBookPage.class) +public class RecipeBookPageMixin +{ + @ModifyArgs(method = "renderTooltip", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;renderTooltip(Ljava/util/List;II)V")) + private void modifyRenderToolTip(Args args) + { + if(Controllable.getInput().isControllerInUse() && Config.CLIENT.options.quickCraft.get()) + { + List components = args.get(0); + components.add(new TranslationTextComponent("controllable.tooltip.craft").applyTextStyle(TextFormatting.BOLD).applyTextStyle(TextFormatting.BLUE).getFormattedText()); + } + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/IngredientGridMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/IngredientGridMixin.java new file mode 100644 index 00000000..b09f4127 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/IngredientGridMixin.java @@ -0,0 +1,18 @@ +package com.mrcrayfish.controllable.mixin.client.jei; + +import mezz.jei.gui.overlay.IngredientGrid; +import mezz.jei.render.IngredientListBatchRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** + * Author: MrCrayfish + */ +@Pseudo +@Mixin(IngredientGrid.class) +public interface IngredientGridMixin +{ + @Accessor(value = "guiIngredientSlots", remap = false) + IngredientListBatchRenderer getGuiIngredientSlots(); +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/IngredientGridWithNavigationMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/IngredientGridWithNavigationMixin.java new file mode 100644 index 00000000..2c5a5eaf --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/IngredientGridWithNavigationMixin.java @@ -0,0 +1,22 @@ +package com.mrcrayfish.controllable.mixin.client.jei; + +import mezz.jei.gui.PageNavigation; +import mezz.jei.gui.overlay.IngredientGrid; +import mezz.jei.gui.overlay.IngredientGridWithNavigation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** + * Author: MrCrayfish + */ +@Pseudo +@Mixin(IngredientGridWithNavigation.class) +public interface IngredientGridWithNavigationMixin +{ + @Accessor(value = "navigation", remap = false) + PageNavigation getNavigation(); + + @Accessor(value = "ingredientGrid", remap = false) + IngredientGrid getIngredientGrid(); +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/IngredientListOverlayMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/IngredientListOverlayMixin.java new file mode 100644 index 00000000..61d063d0 --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/IngredientListOverlayMixin.java @@ -0,0 +1,18 @@ +package com.mrcrayfish.controllable.mixin.client.jei; + +import mezz.jei.gui.overlay.IngredientGridWithNavigation; +import mezz.jei.gui.overlay.IngredientListOverlay; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** + * Author: MrCrayfish + */ +@Pseudo +@Mixin(IngredientListOverlay.class) +public interface IngredientListOverlayMixin +{ + @Accessor(value = "contents", remap = false) + IngredientGridWithNavigation getContents(); +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/MouseUtilMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/MouseUtilMixin.java new file mode 100644 index 00000000..690e65ac --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/MouseUtilMixin.java @@ -0,0 +1,53 @@ +package com.mrcrayfish.controllable.mixin.client.jei; + +import com.mrcrayfish.controllable.Config; +import com.mrcrayfish.controllable.Controllable; +import com.mrcrayfish.controllable.client.ControllerInput; +import mezz.jei.input.MouseUtil; +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * JEI has a utility class to get the X and Y position of the mouse when it's not possible to + * retrieve them. This causes issues when virtual mouse is turned on (which is most of the time). + * This fixes compatibility with the mod. + * + * Author: MrCrayfish + */ +@Pseudo +@Mixin(MouseUtil.class) +public class MouseUtilMixin +{ + @Inject(method = "getX", at = @At(value = "TAIL"), remap = false, cancellable = true) + private static void getX(CallbackInfoReturnable cir) + { + ControllerInput input = Controllable.getInput(); + if(isVirtualMouseActive(input)) + { + Minecraft minecraft = Minecraft.getInstance(); + double mouseX = input.getVirtualMouseX() * (double) minecraft.getMainWindow().getScaledWidth() / (double) minecraft.getMainWindow().getWidth(); + cir.setReturnValue(mouseX); + } + } + + @Inject(method = "getY", at = @At(value = "TAIL"), remap = false, cancellable = true) + private static void getY(CallbackInfoReturnable cir) + { + ControllerInput input = Controllable.getInput(); + if(isVirtualMouseActive(input)) + { + Minecraft minecraft = Minecraft.getInstance(); + double mouseY = input.getVirtualMouseY() * (double) minecraft.getMainWindow().getScaledHeight() / (double) minecraft.getMainWindow().getHeight(); + cir.setReturnValue(mouseY); + } + } + + private static boolean isVirtualMouseActive(ControllerInput input) + { + return Controllable.getController() != null && Config.CLIENT.options.virtualMouse.get() && input.getLastUse() > 0; + } +} diff --git a/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/PageNavigationMixin.java b/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/PageNavigationMixin.java new file mode 100644 index 00000000..2e82154c --- /dev/null +++ b/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/PageNavigationMixin.java @@ -0,0 +1,21 @@ +package com.mrcrayfish.controllable.mixin.client.jei; + +import mezz.jei.gui.PageNavigation; +import mezz.jei.gui.elements.GuiIconButton; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** + * Author: MrCrayfish + */ +@Pseudo +@Mixin(PageNavigation.class) +public interface PageNavigationMixin +{ + @Accessor(value = "nextButton", remap = false) + GuiIconButton getNextButton(); + + @Accessor(value = "backButton", remap = false) + GuiIconButton getBackButton(); +} diff --git a/src/main/resources/META-INF/coremods.json b/src/main/resources/META-INF/coremods.json deleted file mode 100644 index e0ef8fe0..00000000 --- a/src/main/resources/META-INF/coremods.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Controllable": "coremods/controllable-transformer.js" -} \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 5c05e138..10d8d7e3 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,29 +1,33 @@ modLoader="javafml" -loaderVersion="[30,)" -updateJSONURL="https://raw.githubusercontent.com/MrCrayfish/Controllable/master/update.json" +loaderVersion="[31,)" +updateJSONURL="https://raw.githubusercontent.com/MrCrayfish/ModUpdates/master/controllable/update.json" issueTrackerURL="https://github.com/MrCrayfish/Controllable/issues" displayURL="https://mrcrayfish.com/mods?id=controllable" -logoFile="logo.png" -credits="" +logoFile="controllable.png" authors="MrCrayfish" +license="GNU General Public License 3.0" [[mods]] modId="controllable" -version="0.8.0" +version="0.11.0" displayName="Controllable" -description=''' -Adds the ability to use a controller to play Minecraft -''' +description="Adds the ability to use a controller to play Minecraft" [[dependencies.controllable]] modId="forge" mandatory=true - versionRange="[30.0.0,)" + versionRange="[31.2.0,)" ordering="NONE" side="CLIENT" [[dependencies.controllable]] modId="minecraft" mandatory=true - versionRange="[1.15.1,1.16)" + versionRange="[1.15.2]" + ordering="NONE" + side="CLIENT" +[[dependencies.controllable]] + modId="jei" + mandatory=false + versionRange="[6.0.3,)" ordering="NONE" side="CLIENT" \ No newline at end of file diff --git a/src/main/resources/assets/controllable/lang/de_de.json b/src/main/resources/assets/controllable/lang/de_de.json index 404bd518..338433e7 100644 --- a/src/main/resources/assets/controllable/lang/de_de.json +++ b/src/main/resources/assets/controllable/lang/de_de.json @@ -1,51 +1,53 @@ { - "controllable.action.break": "Abbauen", - "controllable.action.attack": "Attackieren", - "controllable.action.eat": "Essen", - "controllable.action.drink": "Trinken", - "controllable.action.block": "Blockieren", - "controllable.action.pull_bow": "Bogen ziehen", - "controllable.action.place_block": "Block platzieren", - "controllable.action.use_item": "Gegenstand benutzen", - "controllable.action.interact": "Interagieren", - "controllable.action.inventory": "Inventar", - "controllable.action.close_inventory": "Inventar schließen", - "controllable.action.swap_hands": "Hand wechseln", - "controllable.action.dismount": "Absteigen", - "controllable.action.jump": "Springen", - "controllable.action.sneak": "Schleichen", - "controllable.action.drop_item": "Gegenstand fallenlassen", - "controllable.action.pickup_stack": "Stapel nehmen", - "controllable.action.pickup_item": "Gegenstand nehmen", - "controllable.action.quick_move": "Schnell bewegen", - "controllable.action.place_stack": "Stapel platzieren", - "controllable.action.place_item": "Gegenstand platzieren", - "controllable.gui.title.select_controller": "Einen Controller ausw\u00e4hlen", - "controllable.gui.title.settings": "Einstellungen", - "controllable.gui.title.layout": "Kn\u00f6pfe zuordnen", - "controllable.gui.settings": "Einstellungen", - "controllable.gui.remap": "Kn\u00f6pfe zuordnen", - "controllable.gui.back": "Zur\u00fcck", - "controllable.options.forceFeedback": "Vibration", - "controllable.options.autoSelect": "Auto Auswahl", - "controllable.options.deadZone": "Totzone", - "controllable.options.deadZone.format": "Totzone: %s", - "controllable.options.rotationSpeed": "Rotationsgeschwindigkeit", - "controllable.options.rotationSpeed.format": "Rotationsgeschwindigkeit: %s", - "controllable.options.mouseSpeed": "Mausgeschwindigkeit", - "controllable.options.mouseSpeed.format": "Mausgeschwindigkeit: %s", - "controllable.options.renderMiniPlayer": "Zeige kleinen Spieler", - "controllable.options.virtualMouse": "Virtuelle Maus", - "controllable.options.consoleHotbar": "Konsolen Schnellzugriffsl.", - "controllable.options.cursorType": "Mauszeigertyp", - "controllable.options.controllerType": "Symbole", - "controllable.controller.default": "Standard", - "controllable.controller.playstation": "Playstation", - "controllable.controller.xbox": "Xbox", - "controllable.cursor.light": "Hell", - "controllable.cursor.dark": "Dunkel", - "controllable.cursor.console": "Konsole", - "controllable.toast.controller": "Controller", - "controllable.toast.connected": "Verbunden", - "controllable.toast.disconnected": "Getrennt" + "controllable.action.break": "Abbauen", + "controllable.action.attack": "Attackieren", + "controllable.action.eat": "Essen", + "controllable.action.drink": "Trinken", + "controllable.action.block": "Blockieren", + "controllable.action.pull_bow": "Bogen ziehen", + "controllable.action.place_block": "Block platzieren", + "controllable.action.use_item": "Gegenstand benutzen", + "controllable.action.interact": "Interagieren", + "controllable.action.inventory": "Inventar", + "controllable.action.close_inventory": "Inventar schließen", + "controllable.action.swap_hands": "Hand wechseln", + "controllable.action.dismount": "Absteigen", + "controllable.action.jump": "Springen", + "controllable.action.sneak": "Schleichen", + "controllable.action.drop_item": "Gegenstand fallenlassen", + "controllable.action.pickup_stack": "Stapel nehmen", + "controllable.action.pickup_item": "Gegenstand nehmen", + "controllable.action.quick_move": "Schnell bewegen", + "controllable.action.place_stack": "Stapel platzieren", + "controllable.action.place_item": "Gegenstand platzieren", + "controllable.gui.title.select_controller": "Einen Controller ausw\u00e4hlen", + "controllable.gui.title.settings": "Einstellungen", + "controllable.gui.title.layout": "Kn\u00f6pfe zuordnen", + "controllable.gui.settings": "Einstellungen", + "controllable.gui.remap": "Kn\u00f6pfe zuordnen", + "controllable.gui.back": "Zur\u00fcck", + "controllable.options.forceFeedback": "Vibration", + "controllable.options.autoSelect": "Auto Auswahl", + "controllable.options.deadZone": "Totzone", + "controllable.options.deadZone.format": "Totzone: %s", + "controllable.options.rotationSpeed": "Rotationsgeschwindigkeit", + "controllable.options.rotationSpeed.format": "Rotationsgeschwindigkeit: %s", + "controllable.options.mouseSpeed": "Mausgeschwindigkeit", + "controllable.options.mouseSpeed.format": "Mausgeschwindigkeit: %s", + "controllable.options.renderMiniPlayer": "Zeige kleinen Spieler", + "controllable.options.virtualMouse": "Virtuelle Maus", + "controllable.options.consoleHotbar": "Konsolen Schnellzugriffsl.", + "controllable.options.cursorType": "Mauszeigertyp", + "controllable.options.cursorType.format": "Mauszeigertyp: %s", + "controllable.options.controllerIcons": "Symbole", + "controllable.options.controllerIcons.format": "Symbole: %s", + "controllable.controller.default": "Standard", + "controllable.controller.playstation": "Playstation", + "controllable.controller.xbox": "Xbox", + "controllable.cursor.light": "Hell", + "controllable.cursor.dark": "Dunkel", + "controllable.cursor.console": "Konsole", + "controllable.toast.controller": "Controller", + "controllable.toast.connected": "Verbunden", + "controllable.toast.disconnected": "Getrennt" } diff --git a/src/main/resources/assets/controllable/lang/en_us.json b/src/main/resources/assets/controllable/lang/en_us.json index 58dab9cb..fa471f24 100644 --- a/src/main/resources/assets/controllable/lang/en_us.json +++ b/src/main/resources/assets/controllable/lang/en_us.json @@ -1,52 +1,124 @@ { - "controllable.action.break": "Break", - "controllable.action.attack": "Attack", - "controllable.action.eat": "Eat", - "controllable.action.drink": "Drink", - "controllable.action.block": "Block", - "controllable.action.pull_bow": "Pull Bow", - "controllable.action.place_block": "Place Block", - "controllable.action.use_item": "Use Item", - "controllable.action.interact": "Interact", - "controllable.action.inventory": "Inventory", - "controllable.action.close_inventory": "Close Inventory", - "controllable.action.swap_hands": "Swap Hands", - "controllable.action.dismount": "Dismount", - "controllable.action.jump": "Jump", - "controllable.action.sneak": "Sneak", - "controllable.action.drop_item": "Drop Item", - "controllable.action.pickup_stack": "Pickup Stack", - "controllable.action.pickup_item": "Pickup Item", - "controllable.action.quick_move": "Quick Move", - "controllable.action.place_stack": "Place Stack", - "controllable.action.place_item": "Place Item", - "controllable.gui.title.select_controller": "Select a Controller", - "controllable.gui.title.settings": "Settings", - "controllable.gui.title.layout": "Remap Buttons", - "controllable.gui.settings": "Settings", - "controllable.gui.remap": "Remap Buttons", - "controllable.gui.back": "Back", - "controllable.options.forceFeedback": "Vibration", - "controllable.options.autoSelect": "Auto Select", - "controllable.options.deadZone": "Dead Zone", - "controllable.options.deadZone.format": "Dead Zone: %s", - "controllable.options.rotationSpeed": "Rotation Speed", - "controllable.options.rotationSpeed.format": "Rotation Speed: %s", - "controllable.options.mouseSpeed": "Mouse Speed", - "controllable.options.mouseSpeed.format": "Mouse Speed: %s", - "controllable.options.renderMiniPlayer": "Render Mini Player", - "controllable.options.virtualMouse": "Virtual Mouse", - "controllable.options.consoleHotbar": "Console Hotbar", - "controllable.options.cursorType": "Cursor Type", - "controllable.options.controllerType": "Icons", - "controllable.options.invertLook": "Invert Look", - "controllable.controller.default": "Default", - "controllable.controller.playstation": "Playstation", - "controllable.controller.xbox": "Xbox", - "controllable.cursor.light": "Light", - "controllable.cursor.dark": "Dark", - "controllable.cursor.console": "Console", - "controllable.toast.controller": "Controller", - "controllable.toast.connected": "Connected", - "controllable.toast.disconnected": "Disconnected" + "controllable.action.break": "Break", + "controllable.action.attack": "Attack", + "controllable.action.eat": "Eat", + "controllable.action.drink": "Drink", + "controllable.action.block": "Block", + "controllable.action.pull_bow": "Pull Bow", + "controllable.action.place_block": "Place Block", + "controllable.action.use_item": "Use Item", + "controllable.action.interact": "Interact", + "controllable.action.inventory": "Inventory", + "controllable.action.close_inventory": "Close Inventory", + "controllable.action.swap_hands": "Swap Hands", + "controllable.action.dismount": "Dismount", + "controllable.action.jump": "Jump", + "controllable.action.sneak": "Sneak", + "controllable.action.drop_item": "Drop Item", + "controllable.action.pickup_stack": "Pickup Stack", + "controllable.action.pickup_item": "Pickup Item", + "controllable.action.quick_move": "Quick Move", + "controllable.action.place_stack": "Place Stack", + "controllable.action.place_item": "Place Item", + "controllable.gui.title.select_controller": "Select a Controller", + "controllable.gui.title.settings": "Settings", + "controllable.gui.title.binging": "Bindings", + "controllable.gui.title.button_binding": "Button Bindings", + "controllable.gui.title.layout": "Layout", + "controllable.gui.title.thumbstick_settings": "Thumbstick Settings", + "controllable.gui.settings": "Settings", + "controllable.gui.binding": "Bindings", + "controllable.gui.back": "Back", + "controllable.gui.save": "Save", + "controllable.gui.reset": "Reset", + "controllable.gui.layout": "Layout", + "controllable.gui.resetBinds": "Reset Binds", + "controllable.gui.layout.press_button": "Listening for button input. Press ESC to cancel", + "controllable.gui.layout.remap": "Click to change mapping...", + "controllable.gui.layout.button": "Button: %s", + "controllable.gui.layout.missing_mapping": "Missing Mapping!", + "controllable.gui.layout.mapped_to": "Mapped Index: %s", + "controllable.gui.layout.info": "Use this visual controller to test if your buttons and thumbsticks match your physical controller. If the wrong button is pressed, you can remap it by clicking the button on the visual controller. If an exclamation icon is shown over a button, it means it has no mapping to the physical controller.", + "controllable.gui.layout.warning": "Warning", + "controllable.gui.layout.invalid_layout": "One or more buttons are not assigned. Resolve any buttons that have an exclamation icon. If you continue, some buttons may not work!", + "controllable.gui.layout.thumbsticks": "Thumbstick Settings", + "controllable.options.forceFeedback": "Vibration", + "controllable.options.forceFeedback.desc": "If enabled, some actions will cause the controller to vibrate", + "controllable.options.autoSelect": "Auto Select", + "controllable.options.autoSelect.desc": "If enabled, controller will be automatically selected on start up or when plugged in", + "controllable.options.deadZone": "Dead Zone", + "controllable.options.deadZone.desc": "The distance you have to move the thumbstick before it's input is registered. This fixes drifting as some thumbsticks don't center to zero.", + "controllable.options.deadZone.format": "Dead Zone: %s", + "controllable.options.rotationSpeed": "Rotation Speed", + "controllable.options.rotationSpeed.desc": "The speed which the camera turns in game", + "controllable.options.rotationSpeed.format": "Rotation Speed: %s", + "controllable.options.mouseSpeed": "Mouse Speed", + "controllable.options.mouseSpeed.desc": "The speed which the cursor or virtual mouse moves around the screen", + "controllable.options.mouseSpeed.format": "Mouse Speed: %s", + "controllable.options.renderMiniPlayer": "Render Mini Player", + "controllable.options.renderMiniPlayer.desc": "If enabled, the player will render in the top left corner likes Bedrock Edition", + "controllable.options.virtualMouse": "Virtual Mouse", + "controllable.options.virtualMouse.desc": "If enabled, the game will use a virtual cursor instead of the real cursor. This must be turned on to be able to run multiple instances!", + "controllable.options.consoleHotbar": "Console Hotbar", + "controllable.options.consoleHotbar.desc": "If enabled, hotbar will render closer to the center of the screen like on console.", + "controllable.options.cursorType": "Cursor Type", + "controllable.options.cursorType.desc": "The image to use for the cursor. This only applies if virtual mouse is enabled!", + "controllable.options.cursorType.format": "Cursor Type: %s", + "controllable.options.controllerIcons": "Icons", + "controllable.options.controllerIcons.desc": "The controller icons to use in game to display actions", + "controllable.options.controllerIcons.format": "Icons: %s", + "controllable.options.invertLook": "Invert Look", + "controllable.options.invertLook.desc": "If enabled, inverts the controls on the Y axis for the camera", + "controllable.options.showActions": "Show Actions", + "controllable.options.showActions.desc": "If enabled, shows common actions when displaying available on the screen", + "controllable.options.showActions.format": "Show Actions: %s", + "controllable.options.switchThumbsticks": "Switch Thumbsticks", + "controllable.options.flipLeftThumbstickX": "Flip Left X-Axis", + "controllable.options.flipLeftThumbstickY": "Flip Left Y-Axis", + "controllable.options.flipRightThumbstickX": "Flip Right X-Axis", + "controllable.options.flipRightThumbstickY": "Flip Right Y-Axis", + "controllable.options.quickCraft": "Quick Craft", + "controllable.options.quickCraft.desc": "If enabled, allows you to craft quickly when clicking an item in the recipe book", + "controllable.controller.default": "Default", + "controllable.controller.playstation": "Playstation", + "controllable.controller.xbox": "Xbox", + "controllable.cursor.light": "Light", + "controllable.cursor.dark": "Dark", + "controllable.cursor.console": "Console", + "controllable.actionVisibility.all": "All", + "controllable.actionVisibility.minimal": "Minimal", + "controllable.actionVisibility.none": "None", + "controllable.toast.controller": "Controller", + "controllable.toast.connected": "Connected", + "controllable.toast.disconnected": "Disconnected", + "controllable.button.a": "A", + "controllable.button.b": "B", + "controllable.button.x": "X", + "controllable.button.y": "Y", + "controllable.button.select": "Select", + "controllable.button.home": "Home", + "controllable.button.start": "Start", + "controllable.button.left_thumb_stick": "Left Thumb Stick", + "controllable.button.right_thumb_stick": "Right Thumb Stick", + "controllable.button.left_bumper": "Left Bumper", + "controllable.button.right_bumper": "Right Bumper", + "controllable.button.left_trigger": "Left Trigger", + "controllable.button.right_trigger": "Right Trigger", + "controllable.button.dpad_up": "Up", + "controllable.button.dpad_down": "Down", + "controllable.button.dpad_left": "Left", + "controllable.button.dpad_right": "Right", + "controllable.key.nextHotbarItem": "Scroll Hotbar Right", + "controllable.key.previousHotbarItem": "Scroll Hotbar Left", + "controllable.key.pauseGame": "Pause Game", + "controllable.key.previousCreativeTab": "Previous Creative Tab / Recipe Page", + "controllable.key.nextCreativeTab": "Next Creative Tab / Recipe Page", + "controllable.key.previousRecipeTab": "Previous Recipe Tab", + "controllable.key.nextRecipeTab": "Next Recipe Tab", + "controllable.key.moveDown": "Navigate Down", + "controllable.key.moveLeft": "Navigate Left", + "controllable.key.moveRight": "Navigate Right", + "controllable.key.moveUp": "Navigate Up", + "controllable.key.debugInfo": "Show Debug Info", + "controllable.tooltip.craft": "Click to Craft Item" } \ No newline at end of file diff --git a/src/main/resources/assets/controllable/lang/es_es.json b/src/main/resources/assets/controllable/lang/es_es.json index fd722f0d..fa68b23b 100644 --- a/src/main/resources/assets/controllable/lang/es_es.json +++ b/src/main/resources/assets/controllable/lang/es_es.json @@ -38,4 +38,4 @@ "controllable.toast.controller": "Mando", "controllable.toast.connected": "Conectado", "controllable.toast.disconnected": "Desconectado" - } \ No newline at end of file +} \ No newline at end of file diff --git a/src/main/resources/assets/controllable/lang/fr_fr.json b/src/main/resources/assets/controllable/lang/fr_fr.json index 1c4e3c82..dc93dee4 100644 --- a/src/main/resources/assets/controllable/lang/fr_fr.json +++ b/src/main/resources/assets/controllable/lang/fr_fr.json @@ -1,30 +1,30 @@ { - "controllable.action.break": "Casser", - "controllable.action.attack": "Attaquer", - "controllable.action.eat": "Manger", - "controllable.action.drink": "Boire", - "controllable.action.block": "Bloquer", - "controllable.action.pull_bow": "Tendre l'arc", - "controllable.action.place_block": "Placer un bloc", - "controllable.action.use_item": "Utiliser un objet", - "controllable.action.interact": "Intéragir", - "controllable.action.inventory": "Inventaire", - "controllable.action.close_inventory": "Fermer l'inventaire", - "controllable.action.swap_hands": "Échanger les mains", - "controllable.action.dismount": "Descendre", - "controllable.action.jump": "Sauter", - "controllable.action.sneak": "S'accroupir", - "controllable.action.drop_item": "Jeter un objet", - "controllable.action.pickup_stack": "Prendre le stack", - "controllable.action.pickup_item": "Prendre l'objet", - "controllable.action.quick_move": "Déplacement rapide", - "controllable.action.place_stack": "Poser le stack", - "controllable.action.place_item": "Poser l'objet", - "controllable.gui.title.select_controller": "Choisir une manette", - "controllable.gui.select": "Choisir", - "controllable.gui.configure": "Configurer", - "controllable.gui.cancel": "Annuler", - "controllable.toast.controller": "Manette", - "controllable.toast.connected": "Connectée", - "controllable.toast.disconnected": "Deconnectée" + "controllable.action.break": "Casser", + "controllable.action.attack": "Attaquer", + "controllable.action.eat": "Manger", + "controllable.action.drink": "Boire", + "controllable.action.block": "Bloquer", + "controllable.action.pull_bow": "Tendre l'arc", + "controllable.action.place_block": "Placer un bloc", + "controllable.action.use_item": "Utiliser un objet", + "controllable.action.interact": "Intéragir", + "controllable.action.inventory": "Inventaire", + "controllable.action.close_inventory": "Fermer l'inventaire", + "controllable.action.swap_hands": "Échanger les mains", + "controllable.action.dismount": "Descendre", + "controllable.action.jump": "Sauter", + "controllable.action.sneak": "S'accroupir", + "controllable.action.drop_item": "Jeter un objet", + "controllable.action.pickup_stack": "Prendre le stack", + "controllable.action.pickup_item": "Prendre l'objet", + "controllable.action.quick_move": "Déplacement rapide", + "controllable.action.place_stack": "Poser le stack", + "controllable.action.place_item": "Poser l'objet", + "controllable.gui.title.select_controller": "Choisir une manette", + "controllable.gui.select": "Choisir", + "controllable.gui.configure": "Configurer", + "controllable.gui.cancel": "Annuler", + "controllable.toast.controller": "Manette", + "controllable.toast.connected": "Connectée", + "controllable.toast.disconnected": "Deconnectée" } \ No newline at end of file diff --git a/src/main/resources/assets/controllable/lang/it_it.json b/src/main/resources/assets/controllable/lang/it_it.json index a6c76a9d..d95d620d 100644 --- a/src/main/resources/assets/controllable/lang/it_it.json +++ b/src/main/resources/assets/controllable/lang/it_it.json @@ -1,30 +1,30 @@ { - "controllable.action.break": "Spacca", - "controllable.action.attack": "Attacca", - "controllable.action.eat": "Mangia", - "controllable.action.drink": "Bevi", - "controllable.action.block": "Blocca", - "controllable.action.pull_bow": "Tira l'Arco", - "controllable.action.place_block": "Piazza Blocco", - "controllable.action.use_item": "Usa Oggetto", - "controllable.action.interact": "Interagisci", - "controllable.action.inventory": "Inventario", - "controllable.action.close_inventory": "Chiudi l'Inventario", - "controllable.action.swap_hands": "Scambia Mani", - "controllable.action.dismount": "Scendi", - "controllable.action.jump": "Salta", - "controllable.action.sneak": "Vai in Furtiva", - "controllable.action.drop_item": "Fai Cadere Oggetto", - "controllable.action.pickup_stack": "Prendi tutta la Pila", - "controllable.action.pickup_item": "Prendi Oggetto", - "controllable.action.quick_move": "Spostamento Veloce", - "controllable.action.place_stack": "Lascia tutta la Pila", - "controllable.action.place_item": "Lascia Oggetto", - "controllable.gui.title.select_controller": "Scegli un Controller", - "controllable.gui.select": "Seleziona", - "controllable.gui.configure": "Configurea", - "controllable.gui.cancel": "Annulla", - "controllable.toast.controller": "Controller", - "controllable.toast.connected": "Connesso", - "controllable.toast.disconnected": "Disconnesso" + "controllable.action.break": "Spacca", + "controllable.action.attack": "Attacca", + "controllable.action.eat": "Mangia", + "controllable.action.drink": "Bevi", + "controllable.action.block": "Blocca", + "controllable.action.pull_bow": "Tira l'Arco", + "controllable.action.place_block": "Piazza Blocco", + "controllable.action.use_item": "Usa Oggetto", + "controllable.action.interact": "Interagisci", + "controllable.action.inventory": "Inventario", + "controllable.action.close_inventory": "Chiudi l'Inventario", + "controllable.action.swap_hands": "Scambia Mani", + "controllable.action.dismount": "Scendi", + "controllable.action.jump": "Salta", + "controllable.action.sneak": "Vai in Furtiva", + "controllable.action.drop_item": "Fai Cadere Oggetto", + "controllable.action.pickup_stack": "Prendi tutta la Pila", + "controllable.action.pickup_item": "Prendi Oggetto", + "controllable.action.quick_move": "Spostamento Veloce", + "controllable.action.place_stack": "Lascia tutta la Pila", + "controllable.action.place_item": "Lascia Oggetto", + "controllable.gui.title.select_controller": "Scegli un Controller", + "controllable.gui.select": "Seleziona", + "controllable.gui.configure": "Configurea", + "controllable.gui.cancel": "Annulla", + "controllable.toast.controller": "Controller", + "controllable.toast.connected": "Connesso", + "controllable.toast.disconnected": "Disconnesso" } \ No newline at end of file diff --git a/src/main/resources/assets/controllable/lang/pt_br.json b/src/main/resources/assets/controllable/lang/pt_br.json new file mode 100644 index 00000000..c0de6f9f --- /dev/null +++ b/src/main/resources/assets/controllable/lang/pt_br.json @@ -0,0 +1,108 @@ +{ + "controllable.action.break": "Quebrar", + "controllable.action.attack": "Ataque", + "controllable.action.eat": "Comer", + "controllable.action.drink": "Beber", + "controllable.action.block": "Bloquear", + "controllable.action.pull_bow": "Puxar Arco", + "controllable.action.place_block": "Colocar Bloco", + "controllable.action.use_item": "Usar Item", + "controllable.action.interact": "Interagir", + "controllable.action.inventory": "Inventário", + "controllable.action.close_inventory": "Fechar Inventário", + "controllable.action.swap_hands": "Trocar de Mãos", + "controllable.action.dismount": "Desmontar", + "controllable.action.jump": "Pular", + "controllable.action.sneak": "Agachar", + "controllable.action.drop_item": "Largar Item", + "controllable.action.pickup_stack": "Pegar Monte", + "controllable.action.pickup_item": "Pegar Item", + "controllable.action.quick_move": "Movimento Rápido", + "controllable.action.place_stack": "Colocar Monte", + "controllable.action.place_item": "Colocar Item", + "controllable.gui.title.select_controller": "Selecione um Controle", + "controllable.gui.title.settings": "Configurações", + "controllable.gui.title.binging": "Ligações", + "controllable.gui.title.button_binding": "Ligação dos Botões", + "controllable.gui.title.layout": "Modelo", + "controllable.gui.title.thumbstick_settings": "Configurações do Analógico", + "controllable.gui.settings": "Configurações", + "controllable.gui.binding": "Ligações", + "controllable.gui.back": "Voltar", + "controllable.gui.save": "Salvar", + "controllable.gui.reset": "Redefinir", + "controllable.gui.layout": "Modelo", + "controllable.gui.resetBinds": "Redefinir Binds", + "controllable.gui.layout.press_button": "Esperando a entrada do botão. Pressione ESC para cancelar", + "controllable.gui.layout.remap": "Clique para alterar o mapeamento...", + "controllable.gui.layout.button": "Botão: %s", + "controllable.gui.layout.missing_mapping": "Mapeamento ausente!", + "controllable.gui.layout.mapped_to": "Índice Mapeado: %s", + "controllable.gui.layout.info": "Use este controle virtual para testar se seus botões e analógicos correspondem ao seu controle. Se o botão errado for pressionado, você pode remapear clicando no botão do controle virtual. Se um ícone de exclamação for mostrado sobre um botão, significa que não há mapeamento para o seu controle.", + "controllable.gui.layout.warning": "Alerta", + "controllable.gui.layout.invalid_layout": "Um ou mais botões não foram atribuídos. Resolva quaisquer botões que tenham um ícone de exclamação. Se você continuar, alguns botões podem não funcionar!", + "controllable.gui.layout.thumbsticks": "Configurações dos Analógicos", + "controllable.options.forceFeedback": "Vibração", + "controllable.options.autoSelect": "Auto Selecionar", + "controllable.options.deadZone": "Zona Morta", + "controllable.options.deadZone.format": "Zona Morta: %s", + "controllable.options.rotationSpeed": "Velocidade de Rotação", + "controllable.options.rotationSpeed.format": "Velocidade de Rotação: %s", + "controllable.options.mouseSpeed": "Velocidade do Mouse", + "controllable.options.mouseSpeed.format": "Velocidade do Mouse: %s", + "controllable.options.renderMiniPlayer": "Render Mini Player", + "controllable.options.virtualMouse": "Mouse Virtual", + "controllable.options.consoleHotbar": "Console barra rápida", + "controllable.options.cursorType": "Tipo de Cursor", + "controllable.options.cursorType.format": "Tipo de Cursor: %s", + "controllable.options.controllerIcons": "Icones", + "controllable.options.controllerIcons.format": "Icones: %s", + "controllable.options.invertLook": "Inverter Visão", + "controllable.options.showActions": "Mostrar Ações", + "controllable.options.showActions.format": "Mostrar Ações: %s", + "controllable.options.switchThumbsticks": "Trocar Analógico", + "controllable.options.flipLeftThumbstickX": "Inverter Eixo X Esquerdo", + "controllable.options.flipLeftThumbstickY": "Inverter Eixo Y Esquerdo", + "controllable.options.flipRightThumbstickX": "Inverter Eixo X Direito", + "controllable.options.flipRightThumbstickY": "Inverter Eixo Y Direito", + "controllable.controller.default": "Padrão", + "controllable.controller.playstation": "Playstation", + "controllable.controller.xbox": "Xbox", + "controllable.cursor.light": "Claro", + "controllable.cursor.dark": "Escuro", + "controllable.cursor.console": "Console", + "controllable.actionVisibility.all": "Todos", + "controllable.actionVisibility.minimal": "Mínimo", + "controllable.actionVisibility.none": "Nenhum", + "controllable.toast.controller": "Controle", + "controllable.toast.connected": "Conectado", + "controllable.toast.disconnected": "Disconectado", + "controllable.button.a": "A", + "controllable.button.b": "B", + "controllable.button.x": "X", + "controllable.button.y": "Y", + "controllable.button.select": "Select", + "controllable.button.home": "Início", + "controllable.button.start": "Start", + "controllable.button.left_thumb_stick": "Analógico Esquerdo", + "controllable.button.right_thumb_stick": "Analógico Direito", + "controllable.button.left_bumper": "Botão Esquerdo", + "controllable.button.right_bumper": "Botão Direito", + "controllable.button.left_trigger": "Gatilho Esquerdo", + "controllable.button.right_trigger": "Gatilho Direito", + "controllable.button.dpad_up": "Cima", + "controllable.button.dpad_down": "Baixo", + "controllable.button.dpad_left": "Esquerda", + "controllable.button.dpad_right": "Direita", + "controllable.key.nextHotbarItem": "Avançar barra rápida para Direita", + "controllable.key.previousHotbarItem": "Voltar barra rápida para Esquerda", + "controllable.key.pauseGame": "Pausar Jogo", + "controllable.key.previousCreativeTab": "Voltar Guia Criativo / Página de Receita", + "controllable.key.nextCreativeTab": "Avançar Guia Criativo / Página de Receita", + "controllable.key.previousRecipeTab": "Voltar Aba de receita", + "controllable.key.nextRecipeTab": "Avançar aba de receita", + "controllable.key.moveDown": "Navegar para Baixo", + "controllable.key.moveLeft": "Navegar para Esquerda", + "controllable.key.moveRight": "Navegar para Direita", + "controllable.key.moveUp": "Navegar para Cima" +} diff --git a/src/main/resources/assets/controllable/lang/pt_br.lang b/src/main/resources/assets/controllable/lang/pt_br.lang deleted file mode 100644 index b12ef654..00000000 --- a/src/main/resources/assets/controllable/lang/pt_br.lang +++ /dev/null @@ -1,51 +0,0 @@ -{ -"controllable.action.break": "Quebrar", -"controllable.action.attack": "Ataque", -"controllable.action.eat": "Comer", -"controllable.action.drink": "Beber", -"controllable.action.block": "Bloquear", -"controllable.action.pull_bow": "Usar Arco", -"controllable.action.place_block": "Colocar Bloco", -"controllable.action.use_item": "Usar Item", -"controllable.action.interact": "Interagir", -"controllable.action.inventory": "Inventário", -"controllable.action.close_inventory": "Fechar Inventário", -"controllable.action.swap_hands": "Trocar de mão", -"controllable.action.dismount": "Desmontar", -"controllable.action.jump": "Pular", -"controllable.action.sneak": "Agachar-se", -"controllable.action.drop_item": "Soltar Item", -"controllable.action.pickup_stack": "Pegar Stack", -"controllable.action.pickup_item": "Pegar Item", -"controllable.action.quick_move": "Movimento Rápido", -"controllable.action.place_stack": "Colocar Stack", -"controllable.action.place_item": "Colocar Item", -"controllable.gui.title.select_controller": "Selecione um Controle", -"controllable.gui.title.settings": "Configurações", -"controllable.gui.title.layout": "Remapear Botões", -"controllable.gui.settings": "Configurações", -"controllable.gui.remap": "Remapear Botões", -"controllable.gui.back": "Voltar", -"controllable.options.forceFeedback": "Vibração", -"controllable.options.autoSelect": "Seleção automática", -"controllable.options.deadZone": "Zona Morta", -"controllable.options.deadZone.format": "Zona Morta: %s", -"controllable.options.rotationSpeed": "Velocidade de rotação", -"controllable.options.rotationSpeed.format": "Velocidade de rotação: %s", -"controllable.options.mouseSpeed": "Velocidade do Mouse", -"controllable.options.mouseSpeed.format": "Velocidade do Mouse: %s", -"controllable.options.renderMiniPlayer": "Renderizar Mini Jogador", -"controllable.options.virtualMouse": "Mouse Virtual", -"controllable.options.consoleHotbar": "Console Hotbar", -"controllable.options.cursorType": "Tipo de Cursor", -"controllable.options.controllerType": "Icones", -"controllable.controller.default": "Padrão", -"controllable.controller.playstation": "Playstation", -"controllable.controller.xbox": "Xbox", -"controllable.cursor.light": "Claro", -"controllable.cursor.dark": "Escuro", -"controllable.cursor.console": "Console", -"controllable.toast.controller": "Controle", -"controllable.toast.connected": "Conectado", -"controllable.toast.disconnected": "Desconectado" -} diff --git a/src/main/resources/assets/controllable/lang/ru_ru.json b/src/main/resources/assets/controllable/lang/ru_ru.json index 120b6a07..7384897c 100644 --- a/src/main/resources/assets/controllable/lang/ru_ru.json +++ b/src/main/resources/assets/controllable/lang/ru_ru.json @@ -1,38 +1,38 @@ { - "controllable.action.break": "Сломать", - "controllable.action.attack": "Атаковать", - "controllable.action.eat": "Съесть", - "controllable.action.drink": "Выпить", - "controllable.action.block": "Заблокировать", - "controllable.action.pull_bow": "Натянуть тетиву", - "controllable.action.place_block": "Поставить Блок", - "controllable.action.use_item": "Использовать Предмет", - "controllable.action.interact": "Взаимодействовать", - "controllable.action.inventory": "Инвентарь", - "controllable.action.close_inventory": "Закрыть Инвентарь", - "controllable.action.swap_hands": "Сменить Руку", - "controllable.action.dismount": "Спешиться", - "controllable.action.jump": "Прыжок", - "controllable.action.sneak": "Пригнуться", - "controllable.action.drop_item": "Бросить Предмет", - "controllable.action.pickup_stack": "Взять Стак", - "controllable.action.pickup_item": "Взять Предмет", - "controllable.action.quick_move": "Быстрое Перемещение", - "controllable.action.place_stack": "Поставить Стак", - "controllable.action.place_item": "Поставить Предмет", - "controllable.gui.title.select_controller": "Выбрать Контроллер", - "controllable.gui.title.settings": "Настройки", - "controllable.gui.title.layout": "Переназначить Кнопки", - "controllable.gui.settings": "Настройки", - "controllable.gui.remap": "Переназначить Кнопки", - "controllable.gui.back": "Назад", - "controllable.options.deadZone": "Мёртвая Зона", - "controllable.options.deadZone.format": "Мёртвая Зона: %s", - "controllable.options.rotationSpeed": "Скорость Вращения", - "controllable.options.rotationSpeed.format": "Скорость Вращения: %s", - "controllable.options.mouseSpeed": "Скорость Мыши", - "controllable.options.mouseSpeed.format": "Скорость Мыши: %s", - "controllable.toast.controller": "Контроллер", - "controllable.toast.connected": "Подключён", - "controllable.toast.disconnected": "Отключён" + "controllable.action.break": "Сломать", + "controllable.action.attack": "Атаковать", + "controllable.action.eat": "Съесть", + "controllable.action.drink": "Выпить", + "controllable.action.block": "Заблокировать", + "controllable.action.pull_bow": "Натянуть тетиву", + "controllable.action.place_block": "Поставить Блок", + "controllable.action.use_item": "Использовать Предмет", + "controllable.action.interact": "Взаимодействовать", + "controllable.action.inventory": "Инвентарь", + "controllable.action.close_inventory": "Закрыть Инвентарь", + "controllable.action.swap_hands": "Сменить Руку", + "controllable.action.dismount": "Спешиться", + "controllable.action.jump": "Прыжок", + "controllable.action.sneak": "Пригнуться", + "controllable.action.drop_item": "Бросить Предмет", + "controllable.action.pickup_stack": "Взять Стак", + "controllable.action.pickup_item": "Взять Предмет", + "controllable.action.quick_move": "Быстрое Перемещение", + "controllable.action.place_stack": "Поставить Стак", + "controllable.action.place_item": "Поставить Предмет", + "controllable.gui.title.select_controller": "Выбрать Контроллер", + "controllable.gui.title.settings": "Настройки", + "controllable.gui.title.layout": "Переназначить Кнопки", + "controllable.gui.settings": "Настройки", + "controllable.gui.remap": "Переназначить Кнопки", + "controllable.gui.back": "Назад", + "controllable.options.deadZone": "Мёртвая Зона", + "controllable.options.deadZone.format": "Мёртвая Зона: %s", + "controllable.options.rotationSpeed": "Скорость Вращения", + "controllable.options.rotationSpeed.format": "Скорость Вращения: %s", + "controllable.options.mouseSpeed": "Скорость Мыши", + "controllable.options.mouseSpeed.format": "Скорость Мыши: %s", + "controllable.toast.controller": "Контроллер", + "controllable.toast.connected": "Подключён", + "controllable.toast.disconnected": "Отключён" } diff --git a/src/main/resources/assets/controllable/lang/zh_tw.json b/src/main/resources/assets/controllable/lang/zh_tw.json index 2c72bbbf..8610f450 100644 --- a/src/main/resources/assets/controllable/lang/zh_tw.json +++ b/src/main/resources/assets/controllable/lang/zh_tw.json @@ -1,30 +1,108 @@ { - "controllable.action.break": "破壞", - "controllable.action.attack": "攻擊", - "controllable.action.eat": "進食", - "controllable.action.drink": "飲用", - "controllable.action.block": "阻擋", - "controllable.action.pull_bow": "拉弓", - "controllable.action.place_block": "放置方塊", - "controllable.action.use_item": "使用物品", - "controllable.action.interact": "互動", - "controllable.action.inventory": "物品欄", - "controllable.action.close_inventory": "關閉物品欄", - "controllable.action.swap_hands": "交換手", - "controllable.action.dismount": "離開騎乘", - "controllable.action.jump": "跳躍", - "controllable.action.sneak": "潛行", - "controllable.action.drop_item": "扔掉物品", - "controllable.action.pickup_stack": "拾起一組物品", - "controllable.action.pickup_item": "拾起物品", - "controllable.action.quick_move": "快速移動", - "controllable.action.place_stack": "放置一組物品", - "controllable.action.place_item": "放置物品", - "controllable.gui.title.select_controller": "選擇一個控制器", - "controllable.gui.select": "選擇", - "controllable.gui.configure": "配置", - "controllable.gui.cancel": "取消", - "controllable.toast.controller": "控制器", - "controllable.toast.connected": "已連接", - "controllable.toast.disconnected": "沒有連接" + "controllable.action.break": "破壞", + "controllable.action.attack": "攻擊", + "controllable.action.eat": "進食", + "controllable.action.drink": "飲用", + "controllable.action.block": "阻擋", + "controllable.action.pull_bow": "拉弓", + "controllable.action.place_block": "放置方塊", + "controllable.action.use_item": "使用物品", + "controllable.action.interact": "互動", + "controllable.action.inventory": "物品欄", + "controllable.action.close_inventory": "關閉物品欄", + "controllable.action.swap_hands": "交換手", + "controllable.action.dismount": "離開騎乘", + "controllable.action.jump": "跳躍", + "controllable.action.sneak": "潛行", + "controllable.action.drop_item": "扔掉物品", + "controllable.action.pickup_stack": "拾起一組物品", + "controllable.action.pickup_item": "拾起物品", + "controllable.action.quick_move": "快速移動", + "controllable.action.place_stack": "放置一組物品", + "controllable.action.place_item": "放置物品", + "controllable.gui.title.select_controller": "選擇一個控制器", + "controllable.gui.title.settings": "設置", + "controllable.gui.title.binging": "綁定", + "controllable.gui.title.button_binding": "按鈕綁定", + "controllable.gui.title.layout": "佈局", + "controllable.gui.title.thumbstick_settings": "搖桿設置", + "controllable.gui.settings": "設置", + "controllable.gui.binding": "綁定", + "controllable.gui.back": "返回", + "controllable.gui.save": "儲存", + "controllable.gui.reset": "重置", + "controllable.gui.layout": "佈局", + "controllable.gui.resetBinds": "重置綁定", + "controllable.gui.layout.press_button": "監聽按鈕輸入中。按ESC以取消", + "controllable.gui.layout.remap": "點擊以更改映射…", + "controllable.gui.layout.button": "按鈕:%s", + "controllable.gui.layout.missing_mapping": "缺少映射!", + "controllable.gui.layout.mapped_to": "映射:%s", + "controllable.gui.layout.info": "使用此虛擬控制器以測試按鈕和搖桿是否與實際控制器匹配。如果按下了錯誤的按鈕,則可以通過點擊虛擬控制器上的按鈕來重新映射它。如果在按鈕上方顯示感嘆號圖示,則表示它沒有映射到實際控制器。", + "controllable.gui.layout.warning": "警告", + "controllable.gui.layout.invalid_layout": "未分配一個或多個按鈕。解決所有帶有感嘆號圖示的按鈕。如果繼續,某些按鈕可能不起作用!", + "controllable.gui.layout.thumbsticks": "搖桿設置", + "controllable.options.forceFeedback": "振動", + "controllable.options.autoSelect": "自動選擇", + "controllable.options.deadZone": "盲區", + "controllable.options.deadZone.format": "盲區:%s", + "controllable.options.rotationSpeed": "旋轉速度", + "controllable.options.rotationSpeed.format": "旋轉速度:%s", + "controllable.options.mouseSpeed": "滑鼠速度", + "controllable.options.mouseSpeed.format": "滑鼠速度:%s", + "controllable.options.renderMiniPlayer": "顯示迷你玩家", + "controllable.options.virtualMouse": "虛擬滑鼠", + "controllable.options.consoleHotbar": "控制台快捷欄", + "controllable.options.cursorType": "游標類型", + "controllable.options.cursorType.format": "游標類型:%s", + "controllable.options.controllerIcons": "圖示", + "controllable.options.controllerIcons.format": "圖示:%s", + "controllable.options.invertLook": "反轉", + "controllable.options.showActions": "顯示動作", + "controllable.options.showActions.format": "顯示動作:%s", + "controllable.options.switchThumbsticks": "切換搖桿", + "controllable.options.flipLeftThumbstickX": "翻轉左邊X軸", + "controllable.options.flipLeftThumbstickY": "翻轉左邊Y軸", + "controllable.options.flipRightThumbstickX": "翻轉右邊X軸", + "controllable.options.flipRightThumbstickY": "翻轉右邊Y軸", + "controllable.controller.default": "默認", + "controllable.controller.playstation": "Playstation", + "controllable.controller.xbox": "Xbox", + "controllable.cursor.light": "淺", + "controllable.cursor.dark": "深", + "controllable.cursor.console": "控制台", + "controllable.actionVisibility.all": "完整", + "controllable.actionVisibility.minimal": "簡化", + "controllable.actionVisibility.none": "沒有", + "controllable.toast.controller": "控制器", + "controllable.toast.connected": "已連接", + "controllable.toast.disconnected": "沒有連接", + "controllable.button.a": "A", + "controllable.button.b": "B", + "controllable.button.x": "X", + "controllable.button.y": "Y", + "controllable.button.select": "Select", + "controllable.button.home": "Home", + "controllable.button.start": "Start", + "controllable.button.left_thumb_stick": "左搖桿", + "controllable.button.right_thumb_stick": "右搖桿", + "controllable.button.left_bumper": "左緩衝鍵", + "controllable.button.right_bumper": "右緩衝鍵", + "controllable.button.left_trigger": "左發射鍵", + "controllable.button.right_trigger": "右發射鍵", + "controllable.button.dpad_up": "十字鍵上", + "controllable.button.dpad_down": "十字鍵下", + "controllable.button.dpad_left": "十字鍵左", + "controllable.button.dpad_right": "十字鍵右", + "controllable.key.nextHotbarItem": "向右滾動快捷欄", + "controllable.key.previousHotbarItem": "向左滾動快捷欄", + "controllable.key.pauseGame": "暫停遊戲", + "controllable.key.previousCreativeTab": "上一個創造模式分類/配方頁面", + "controllable.key.nextCreativeTab": "下一個創造模式分類/配方頁面", + "controllable.key.previousRecipeTab": "上一個配方分類", + "controllable.key.nextRecipeTab": "下一個配方分類", + "controllable.key.moveDown": "向下瀏覽", + "controllable.key.moveLeft": "向左瀏覽", + "controllable.key.moveRight": "向右瀏覽", + "controllable.key.moveUp": "向上瀏覽" } \ No newline at end of file diff --git a/src/main/resources/assets/controllable/textures/gui/buttons.png b/src/main/resources/assets/controllable/textures/gui/buttons.png index 27190bf3..5d63499e 100644 Binary files a/src/main/resources/assets/controllable/textures/gui/buttons.png and b/src/main/resources/assets/controllable/textures/gui/buttons.png differ diff --git a/src/main/resources/assets/controllable/textures/gui/controller.png b/src/main/resources/assets/controllable/textures/gui/controller.png index 84192c8f..64628be4 100644 Binary files a/src/main/resources/assets/controllable/textures/gui/controller.png and b/src/main/resources/assets/controllable/textures/gui/controller.png differ diff --git a/src/main/resources/controllable.mixins.json b/src/main/resources/controllable.mixins.json new file mode 100644 index 00000000..99517e2f --- /dev/null +++ b/src/main/resources/controllable.mixins.json @@ -0,0 +1,30 @@ +{ + "required": true, + "package": "com.mrcrayfish.controllable.mixin", + "plugin": "com.mrcrayfish.controllable.mixin.ControllableMixinPlugin", + "compatibilityLevel": "JAVA_8", + "minVersion": "0.8", + "refmap": "controllable.refmap.json", + "client": [ + "client.ClientPlayerEntityMixin", + "client.ContainerScreenMixin", + "client.CreativeScreenMixin", + "client.ForgeIngameGuiMixin", + "client.GameRendererMixin", + "client.OptifineGameRendererMixin", + "client.IngameGuiMixin", + "client.MinecraftMixin", + "client.MouseHelperMixin", + "client.RecipeBookGuiMixin", + "client.RecipeBookPageAccessor", + "client.RecipeBookPageMixin", + "client.jei.MouseUtilMixin", + "client.jei.IngredientListOverlayMixin", + "client.jei.IngredientGridWithNavigationMixin", + "client.jei.IngredientGridMixin", + "client.jei.PageNavigationMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/src/main/resources/controllable.png b/src/main/resources/controllable.png new file mode 100644 index 00000000..b0d8beb2 Binary files /dev/null and b/src/main/resources/controllable.png differ diff --git a/src/main/resources/coremods/controllable-transformer.js b/src/main/resources/coremods/controllable-transformer.js deleted file mode 100644 index cafbc297..00000000 --- a/src/main/resources/coremods/controllable-transformer.js +++ /dev/null @@ -1,387 +0,0 @@ -function initializeCoreMod() { - return { - 'minecraft': { - 'target': { - 'type': 'CLASS', - 'name': 'net.minecraft.client.Minecraft' - }, - 'transformer': function(classNode) { - log("Patching Minecraft..."); - - patch({ - obfName: "func_147115_a", - name: "sendClickBlockToController", - desc: "(Z)V", - patch: patch_Minecraft_sendClickBlockToController - }, classNode); - - patch({ - obfName: "func_184117_aA", - name: "processKeyBinds", - desc: "()V", - patch: patch_Minecraft_processKeyBinds - }, classNode); - - return classNode; - } - }, - 'container_screen': { - 'target': { - 'type': 'CLASS', - 'name': 'net.minecraft.client.gui.screen.inventory.ContainerScreen' - }, - 'transformer': function(classNode) { - log("Patching ContainerScreen..."); - - patch({ - obfName: "func_73864_a", - name: "mouseClicked", - desc: "(DDI)Z", - patch: patch_ContainerScreen_mouseClicked - }, classNode); - - patch({ - obfName: "func_146286_b", - name: "mouseReleased", - desc: "(DDI)Z", - patch: patch_ContainerScreen_mouseReleased - }, classNode); - - return classNode; - } - }, - 'forge_ingame_gui': { - 'target': { - 'type': 'CLASS', - 'name': 'net.minecraftforge.client.ForgeIngameGui' - }, - 'transformer': function(classNode) { - log("Patching ForgeIngameGui..."); - - patch({ - obfName: "", - name: "renderPlayerList", - desc: "(II)V", - patch: patch_ForgeIngameGui_renderPlayerList - }, classNode); - - patch({ - obfName: "", - name: "renderRecordOverlay", - desc: "(IIF)V", - patch: patch_IngameGui_renderSelectedItem - }, classNode); - - return classNode; - } - //updateCameraAndRender(FJ)V - }, - 'screen_render_patch': { - 'target': { - 'type': 'CLASS', - 'name': 'net.minecraft.client.renderer.GameRenderer' - }, - 'transformer': function(classNode) { - log("Patching GameRenderer..."); - - patch({ - obfName: "func_195458_a", - name: "updateCameraAndRender", - desc: "(FJZ)V", - patch: patch_GameRenderer_updateCameraAndRender - }, classNode); - - return classNode; - } - }, - 'selected_item_name': { - 'target': { - 'type': 'CLASS', - 'name': 'net.minecraft.client.gui.IngameGui' - }, - 'transformer': function(classNode) { - log("Patching IngameGui..."); - patch({ - obfName: "func_194801_c ", - name: "renderSelectedItem", - desc: "()V", - patch: patch_IngameGui_renderSelectedItem - }, classNode); - return classNode; - } - } - }; -} - -function findMethod(methods, entry) { - var length = methods.length; - for(var i = 0; i < length; i++) { - var method = methods[i]; - if((method.name.equals(entry.obfName) || method.name.equals(entry.name)) && method.desc.equals(entry.desc)) { - return method; - } - } - return null; -} - -function patch(entry, classNode) { - var method = findMethod(classNode.methods, entry); - var name = classNode.name.replace("/", ".") + "#" + entry.name + entry.desc; - if(method !== null) { - log("Starting to patch: " + name); - if(entry.patch(method)) { - log("Successfully patched: " + name); - } else { - log("Failed to patch: " + name); - } - } else { - log("Failed to find method: " + name); - } -} - -var ASMAPI = Java.type('net.minecraftforge.coremod.api.ASMAPI'); -var Opcodes = Java.type('org.objectweb.asm.Opcodes'); -var MethodInsnNode = Java.type('org.objectweb.asm.tree.MethodInsnNode'); -var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode'); -var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode'); -var LabelNode = Java.type('org.objectweb.asm.tree.LabelNode'); -var FieldInsnNode = Java.type('org.objectweb.asm.tree.FieldInsnNode'); -var TypeInsnNode = Java.type('org.objectweb.asm.tree.TypeInsnNode'); -var JumpInsnNode = Java.type('org.objectweb.asm.tree.JumpInsnNode'); -var FrameNode = Java.type('org.objectweb.asm.tree.FrameNode'); - -function patch_Minecraft_sendClickBlockToController(method) { - method.instructions.insert(new VarInsnNode(Opcodes.ISTORE, 1)); - method.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, "com/mrcrayfish/controllable/client/Hooks", "isLeftClicking", "()Z", false)); - return true; -} - -function patch_Minecraft_processKeyBinds(method) { - var findInstruction = { - obfName: "func_151470_d", - name: "isKeyDown", - desc: "()Z", - matches: function(s) { - return s.equals(this.obfName) || s.equals(this.name); - } - }; - - var foundNode = null; - var instructions = method.instructions.toArray(); - var length = instructions.length; - for (var i = 0; i < length; i++) { - var node = instructions[i]; - if(node.getOpcode() == Opcodes.INVOKEVIRTUAL && node.getNext().getOpcode() == Opcodes.IFNE) { - if(node instanceof MethodInsnNode && findInstruction.matches(node.name) && findInstruction.desc.equals(node.desc)) { - if(node.getPrevious().getOpcode() == Opcodes.GETFIELD && node.getPrevious().getPrevious().getOpcode() == Opcodes.GETFIELD && node.getPrevious().getPrevious().getPrevious().getOpcode() == Opcodes.ALOAD) { - foundNode = node; - break; - } - } - } - } - - if(foundNode !== null) { - var nextNode = foundNode.getNext(); - if(!removeNthNodes(method.instructions, foundNode, -3)) - return false; - method.instructions.remove(foundNode); - method.instructions.insertBefore(nextNode, new MethodInsnNode(Opcodes.INVOKESTATIC, "com/mrcrayfish/controllable/client/Hooks", "isRightClicking", "()Z", false)); - return true; - } - return false; -} - -function patch_ContainerScreen_mouseClicked(method) { - return patchQuickMove(method); -} - -function patch_ContainerScreen_mouseReleased(method) { - return patchQuickMove(method); -} - -function patchQuickMove(method) { - var findInstruction = { - obfName: "func_216506_a", - name: "isKeyDown", - desc: "(JI)Z", - matches: function(s) { - return s.equals(this.obfName) || s.equals(this.name); - } - }; - - var foundNode = null; - var instructions = method.instructions.toArray(); - var length = instructions.length; - for (var i = 0; i < length; i++) { - var node = instructions[i]; - if(node.getOpcode() != Opcodes.INVOKESTATIC) - continue; - if(node.getNext() === null || node.getNext().getOpcode() != Opcodes.IFNE) - continue; - if(node.getPrevious() === null || node.getPrevious().getOpcode() != Opcodes.SIPUSH) - continue; - if(!findInstruction.matches(node.name)) - continue; - if(!findInstruction.desc.equals(node.desc)) - continue; - var temp = getNthRelativeNode(node, 6); - if(temp === null) - continue; - if(temp.getOpcode() != Opcodes.INVOKESTATIC && temp.getNext().getOpcode() != Opcodes.IFEQ && temp.getPrevious().getOpcode() != Opcodes.SIPUSH) - continue; - if(!findInstruction.matches(temp.name)) - continue; - if(!findInstruction.desc.equals(temp.desc)) - continue; - foundNode = node.getPrevious(); - break; - } - - if(foundNode !== null) - { - var previousNode = getNthRelativeNode(foundNode, -4); - if(!removeNthNodes(method.instructions, foundNode, 7)) - return false; - if(!removeNthNodes(method.instructions, foundNode, -3)) - return false; - method.instructions.remove(foundNode); - method.instructions.insert(previousNode, new MethodInsnNode(Opcodes.INVOKESTATIC, "com/mrcrayfish/controllable/client/Hooks", "canQuickMove", "()Z", false)); - return true; - } - return false; -} - -function patch_ForgeIngameGui_renderPlayerList(method) { - var findInstruction = { - obfName: "func_151470_d", - name: "isKeyDown", - desc: "()Z", - matches: function(s) { - return s.equals(this.obfName) || s.equals(this.name); - } - }; - - var foundNode = null; - var instructions = method.instructions.toArray(); - var length = instructions.length; - for (var i = 0; i < length; i++) { - var node = instructions[i]; - if(node.getOpcode() != Opcodes.INVOKEVIRTUAL) - continue; - if(!findInstruction.matches(node.name)) - continue; - if(getNthRelativeNode(node, -1) === null || getNthRelativeNode(node, -1).getOpcode() != Opcodes.GETFIELD) - continue; - if(getNthRelativeNode(node, -2) === null || getNthRelativeNode(node, -2).getOpcode() != Opcodes.GETFIELD) - continue; - if(getNthRelativeNode(node, -3) === null || getNthRelativeNode(node, -3).getOpcode() != Opcodes.GETFIELD) - continue; - if(getNthRelativeNode(node, -4) === null || getNthRelativeNode(node, -4).getOpcode() != Opcodes.ALOAD) - continue; - foundNode = node; - break; - } - - if(foundNode !== null) - { - if(!removeNthNodes(method.instructions, foundNode, -3)) - return false; - method.instructions.insert(foundNode, new MethodInsnNode(Opcodes.INVOKESTATIC, "com/mrcrayfish/controllable/client/Hooks", "canShowPlayerList", "()Z", false)); - method.instructions.remove(foundNode); - return true; - } - return false; -} - -function patch_GameRenderer_updateCameraAndRender(method) { - var findInstruction = { - name: "drawScreen", - desc: "(Lnet/minecraft/client/gui/screen/Screen;IIF)V", - matches: function(s) { - return s.equals(this.name); - } - }; - - var foundNode = null; - var instructions = method.instructions.toArray(); - var length = instructions.length; - for (var i = 0; i < length; i++) { - var node = instructions[i]; - if(node.getOpcode() != Opcodes.INVOKESTATIC) - continue; - if(findInstruction.name.equals(node.name) && findInstruction.desc.equals(node.desc)) { - foundNode = node; - break; - } - } - - if(foundNode !== null) { - var previousNode = foundNode.getPrevious(); - method.instructions.remove(foundNode); - method.instructions.insert(previousNode, new MethodInsnNode(Opcodes.INVOKESTATIC, "com/mrcrayfish/controllable/client/Hooks", "drawScreen", "(Lnet/minecraft/client/gui/screen/Screen;IIF)V", false)); - return true; - } - return false; -} - -function patch_IngameGui_renderSelectedItem(method) { - var findInstruction = { - name: "pushMatrix", - desc: "()V", - matches: function(s) { - return s.equals(this.name); - } - }; - - var foundNode = null; - var instructions = method.instructions.toArray(); - var length = instructions.length; - for (var i = 0; i < length; i++) { - var node = instructions[i]; - if(node.getOpcode() != Opcodes.INVOKESTATIC) - continue; - if(findInstruction.name.equals(node.name) && findInstruction.desc.equals(node.desc)) { - foundNode = node; - break; - } - } - - if(foundNode !== null) { - method.instructions.insert(foundNode, new MethodInsnNode(Opcodes.INVOKESTATIC, "com/mrcrayfish/controllable/client/Hooks", "applyHotbarOffset", "()V", false)); - return true; - } - return false; -} - -function removeNthNodes(instructions, node, n) { - while(n > 0) { - if(node.getNext() === null) - return false; - instructions.remove(node.getNext()); - n--; - } - while(n < 0) { - if(node.getPrevious() === null) - return false; - instructions.remove(node.getPrevious()); - n++; - } - return true; -} - -function getNthRelativeNode(node, n) { - while(n > 0 && node !== null) { - node = node.getNext(); - n--; - } - while(n < 0 && node !== null) { - node = node.getPrevious(); - n++; - } - return node; -} - -function log(s) { - print("[controllable-transformer.js] " + s); -} diff --git a/src/main/resources/gamecontrollerdb.txt b/src/main/resources/gamecontrollerdb.txt new file mode 100644 index 00000000..728fddc2 --- /dev/null +++ b/src/main/resources/gamecontrollerdb.txt @@ -0,0 +1,943 @@ +# Game Controller DB for SDL in 2.0.9 format +# Source: https://github.com/gabomdq/SDL_GameControllerDB + +# Windows +03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows, +03000000c82d00002038000000000000,8bitdo,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d000011ab000000000000,8BitDo F30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00005106000000000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00015900000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00065280000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000022000000090000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000203800000900000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000060000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000061000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000102800000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00003028000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000351000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00006228000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000260000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000261000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000031000000000000,8BitDo Wireless Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, +030000008f0e00001200000000000000,Acme GA-02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000fa190000f0ff000000000000,Acteck AGJ-3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000006f0e00001413000000000000,Afterglow,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000263000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001101000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001401000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001402000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001901000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001a01000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d62000001d57000000000000,Airflo PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000869800002400000000007801,Astro C40 TR,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000d6200000e557000000000000,Batarang,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows, +030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d62000002a79000000000000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000bc2000000055000000000000,Betop BFM Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000bc2000006312000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000bc2000006321000000000000,BETOP CONTROLLER,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000bc2000006412000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000c01100000555000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000c01100000655000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000790000000700000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000808300000300000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, +0300000066f700000500000000000000,BrutalLegendTest,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000d81d00000b00000000000000,BUFFALO BSGP1601 Series ,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows, +03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000457500000401000000000000,Cobra,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000005e0400008e02000000000000,Controller (XBOX 360 For Windows),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000a102000000000000,Controller (Xbox 360 Wireless Receiver for Windows),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000ff02000000000000,Controller (Xbox One For Windows) - Wired,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000ea02000000000000,Controller (Xbox One For Windows) - Wireless,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows, +03000000a306000022f6000000000000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000451300000830000000000000,Defender Game Racer X7,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000007d0400000840000000000000,Destroyer Tiltpad,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows, +03000000791d00000103000000000000,Dual Box WII,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000bd12000002e0000000000000,Dual USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows, +030000008f0e00000910000000000000,DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows, +030000006f0e00003001000000000000,EA SPORTS PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +03000000120c0000f61c000000000000,Elite,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, +03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000006f0e00008401000000000000,Faceoff Deluxe+ Audio Wired Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00008001000000000000,Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000852100000201000000000000,FF-GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008500000000000000,Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008400000000000000,Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008700000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008800000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, +030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows, +03000000790000002201000000000000,Game Controller for PC,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows, +03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows, +03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +030000008f0e00000d31000000000000,GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000280400000140000000000000,GamePad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000ac0500003d03000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000ac0500004d04000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000ffff00000000000000000000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000102000000007801,GameStop Xbox 360 Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000009b2800003200000000000000,GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, +030000009b2800006000000000000000,GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, +030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000005c1a00003330000000000000,Genius MaxFire Grandias 12V,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000300f00000b01000000000000,GGE909 Recoil Pad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000f0250000c283000000000000,Gioteck,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f0250000c383000000000000,Gioteck VX2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f0250000c483000000000000,Gioteck VX2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000007d0400000540000000000000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004900000000000000,Hatsune Miku Sho Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000001008000001e1000000000000,Havit HV-G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows, +03000000d81400000862000000000000,HitBox Edition Cthulhu+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +03000000632500002605000000000000,HJD-X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +030000000d0f00002d00000000000000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005f00000000000000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005e00000000000000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004000000000000000,Hori Fighting Stick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005400000000000000,Hori Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00000900000000000000,Hori Pad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004d00000000000000,Hori Pad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00001600000000007803,HORI Real Arcade Pro EX-SE (Xbox 360),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00009c00000000000000,Hori TAC Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000c100000000000000,Horipad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006e00000000000000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006600000000000000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005500000000000000,Horipad 4 FPS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000ee00000000000000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000250900000017000000000000,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows, +030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Windows, +03000000d81d00000f00000000000000,iBUFFALO BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d81d00001000000000000000,iBUFFALO BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000830500006020000000000000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Windows, +03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +030000006f0e00002401000000000000,INJUSTICE FightStick PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000ac0500002c02000000000000,IPEGA,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000491900000204000000000000,Ipega PG-9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000491900000304000000000000,Ipega PG-9087 - Bluetooth Gamepad,+righty:+a5,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows, +030000006e0500000a20000000000000,JC-DUX60 ELECOM MMO Gamepad,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows, +030000006e0500000520000000000000,JC-P301U,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500000320000000000000,JC-U3613M (DInput),a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500000720000000000000,JC-W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +030000007e0500000620000000000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Windows, +030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Windows, +030000007e0500000720000000000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, +030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, +03000000bd12000003c0000000000000,JY-P70UR,a:b1,b:b0,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b4,x:b3,y:b2,platform:Windows, +03000000242f00002d00000000000000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000242f00008a00000000000000,JYS Wireless Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +03000000790000000200000000000000,King PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d040000d2ca000000000000,Logitech Cordless Precision,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows, +030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d0400001ac2000000000000,Logitech Precision Gamepad,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006d0400000ac2000000000000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows, +03000000380700006652000000000000,Mad Catz C.T.R.L.R,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000380700005032000000000000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700005082000000000000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008433000000000000,Mad Catz FightStick TE S+ (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008483000000000000,Mad Catz FightStick TE S+ (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008134000000000000,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008184000000000000,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700006252000000000000,Mad Catz Micro C.T.R.L.R,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008532000000000000,Madcatz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700003888000000000000,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700001888000000000000,MadCatz SFIV FightStick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows, +03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows, +03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,back:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b4,leftstick:b0,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows, +0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, +03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000790000002418000000000000,Mega Drive,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows, +03000000380700006382000000000000,MLG GamePad PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000c62400002a89000000000000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c62400002b89000000000000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c62400001a89000000000000,MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c62400001b89000000000000,MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000efbe0000edfe000000000000,Monect Virtual Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +030000006b140000010c000000000000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Windows, +03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, +030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows, +03000000550900001472000000000000,NVIDIA Controller v01.04,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows, +030000004b120000014d000000000000,NYKO AIRFLO,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,rightshoulder:b5,rightstick:a2,righttrigger:b7,start:b9,x:b2,y:b3,platform:Windows, +03000000782300000a10000000000000,Onlive Wireless Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,platform:Windows, +03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows, +03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000901000000000000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d62000009f31000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d6200000c757000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000632500002306000000000000,PS Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, +03000000e30500009605000000000000,PS to USB convert cable,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000100800000100000000000000,PS1 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +030000008f0e00007530000000000000,PS1 Controller,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000100800000300000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000250900008888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000666600006706000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows, +030000006b1400000303000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000009d0d00001330000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000250900000500000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, +030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows, +03000000632500007505000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +030000008f0e00001431000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000003807000056a8000000000000,PS3 RF pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000100000008200000000000000,PS360+ v1.66,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:h0.4,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00000011000000000000,QanBa Arcade JoyStick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows, +03000000300f00001611000000000000,QanBa Arcade JoyStick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, +03000000222c00000020000000000000,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001210000000000000,QanBa Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, +03000000341a00000104000000000000,QanBa Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows, +03000000222c00000223000000000000,Qanba Obsidian Arcade Joystick PS3 Mode,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000222c00000023000000000000,Qanba Obsidian Arcade Joystick PS4 Mode,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000321500000204000000000000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000104000000000000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000321500000707000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000321500000011000000000000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00001100000000000000,REAL ARCADE PRO.3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00007000000000000000,REAL ARCADE PRO.4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002200000000000000,REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005b00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005c00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000790000001100000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000bd12000013d0000000000000,Retrolink USB SEGA Saturn Classic,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows, +0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, +0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, +030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000006b140000020d000000000000,Revolution Pro Controller 2(1/2),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000006b140000130d000000000000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000003d0000000000000,run'n'drive,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000a306000023f6000000000000,Saitek Cyborg V.1 Game pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001201000000000000,Saitek Dual Analog Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows, +03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows, +03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001001000000000000,Saitek P480 Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows, +03000000a30600002106000000000000,Saitek PS1000,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000a306000020f6000000000000,Saitek PS2700,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001101000000000000,Saitek Rumble Pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows, +0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, +030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, +030000005e0400008e02000000007801,ShanWan PS3/PC Wired GamePad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000341a00000208000000000000,SL-6555-SBK,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows, +03000000341a00000908000000000000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000008f0e00000800000000000000,SpeedLink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000c01100000591000000000000,Speedlink Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d11800000094000000000000,Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows, +03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, +03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows, +03000000790000001c18000000000000,STK-7024X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000ff1100003133000000000000,SVEN X-PAD,a:b2,b:b3,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a4,start:b5,x:b0,y:b1,platform:Windows, +03000000d620000011a7000000000000,Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000457500002211000000000000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000007d0000000000000,T Mini Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000004f0400000ab1000000000000,T.16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows, +03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +030000004f04000023b3000000000000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f0400000ed0000000000000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows, +030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +03000000666600000488000000000000,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000d62000006000000000000000,Tournament PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000b80500000210000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows, +03000000d90400000200000000000000,TwinShock PS2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +030000006e0500001320000000000000,U4113,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000101c0000171c000000000000,uRage Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000300f00000701000000000000,USB 4-Axis 12-Button Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000341a00002308000000000000,USB gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000005509000000b4000000000000,USB gamepad,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,platform:Windows, +030000006b1400000203000000000000,USB gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000790000000a00000000000000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000f0250000c183000000000000,USB gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000ff1100004133000000000000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000632500002305000000000000,USB Vibration Joystick (BM),a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000302000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000702000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:+a3,righty:+a4,start:b4,x:b2,y:b3,platform:Windows, +030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000ff02000000007801,Xbox One Elite Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000450c00002043000000000000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000ac0500005b05000000000000,Xiaoji Gamesir-G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000172700004431000000000000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000790000004f18000000000000,ZD-T Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000120c0000101e000000000000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, + +# Mac OS X +030000008f0e00000300000009010000,2In1 USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +030000003512000012ab000001000000,8BitDo NES30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000022000000090000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000190000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001290000001000000,8BitDo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000260000001000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000031000001000000,8BitDo Wireless Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000a00500003232000009010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X, +03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X, +03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000ad1b000001f9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006f0e00000102000000000000,GameStop Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000007d0400000540000001010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005f00000000010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005e00000000010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005f00000000000000,HORI Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005e00000000000000,HORI Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00004d00000000000000,HORI Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00006e00000000010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00006600000000010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00006600000000000000,HORIPAD FPS PLUS 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f0000ee00000000010000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X, +03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X, +03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X, +030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X, +030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000242f00002d00000007010000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000019c2000005030000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d0400001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000006d04000018c2000000010000,Logitech RumblePad 2 USB,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700005032000000010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700005082000000010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700008433000000010000,Mad Catz FightStick TE S+ (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700008483000000010000,Mad Catz FightStick TE S+ (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X, +0300000079000000d218000026010000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000d620000010a7000003010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X, +03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X, +03000000d8140000cecf000000000000,MC Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000005e0400002700000001010000,Microsoft SideWinder Plug & Play Game Pad,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,leftx:a0,lefty:a1,righttrigger:b5,x:b2,y:b3,platform:Mac OS X, +03000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X, +03000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c62400002b89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000632500007505000000020000,NEOGEO mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X, +030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000d620000011a7000000020000,Nintendo Switch Core (Plus) Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000550900001472000025050000,NVIDIA Controller v01.04,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X, +030000006f0e00000901000002010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X, +030000004c050000da0c000000010000,Playstation Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000321500000204000000010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000321500000104000000010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000321500000010000000010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000321500000011000000010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, +030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, +0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000c6240000fefa000000000000,Rock Candy Gamepad for PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Mac OS X, +03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X, +03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X, +030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X, +030000004c050000e60c000000010000,Sony DualSense,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, +030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X, +03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, +03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, +03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X, +03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X, +03000000457500002211000000010000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X, +030000004f0400000ed0000000020000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X, +03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000bd12000015d0000000010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X, +030000006f0e00000302000025040000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006f0e00000702000003060000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000791d00000103000009010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X, +050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X, +030000005e0400008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000c6240000045d000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000050b000003090000,Xbox Elite Wireless Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000d102000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000dd02000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000e302000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000e002000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X, +030000005e040000e002000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X, +030000005e040000ea02000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000120c0000101e000000010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, + +# Linux +03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00001038000000010000,8Bitdo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux, +05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux, +03000000022000000090000011010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00002038000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000190000011010000,8Bitdo NES30 Pro 8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000061000000010000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +030000003512000012ab000010010000,8Bitdo SFC30 GamePad,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux, +05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00001290000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +030000005e0400008e02000020010000,8BitDo Wireless Adapter (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c82d00000031000011010000,8BitDo Wireless Adapter (DInput),a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, +05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, +030000006f0e00001302000000010000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00003901000020060000,Afterglow Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00003901000013020000,Afterglow Prismatic Wired Controller 048-007-NA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000007c1800000006000010010000,Alienware Dual Compatible Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +05000000491900000204000021000000,Amazon Fire Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux, +05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux, +03000000120c00000500000010010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux, +03000000c62400001b89000011010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000c21100000791000011010000,Be1 GC101 Controller 1.03 mode,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000c31100000791000011010000,Be1 GC101 GAMEPAD 1.03 mode,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000005e0400008e02000003030000,Be1 GC101 Xbox 360 Controller mode,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux, +03000000ffff0000ffff000000010000,Chinese-made Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux, +03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux, +03000000a306000022f6000011010000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000b40400000a01000000010000,CYPRESS USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux, +03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux, +030000004f04000004b3000010010000,Dual Power 2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000008f0e00000800000010010000,Gasia Co. Ltd PS(R) Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000007d0400000540000000010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000280400000140000000010000,Gravis GamePad Pro USB ,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys GamePad ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux, +030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000f0250000c383000010010000,GT VX2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +06000000adde0000efbe000002010000,Hidromancer Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux, +03000000c9110000f055000011010000,HJC Game GAMEPAD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000632500002605000010010000,HJD-X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000000d0f00000d00000000010000,hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftx:b4,lefty:b5,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux, +030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f0000c100000011010000,HORI CO. LTD. HORIPAD S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006b00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00008500000010010000,HORI Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00008600000002010000,Hori Fighting Commander,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000000d0f00005f00000011010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00005e00000011010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f0000aa00000011010000,HORI Real Arcade Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000000d0f0000d800000072056800,HORI Real Arcade Pro S,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +030000000d0f00001600000000010000,Hori Real Arcade Pro.EX-SE (Xbox 360),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, +030000000d0f00006e00000011010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006600000011010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f0000ee00000011010000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006700000001010000,HORIPAD ONE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux, +03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux, +050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000b50700001503000010010000,impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000d80400008200000003000000,IMS PCU#0 Gamepad Interface,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux, +03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux, +0500000049190000020400001b010000,Ipega PG-9069 - Bluetooth Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000632500007505000011010000,Ipega PG-9099 - Bluetooth Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux, +03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil Pad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux, +050000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux, +030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux, +03000000242f00002d00000011010000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000242f00008a00000011010000,JYS Wireless Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux, +030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000019200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400000ac2000010010000,Logitech Inc. WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux, +030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux, +050000004d4f435554452d3035305800,M54-PC,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,platform:Linux, +05000000380700006652000025010000,Mad Catz C.T.R.L.R ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700005032000011010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700005082000011010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux, +03000000380700008034000011010000,Mad Catz fightstick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008084000011010000,Mad Catz fightstick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008433000011010000,Mad Catz FightStick TE S+ (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008483000011010000,Mad Catz FightStick TE S+ (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller (SFIV),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000120c00000500000000010000,Manta Dualshock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +03000000790000004318000010010000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +03000000242f00007300000011010000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux, +0300000079000000d218000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000d620000010a7000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +0300000025090000e803000001010000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +03000000780000000600000010010000,Microntek USB Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +030000005e0400000e00000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux, +030000005e0400008e02000004010000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000062230000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000050b000003090000,Microsoft X-Box One Elite 2 pad,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000005e040000e302000003020000,Microsoft X-Box One Elite pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000d102000001010000,Microsoft X-Box One pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000dd02000003020000,Microsoft X-Box One pad (Firmware 2015),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000d102000003020000,Microsoft X-Box One pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008502000000010000,Microsoft X-Box pad (Japan),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +030000005e040000000b000008040000,Microsoft Xbox One Elite 2 pad - Wired,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000ea02000008040000,Microsoft Xbox One S pad - Wired,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c62400001a53000000010000,Mini PE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux, +05000000d6200000e589000001000000,Moga 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +05000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +03000000c62400002b89000011010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000c62400001a89000000010000,MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000250900006688000000010000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, +030000006b140000010c000010010000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux, +060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux, +03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b0,y:b3,platform:Linux, +050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500000920000001800000,Nintendo Switch Pro Controller (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +030000007e0500000920000011810000,Nintendo Switch Pro Controller Wired (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux, +03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, +05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, +03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +19000000010000000100000001010000,odroidgo2_joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux, +19000000010000000200000011000000,odroidgo2_joypad_v11,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux, +030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, +05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, +03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux, +03000000790000001c18000011010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e0000b802000001010000,PDP AFTERGLOW Wired Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000b802000013020000,PDP AFTERGLOW Wired Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00008001000011010000,PDP CO. LTD. Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00008701000011010000,PDP Rock Candy Wired Controller for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00000901000011010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000006f0e00008501000011010000,PDP Wired Fight Pad Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +05000000491900000204000000000000,PG-9118,x:b76,a:b73,b:b74,y:b77,back:b83,start:b84,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b79,lefttrigger:b81,rightshoulder:b80,righttrigger:b82,leftstick:b86,rightstick:b87,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux, +0500000049190000030400001b010000,PG-9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000c62400001a58000001010000,PowerA Xbox One Cabled,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000006f0e00001402000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000008f0e00000300000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +050000004c0500006802000000800000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +05000000504c415953544154494f4e00,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +060000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +03000000c01100000140000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c050000c405000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux, +030000009b2800003200000001010000,Raphnet Technologies GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, +030000009b2800006000000001010000,Raphnet Technologies GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, +030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux, +030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000008916000000fd000024010000,Razer Onza Tournament Edition,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000321500000204000011010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000104000011010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000810000011010000,Razer Panthera Evo Arcade Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000010000011010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000321500000011000011010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000790000001100000010010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, +0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux, +0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, +030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux, +03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux, +03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux, +03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux, +03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux, +03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux, +03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000a306000020f6000011010000,Saitek PS2700 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux, +03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,platform:Linux, +03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000632500007505000010010000,SHANWAN PS3/PC Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000bc2000000055000010010000,ShanWan PS3/PC Wired GamePad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000632500002305000010010000,ShanWan USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000341a00000908000010010000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, +030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, +03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, +03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000ad1b000038f0000090040000,Street Fighter IV FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000003b07000004a1000000010000,Suncom SFX Plus for USB,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux, +03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, +0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, +03000000457500002211000010010000,SZMY-POWER CO. LTD. GAMEPAD,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000008f0e00000d31000010010000,SZMY-POWER CO. LTD. GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000008f0e00001431000010010000,SZMY-POWER CO.,LTD. PS3 gamepad,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux, +030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004f0400000ed0000011010000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux, +030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b9,rightx:a2,righty:a3,x:b1,y:b3,platform:Linux, +030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux, +030000004f04000026b3000002040000,Thrustmaster Gamepad GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c6240000025b000002020000,Thrustmaster GPX Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000007d0000000010000,Thrustmaster T Mini Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000012b3000010010000,Thrustmaster vibrating gamepad,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +03000000bd12000015d0000010010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, +030000005e0400008e02000070050000,Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c01100000591000011010000,Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux, +03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux, +030000006f0e00000302000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00000702000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +05000000ac0500003232000001000000,VR-BOX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +03000000791d00000103000010010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +050000000d0f0000f600000001000000,Wireless HORIPAD Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux, +030000005e040000a102000014010000,Xbox 360 Wireless Receiver (XBOX),a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000005e040000ea02000000000000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000005e040000ea02000001030000,Xbox One Wireless Controller (Model 1708),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000005e0400008e02000000010000,xbox360 Wireless EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000ac0500005b05000010010000,Xiaoji Gamesir-G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux, +03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux, +xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000c0160000dc27000001010000,OnyxSoft Dual JoyDivision,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0, + +# Android +05000000c82d000006500000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000051060000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000012900000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000062280000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000002600000ffff0f00,8BitDo SN30 Pro+,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000002028000009000000ffff3f00,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000003512000020ab000000780f00,8BitDo SNES30 Gamepad,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android, +05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, +0500000031366332860c44aadfff0f00,GS Gamepad,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b3,y:b2,platform:Android, +64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Android, +050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android, +37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005509000003720000cf7f3f00,NVIDIA Controller v01.01,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005509000010720000ffff3f00,NVIDIA Controller v01.03,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005509000014720000df7f3f00,NVIDIA Controller v01.04,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, +050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +030000004c050000cc09000000006800,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000004c050000c4050000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +050000004c050000c4050000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000004c050000cc090000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +32633532643734376632656664383733,Sony DualSense,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +61303162353165316365336436343139,Sony DualSense,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android, +05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android, +050000004f0400000ed00000fffe3f00,ThrustMaster eSwap PRO Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +5477696e20555342204a6f7973746963,Twin USB Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android, +30306539356238653637313730656134,Wireless HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, +050000005e040000fd020000ff7f3f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000e00200000ffe3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android, +050000005e040000fd020000ffff3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000130b0000ffff3f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +65633038363832353634653836396239,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e04000091020000ff073f00,Xbox Wireless Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android, +050000001727000044310000ffff3f00,XiaoMi Game Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, + +# iOS +05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS, +05000000ac050000010000004f066d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS, +05000000ac05000001000000cf076d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS, +05000000ac05000001000000df076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +05000000ac0500000200000000006d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS, +05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS, +4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS, +4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS, +050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000004c050000cc090000ff870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,platform:iOS, +05000000ac0500000300000000006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS, +05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS, +05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS, +05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS, +050000005e040000050b0000ff070001,Xbox Elite Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000005e040000e0020000df070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000005e040000e0020000ff070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,