├── .github ├── dependabot.yml └── workflows │ └── release.yml ├── .gitignore ├── .gitmodules ├── .idea ├── ControllerBuddy.iml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── eclipseCodeFormatter.xml ├── encodings.xml ├── icon.svg ├── inspectionProfiles │ └── Project_Default.xml ├── misc.xml ├── runConfigurations │ ├── ControllerBuddy__de_DE_.xml │ └── ControllerBuddy__en_US_.xml └── vcs.xml ├── LICENSE ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── icon.ico ├── icon.png ├── icon.svg ├── screenshot_1.png ├── screenshot_2.png ├── screenshot_3.png ├── screenshot_4.png ├── screenshot_5.png ├── screenshot_6.png ├── screenshot_7.png ├── settings.gradle ├── spotbugs-baseline.xml ├── spotless.eclipseformat.xml ├── spotless.importorder └── src └── main ├── java └── de │ └── bwravencl │ └── controllerbuddy │ ├── ffi │ ├── Kernel32.java │ ├── Linux.java │ ├── User32.java │ └── VjoyInterface.java │ ├── gui │ ├── AssignmentsComponent.java │ ├── EditActionsDialog.java │ ├── GuiUtils.java │ ├── Main.java │ └── OnScreenKeyboard.java │ ├── input │ ├── Input.java │ ├── KeyStroke.java │ ├── LockKey.java │ ├── Mode.java │ ├── OverlayAxis.java │ ├── Profile.java │ ├── ScanCode.java │ └── action │ │ ├── ActivationIntervalAction.java │ │ ├── AxisToAxisAction.java │ │ ├── AxisToButtonAction.java │ │ ├── AxisToCursorAction.java │ │ ├── AxisToKeyAction.java │ │ ├── AxisToMouseButtonAction.java │ │ ├── AxisToRelativeAxisAction.java │ │ ├── AxisToScrollAction.java │ │ ├── ButtonToAxisResetAction.java │ │ ├── ButtonToButtonAction.java │ │ ├── ButtonToCursorAction.java │ │ ├── ButtonToCycleAction.java │ │ ├── ButtonToKeyAction.java │ │ ├── ButtonToLockKeyAction.java │ │ ├── ButtonToModeAction.java │ │ ├── ButtonToMouseButtonAction.java │ │ ├── ButtonToPressOnScreenKeyboardKeyAction.java │ │ ├── ButtonToReleaseAllOnScreenKeyboardKeysAction.java │ │ ├── ButtonToScrollAction.java │ │ ├── ButtonToSelectOnScreenKeyboardKeyAction.java │ │ ├── DescribableAction.java │ │ ├── IAction.java │ │ ├── IActivatableAction.java │ │ ├── IAxisToAction.java │ │ ├── IAxisToLongPressAction.java │ │ ├── IButtonToAction.java │ │ ├── IInitializationAction.java │ │ ├── ILongPressAction.java │ │ ├── IResetableAction.java │ │ ├── InvertableAction.java │ │ ├── NullAction.java │ │ ├── ToAxisAction.java │ │ ├── ToButtonAction.java │ │ ├── ToCursorAction.java │ │ ├── ToKeyAction.java │ │ ├── ToMouseButtonAction.java │ │ ├── ToScrollAction.java │ │ ├── annotation │ │ ├── Action.java │ │ └── ActionProperty.java │ │ └── gui │ │ ├── ActionsEditorBuilder.java │ │ ├── ActivationEditorBuilder.java │ │ ├── ActivationIntervalEditorBuilder.java │ │ ├── ArrayEditorBuilder.java │ │ ├── AxisValueEditorBuilder.java │ │ ├── BooleanEditorBuilder.java │ │ ├── ButtonEditorBuilder.java │ │ ├── ClicksEditorBuilder.java │ │ ├── CursorSensitivityEditorBuilder.java │ │ ├── DeadZoneEditorBuilder.java │ │ ├── DetentValueEditorBuilder.java │ │ ├── DirectionEditorBuilder.java │ │ ├── EditorBuilder.java │ │ ├── ExponentEditorBuilder.java │ │ ├── KeystrokeEditorBuilder.java │ │ ├── LockKeyEditorBuilder.java │ │ ├── LongPressEditorBuilder.java │ │ ├── MaxAxisValueEditorBuilder.java │ │ ├── MaxRelativeSpeedEditorBuilder.java │ │ ├── MinAxisValueEditorBuilder.java │ │ ├── ModeEditorBuilder.java │ │ ├── MouseAxisEditorBuilder.java │ │ ├── MouseButtonEditorBuilder.java │ │ ├── NumberEditorBuilder.java │ │ ├── StringEditorBuilder.java │ │ └── VirtualAxisEditorBuilder.java │ ├── json │ ├── ActionTypeAdapter.java │ ├── ColorTypeAdapter.java │ ├── LockKeyAdapter.java │ ├── ProfileTypeAdapterFactory.java │ └── ScanCodeAdapter.java │ ├── runmode │ ├── ClientRunMode.java │ ├── LocalRunMode.java │ ├── OutputRunMode.java │ ├── RunMode.java │ ├── ServerRunMode.java │ └── UinputDevice.java │ └── util │ ├── RunnableWithDefaultExceptionHandler.java │ └── VersionUtils.java └── resources ├── controller.svg ├── icon_128.png ├── icon_16.png ├── icon_32.png ├── icon_64.png ├── strings.properties ├── strings_de_DE.properties └── tray_icon_hint.png /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gradle" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | commit-message: 8 | prefix: "chore" 9 | - package-ecosystem: "gitsubmodule" 10 | directory: "/" 11 | schedule: 12 | interval: "daily" 13 | commit-message: 14 | prefix: "chore" 15 | - package-ecosystem: "github-actions" 16 | directory: "/" 17 | schedule: 18 | interval: "daily" 19 | commit-message: 20 | prefix: "chore" 21 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "SDL_GameControllerDB"] 2 | path = SDL_GameControllerDB 3 | url = https://github.com/mdqinc/SDL_GameControllerDB.git 4 | -------------------------------------------------------------------------------- /.idea/ControllerBuddy.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/eclipseCodeFormatter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/runConfigurations/ControllerBuddy__de_DE_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | -------------------------------------------------------------------------------- /.idea/runConfigurations/ControllerBuddy__en_US_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/icon.ico -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/icon.png -------------------------------------------------------------------------------- /screenshot_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/screenshot_1.png -------------------------------------------------------------------------------- /screenshot_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/screenshot_2.png -------------------------------------------------------------------------------- /screenshot_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/screenshot_3.png -------------------------------------------------------------------------------- /screenshot_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/screenshot_4.png -------------------------------------------------------------------------------- /screenshot_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/screenshot_5.png -------------------------------------------------------------------------------- /screenshot_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/screenshot_6.png -------------------------------------------------------------------------------- /screenshot_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/screenshot_7.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' 3 | } 4 | -------------------------------------------------------------------------------- /spotless.importorder: -------------------------------------------------------------------------------- 1 | 0= 2 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/ffi/Kernel32.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2025 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.ffi; 18 | 19 | import java.lang.foreign.Arena; 20 | import java.lang.foreign.FunctionDescriptor; 21 | import java.lang.foreign.Linker; 22 | import java.lang.foreign.SymbolLookup; 23 | import java.lang.foreign.ValueLayout; 24 | import java.lang.invoke.MethodHandle; 25 | 26 | @SuppressWarnings({ "exports", "restricted" }) 27 | public final class Kernel32 { 28 | 29 | private static final Linker LINKER = Linker.nativeLinker(); 30 | 31 | private static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("Kernel32"), 32 | Arena.global()); 33 | 34 | private static final MethodHandle GET_LAST_ERROR_METHOD_HANDLE = LINKER 35 | .downcallHandle(SYMBOL_LOOKUP.findOrThrow("GetLastError"), FunctionDescriptor.of(ValueLayout.JAVA_INT)); 36 | 37 | private Kernel32() { 38 | } 39 | 40 | public static int GetLastError() { 41 | try { 42 | return (int) GET_LAST_ERROR_METHOD_HANDLE.invoke(); 43 | } catch (final Throwable t) { 44 | throw new RuntimeException(t); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/KeyStroke.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import java.io.IOException; 21 | import java.io.ObjectInputStream; 22 | import java.io.ObjectOutputStream; 23 | import java.io.Serial; 24 | import java.io.Serializable; 25 | import java.util.ArrayList; 26 | import java.util.Arrays; 27 | import java.util.Objects; 28 | import java.util.Set; 29 | import java.util.stream.Collectors; 30 | 31 | public final class KeyStroke implements Cloneable, Serializable { 32 | 33 | @Serial 34 | private static final long serialVersionUID = 3572153768203547877L; 35 | 36 | @SuppressWarnings({ "serial", "RedundantSuppression" }) 37 | private ScanCode[] keyCodes; 38 | 39 | @SuppressWarnings({ "serial", "RedundantSuppression" }) 40 | private ScanCode[] modifierCodes; 41 | 42 | public KeyStroke() { 43 | this(new ScanCode[0], new ScanCode[0]); 44 | } 45 | 46 | public KeyStroke(final ScanCode[] keyCodes, final ScanCode[] modifierCodes) { 47 | this.keyCodes = keyCodes; 48 | this.modifierCodes = modifierCodes; 49 | } 50 | 51 | @Override 52 | public Object clone() throws CloneNotSupportedException { 53 | final var keyStroke = (KeyStroke) super.clone(); 54 | 55 | final var clonedKeyCodes = new ScanCode[keyCodes.length]; 56 | System.arraycopy(keyCodes, 0, clonedKeyCodes, 0, keyCodes.length); 57 | keyStroke.keyCodes = clonedKeyCodes; 58 | 59 | final var clonedModifierCodes = new ScanCode[modifierCodes.length]; 60 | System.arraycopy(modifierCodes, 0, clonedModifierCodes, 0, modifierCodes.length); 61 | keyStroke.modifierCodes = clonedModifierCodes; 62 | 63 | return keyStroke; 64 | } 65 | 66 | @Override 67 | public boolean equals(final Object obj) { 68 | return obj instanceof final KeyStroke keyStroke && Arrays.equals(keyCodes, keyStroke.keyCodes) 69 | && Arrays.equals(modifierCodes, keyStroke.modifierCodes); 70 | } 71 | 72 | public ScanCode[] getKeyCodes() { 73 | return keyCodes; 74 | } 75 | 76 | public ScanCode[] getModifierCodes() { 77 | return modifierCodes; 78 | } 79 | 80 | @Override 81 | public int hashCode() { 82 | return Objects.hash(Arrays.hashCode(keyCodes), Arrays.hashCode(modifierCodes)); 83 | } 84 | 85 | @Serial 86 | private void readObject(final ObjectInputStream stream) throws ClassNotFoundException, IOException { 87 | @SuppressWarnings("unchecked") 88 | final var modifierCodesKeyCodes = (Set) stream.readObject(); 89 | modifierCodes = modifierCodesKeyCodes.stream().map(ScanCode.KEY_CODE_TO_SCAN_CODE_MAP::get) 90 | .toArray(ScanCode[]::new); 91 | 92 | @SuppressWarnings("unchecked") 93 | final var keyCodesKeyCodes = (Set) stream.readObject(); 94 | keyCodes = keyCodesKeyCodes.stream().map(ScanCode.KEY_CODE_TO_SCAN_CODE_MAP::get).toArray(ScanCode[]::new); 95 | } 96 | 97 | public void setKeyCodes(final ScanCode[] keyCodes) { 98 | this.keyCodes = keyCodes; 99 | } 100 | 101 | public void setModifierCodes(final ScanCode[] modifierCodes) { 102 | this.modifierCodes = modifierCodes; 103 | } 104 | 105 | @Override 106 | public String toString() { 107 | final var collectedKeyCodes = new ArrayList<>(Arrays.asList(modifierCodes)); 108 | collectedKeyCodes.addAll(Arrays.asList(keyCodes)); 109 | if (collectedKeyCodes.isEmpty()) { 110 | return Main.STRINGS.getString("NOTHING"); 111 | } 112 | 113 | return collectedKeyCodes.stream().map(ScanCode::name).collect(Collectors.joining(" + ")); 114 | } 115 | 116 | @Serial 117 | private void writeObject(final ObjectOutputStream stream) throws IOException { 118 | stream.writeObject(Arrays.stream(modifierCodes).map(ScanCode::keyCode).collect(Collectors.toSet())); 119 | stream.writeObject(Arrays.stream(keyCodes).map(ScanCode::keyCode).collect(Collectors.toSet())); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/LockKey.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2016 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input; 18 | 19 | import de.bwravencl.controllerbuddy.runmode.UinputDevice.Event; 20 | import java.awt.event.KeyEvent; 21 | import java.util.Collections; 22 | import java.util.HashMap; 23 | import java.util.List; 24 | import java.util.Map; 25 | 26 | public record LockKey(String name, int virtualKeyCode, Event event, String sysfsLedName) { 27 | 28 | public static final String LOCK_SUFFIX = " Lock"; 29 | 30 | public static final String CAPS_LOCK = "Caps" + LOCK_SUFFIX; 31 | 32 | public static final LockKey CAPS_LOCK_LOCK_KEY = new LockKey(CAPS_LOCK, KeyEvent.VK_CAPS_LOCK, Event.KEY_CAPSLOCK, 33 | "capslock"); 34 | 35 | public static final Map NAME_TO_LOCK_KEY_MAP; 36 | 37 | public static final String NUM_LOCK = "Num" + LOCK_SUFFIX; 38 | 39 | public static final LockKey NUM_LOCK_LOCK_KEY = new LockKey(NUM_LOCK, KeyEvent.VK_NUM_LOCK, Event.KEY_NUMLOCK, 40 | "numlock"); 41 | 42 | public static final Map VIRTUAL_KEY_CODE_TO_LOCK_KEY_MAP; 43 | 44 | private static final String SCROLL_LOCK = "Scroll" + LOCK_SUFFIX; 45 | 46 | public static final LockKey SCROLL_LOCK_LOCK_KEY = new LockKey(SCROLL_LOCK, KeyEvent.VK_SCROLL_LOCK, 47 | Event.KEY_SCROLLLOCK, "scrolllock"); 48 | 49 | public static final List LOCK_KEYS = List.of(CAPS_LOCK_LOCK_KEY, NUM_LOCK_LOCK_KEY, SCROLL_LOCK_LOCK_KEY); 50 | 51 | static { 52 | final var modifiableNameToLockKeyMap = new HashMap(); 53 | final var modifiableVirtualKeyCodeToLockKeyMap = new HashMap(); 54 | 55 | for (final var lockKey : LOCK_KEYS) { 56 | modifiableNameToLockKeyMap.put(lockKey.name, lockKey); 57 | modifiableVirtualKeyCodeToLockKeyMap.put(lockKey.virtualKeyCode, lockKey); 58 | } 59 | 60 | NAME_TO_LOCK_KEY_MAP = Collections.unmodifiableMap(modifiableNameToLockKeyMap); 61 | VIRTUAL_KEY_CODE_TO_LOCK_KEY_MAP = Collections.unmodifiableMap(modifiableVirtualKeyCodeToLockKeyMap); 62 | } 63 | 64 | @Override 65 | public String toString() { 66 | return name; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/Mode.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Mode.Component.ComponentType; 21 | import de.bwravencl.controllerbuddy.input.action.IAction; 22 | import java.lang.constant.Constable; 23 | import java.util.ArrayList; 24 | import java.util.HashMap; 25 | import java.util.List; 26 | import java.util.Map; 27 | import java.util.Objects; 28 | import java.util.Set; 29 | import java.util.UUID; 30 | import java.util.stream.Collectors; 31 | import java.util.stream.Stream; 32 | import org.lwjgl.sdl.SDLGamepad; 33 | 34 | public final class Mode implements Cloneable { 35 | 36 | private final UUID uuid; 37 | 38 | private Map>> axisToActionsMap = new HashMap<>(); 39 | 40 | private Map>> buttonToActionsMap = new HashMap<>(); 41 | 42 | private String description; 43 | 44 | public Mode() { 45 | uuid = UUID.randomUUID(); 46 | description = Main.STRINGS.getString("NEW_MODE_DESCRIPTION"); 47 | } 48 | 49 | public Mode(final UUID uuid) { 50 | this.uuid = uuid; 51 | } 52 | 53 | @SuppressWarnings("unchecked") 54 | private static Map>> cloneActionMap( 55 | final Map>> actionMap) throws CloneNotSupportedException { 56 | final var clonedActionMap = new HashMap>>(); 57 | for (final var entry : actionMap.entrySet()) { 58 | for (final var action : entry.getValue()) { 59 | final var key = entry.getKey(); 60 | 61 | final var clonedActions = clonedActionMap.computeIfAbsent(key, _ -> new ArrayList<>()); 62 | clonedActions.add((IAction) action.clone()); 63 | } 64 | } 65 | 66 | return clonedActionMap; 67 | } 68 | 69 | @Override 70 | public Object clone() throws CloneNotSupportedException { 71 | final var mode = (Mode) super.clone(); 72 | 73 | mode.axisToActionsMap = cloneActionMap(axisToActionsMap); 74 | mode.buttonToActionsMap = cloneActionMap(buttonToActionsMap); 75 | 76 | return mode; 77 | } 78 | 79 | @Override 80 | public boolean equals(final Object obj) { 81 | return obj instanceof final Mode mode && Objects.equals(uuid, mode.uuid); 82 | } 83 | 84 | public Set> getAllActions() { 85 | return Stream.concat(axisToActionsMap.values().stream(), buttonToActionsMap.values().stream()) 86 | .flatMap(List::stream).collect(Collectors.toUnmodifiableSet()); 87 | } 88 | 89 | public Map>> getAxisToActionsMap() { 90 | return axisToActionsMap; 91 | } 92 | 93 | public Map>> getButtonToActionsMap() { 94 | return buttonToActionsMap; 95 | } 96 | 97 | public Map getComponentToActionsMap(final ComponentType type) { 98 | if (type == ComponentType.AXIS) { 99 | return axisToActionsMap; 100 | } 101 | return buttonToActionsMap; 102 | } 103 | 104 | public String getDescription() { 105 | return description; 106 | } 107 | 108 | public UUID getUuid() { 109 | return uuid; 110 | } 111 | 112 | @Override 113 | public int hashCode() { 114 | return Objects.hash(uuid); 115 | } 116 | 117 | public void setButtonToActionsMap(final Map>> buttonToActionsMap) { 118 | this.buttonToActionsMap = buttonToActionsMap; 119 | } 120 | 121 | public void setDescription(final String description) { 122 | this.description = description; 123 | } 124 | 125 | @Override 126 | public String toString() { 127 | return description; 128 | } 129 | 130 | public static final class Component { 131 | 132 | private final int index; 133 | 134 | private final Main main; 135 | 136 | private final ComponentType type; 137 | 138 | public Component(final Main main, final ComponentType type, final int index) { 139 | this.main = main; 140 | this.type = type; 141 | this.index = index; 142 | } 143 | 144 | public int getIndex() { 145 | if (main.isSwapLeftAndRightSticks()) { 146 | return switch (type) { 147 | case AXIS -> switch (index) { 148 | case SDLGamepad.SDL_GAMEPAD_AXIS_LEFTX -> SDLGamepad.SDL_GAMEPAD_AXIS_RIGHTX; 149 | case SDLGamepad.SDL_GAMEPAD_AXIS_LEFTY -> SDLGamepad.SDL_GAMEPAD_AXIS_RIGHTY; 150 | case SDLGamepad.SDL_GAMEPAD_AXIS_RIGHTX -> SDLGamepad.SDL_GAMEPAD_AXIS_LEFTX; 151 | case SDLGamepad.SDL_GAMEPAD_AXIS_RIGHTY -> SDLGamepad.SDL_GAMEPAD_AXIS_LEFTY; 152 | default -> index; 153 | }; 154 | case BUTTON -> switch (index) { 155 | case SDLGamepad.SDL_GAMEPAD_BUTTON_LEFT_STICK -> SDLGamepad.SDL_GAMEPAD_BUTTON_RIGHT_STICK; 156 | case SDLGamepad.SDL_GAMEPAD_BUTTON_RIGHT_STICK -> SDLGamepad.SDL_GAMEPAD_BUTTON_LEFT_STICK; 157 | default -> index; 158 | }; 159 | }; 160 | } 161 | 162 | return index; 163 | } 164 | 165 | public ComponentType getType() { 166 | return type; 167 | } 168 | 169 | public enum ComponentType { 170 | AXIS, BUTTON 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/OverlayAxis.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input; 18 | 19 | import java.awt.Color; 20 | 21 | public final class OverlayAxis implements Cloneable { 22 | 23 | public Color color; 24 | 25 | public boolean inverted; 26 | 27 | public OverlayAxis() { 28 | this(Color.BLACK, false); 29 | } 30 | 31 | private OverlayAxis(final Color color, final boolean inverted) { 32 | this.color = color; 33 | this.inverted = inverted; 34 | } 35 | 36 | @SuppressWarnings("MethodDoesntCallSuperMethod") 37 | @Override 38 | public Object clone() { 39 | return new OverlayAxis(new Color(color.getRGB(), true), inverted); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ActivationIntervalAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2024 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 21 | import de.bwravencl.controllerbuddy.input.action.gui.ActivationIntervalEditorBuilder; 22 | import java.lang.constant.Constable; 23 | 24 | abstract class ActivationIntervalAction extends DescribableAction 25 | implements IInitializationAction { 26 | 27 | @ActionProperty(label = "MAX_ACTIVATION_INTERVAL", editorBuilder = ActivationIntervalEditorBuilder.class, order = 501) 28 | private int maxActivationInterval; 29 | 30 | private transient long maxActivationTime = Integer.MAX_VALUE; 31 | 32 | @ActionProperty(label = "MIN_ACTIVATION_INTERVAL", editorBuilder = ActivationIntervalEditorBuilder.class, order = 500) 33 | private int minActivationInterval; 34 | 35 | private transient long minActivationTime; 36 | 37 | private transient boolean wasUp = true; 38 | 39 | public int getMaxActivationInterval() { 40 | return maxActivationInterval; 41 | } 42 | 43 | public int getMinActivationInterval() { 44 | return minActivationInterval; 45 | } 46 | 47 | boolean handleActivationInterval(final boolean hot) { 48 | final var hasMinActivationInterval = minActivationInterval > 0L; 49 | final var hasMaxActivationInterval = maxActivationInterval > 0L; 50 | 51 | if (hasMinActivationInterval || hasMaxActivationInterval) { 52 | final var currentTime = System.currentTimeMillis(); 53 | 54 | if (hot) { 55 | if (hasMaxActivationInterval && currentTime > maxActivationTime) { 56 | return false; 57 | } 58 | 59 | if (wasUp) { 60 | wasUp = false; 61 | if (hasMinActivationInterval) { 62 | minActivationTime = currentTime + minActivationInterval; 63 | } 64 | if (hasMaxActivationInterval) { 65 | maxActivationTime = currentTime + maxActivationInterval; 66 | } 67 | } 68 | } else { 69 | wasUp = true; 70 | 71 | if (hasMinActivationInterval && currentTime <= minActivationTime) { 72 | return true; 73 | } 74 | 75 | minActivationTime = 0L; 76 | maxActivationTime = Long.MAX_VALUE; 77 | } 78 | } 79 | 80 | return hot; 81 | } 82 | 83 | @Override 84 | public void init(final Input input) { 85 | wasUp = true; 86 | minActivationTime = 0; 87 | maxActivationTime = Long.MAX_VALUE; 88 | } 89 | 90 | public void setMaxActivationInterval(final int maxActivationInterval) { 91 | this.maxActivationInterval = maxActivationInterval; 92 | } 93 | 94 | public void setMinActivationInterval(final int minActivationInterval) { 95 | this.minActivationInterval = minActivationInterval; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/AxisToAxisAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 23 | import de.bwravencl.controllerbuddy.input.action.gui.AxisValueEditorBuilder; 24 | import de.bwravencl.controllerbuddy.input.action.gui.DeadZoneEditorBuilder; 25 | import de.bwravencl.controllerbuddy.input.action.gui.ExponentEditorBuilder; 26 | import de.bwravencl.controllerbuddy.input.action.gui.MaxAxisValueEditorBuilder; 27 | import de.bwravencl.controllerbuddy.input.action.gui.MinAxisValueEditorBuilder; 28 | 29 | @Action(label = "TO_AXIS_ACTION", category = ActionCategory.AXIS, order = 10) 30 | public class AxisToAxisAction extends ToAxisAction implements IAxisToAction, IInitializationAction { 31 | 32 | private static final float DEFAULT_DEAD_ZONE = 0f; 33 | 34 | private static final float DEFAULT_EXPONENT = 1f; 35 | 36 | private static final float DEFAULT_INITIAL_VALUE = 0f; 37 | 38 | private static final float DEFAULT_MAX_VALUE = 1f; 39 | 40 | private static final float DEFAULT_MIN_VALUE = -1f; 41 | 42 | @ActionProperty(label = "DEAD_ZONE", editorBuilder = DeadZoneEditorBuilder.class, order = 100) 43 | float deadZone = DEFAULT_DEAD_ZONE; 44 | 45 | @ActionProperty(label = "EXPONENT", editorBuilder = ExponentEditorBuilder.class, order = 103) 46 | float exponent = DEFAULT_EXPONENT; 47 | 48 | @ActionProperty(label = "INITIAL_VALUE", editorBuilder = AxisValueEditorBuilder.class, order = 202) 49 | float initialValue = DEFAULT_INITIAL_VALUE; 50 | 51 | @ActionProperty(label = "MAX_AXIS_VALUE", editorBuilder = MaxAxisValueEditorBuilder.class, order = 102) 52 | float maxValue = DEFAULT_MAX_VALUE; 53 | 54 | @ActionProperty(label = "MIN_AXIS_VALUE", editorBuilder = MinAxisValueEditorBuilder.class, order = 101) 55 | float minValue = DEFAULT_MIN_VALUE; 56 | 57 | @Override 58 | public void doAction(final Input input, final int component, Float value) { 59 | if (input.isAxisSuspended(component)) { 60 | return; 61 | } 62 | 63 | final var absValue = Math.abs(value); 64 | 65 | if (absValue <= deadZone) { 66 | value = 0f; 67 | } else { 68 | final float inMax; 69 | if (exponent != 0f) { 70 | inMax = (float) Math.pow((1f - deadZone) * 100f, exponent); 71 | 72 | value = Math.signum(value) * (float) Math.pow((absValue - deadZone) * 100f, exponent); 73 | } else { 74 | inMax = 1f; 75 | } 76 | 77 | if (value >= 0f) { 78 | value = Input.normalize(value, deadZone, inMax, 0f, maxValue); 79 | } else { 80 | value = Input.normalize(value, -inMax, -deadZone, minValue, 0f); 81 | } 82 | } 83 | 84 | input.setAxis(virtualAxis, invert ? -value : value, false, null); 85 | } 86 | 87 | public float getDeadZone() { 88 | return deadZone; 89 | } 90 | 91 | public float getExponent() { 92 | return exponent; 93 | } 94 | 95 | public float getInitialValue() { 96 | return initialValue; 97 | } 98 | 99 | public float getMaxValue() { 100 | return maxValue; 101 | } 102 | 103 | public float getMinValue() { 104 | return minValue; 105 | } 106 | 107 | @Override 108 | public void init(final Input input) { 109 | if (!input.isSkipAxisInitialization()) { 110 | input.setAxis(virtualAxis, invert ? -initialValue : initialValue, false, null); 111 | } 112 | } 113 | 114 | public void setDeadZone(final float deadZone) { 115 | this.deadZone = deadZone; 116 | } 117 | 118 | public void setExponent(final float exponent) { 119 | this.exponent = exponent; 120 | } 121 | 122 | public void setInitialValue(final float initialValue) { 123 | this.initialValue = initialValue; 124 | } 125 | 126 | public void setMaxValue(final float maxValue) { 127 | this.maxValue = maxValue; 128 | } 129 | 130 | public void setMinValue(final float minValue) { 131 | this.minValue = minValue; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/AxisToButtonAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 23 | import de.bwravencl.controllerbuddy.input.action.gui.AxisValueEditorBuilder; 24 | import de.bwravencl.controllerbuddy.input.action.gui.LongPressEditorBuilder; 25 | 26 | @Action(label = "TO_BUTTON_ACTION", category = ActionCategory.AXIS, order = 20) 27 | public final class AxisToButtonAction extends ToButtonAction implements IAxisToLongPressAction { 28 | 29 | private static final float DEFAULT_MAX_AXIS_VALUE = 1f; 30 | 31 | private static final float DEFAULT_MIN_AXIS_VALUE = 0.5f; 32 | 33 | @ActionProperty(label = "LONG_PRESS", editorBuilder = LongPressEditorBuilder.class, order = 400) 34 | private boolean longPress = DEFAULT_LONG_PRESS; 35 | 36 | @ActionProperty(label = "MAX_AXIS_VALUE", editorBuilder = AxisValueEditorBuilder.class, order = 101) 37 | private float maxAxisValue = DEFAULT_MAX_AXIS_VALUE; 38 | 39 | @ActionProperty(label = "MIN_AXIS_VALUE", editorBuilder = AxisValueEditorBuilder.class, order = 100) 40 | private float minAxisValue = DEFAULT_MIN_AXIS_VALUE; 41 | 42 | @Override 43 | public void doAction(final Input input, final int component, Float value) { 44 | value = handleLongPress(input, component, value); 45 | 46 | var hot = !input.isAxisSuspended(component) && value >= minAxisValue && value <= maxAxisValue; 47 | hot = handleActivationInterval(hot); 48 | 49 | if (hot && isAlreadyPressed(input)) { 50 | return; 51 | } 52 | 53 | input.setButton(buttonId, hot); 54 | } 55 | 56 | @Override 57 | public float getMaxAxisValue() { 58 | return maxAxisValue; 59 | } 60 | 61 | @Override 62 | public float getMinAxisValue() { 63 | return minAxisValue; 64 | } 65 | 66 | @Override 67 | public boolean isLongPress() { 68 | return longPress; 69 | } 70 | 71 | @Override 72 | public void setLongPress(final boolean longPress) { 73 | this.longPress = longPress; 74 | } 75 | 76 | @Override 77 | public void setMaxAxisValue(final float maxAxisValue) { 78 | this.maxAxisValue = maxAxisValue; 79 | } 80 | 81 | @Override 82 | public void setMinAxisValue(final float minAxisValue) { 83 | this.minAxisValue = minAxisValue; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/AxisToCursorAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 23 | import de.bwravencl.controllerbuddy.input.action.gui.DeadZoneEditorBuilder; 24 | import de.bwravencl.controllerbuddy.input.action.gui.ExponentEditorBuilder; 25 | 26 | @Action(label = "TO_CURSOR_ACTION", category = ActionCategory.AXIS, order = 25) 27 | public final class AxisToCursorAction extends ToCursorAction implements IAxisToAction { 28 | 29 | private static final float DEFAULT_DEAD_ZONE = 0.1f; 30 | 31 | private static final float DEFAULT_EXPONENT = 2f; 32 | 33 | @ActionProperty(label = "DEAD_ZONE", editorBuilder = DeadZoneEditorBuilder.class, order = 13) 34 | private float deadZone = DEFAULT_DEAD_ZONE; 35 | 36 | @ActionProperty(label = "EXPONENT", editorBuilder = ExponentEditorBuilder.class, order = 12) 37 | private float exponent = DEFAULT_EXPONENT; 38 | 39 | @Override 40 | public void doAction(final Input input, final int component, final Float value) { 41 | final var absValue = Math.abs(value); 42 | 43 | if (!input.isAxisSuspended(component) && absValue > deadZone) { 44 | final var inMax = (float) Math.pow((1f - deadZone) * 100f, exponent); 45 | 46 | final var d = Input.normalize(Math.signum(value) * (float) Math.pow((absValue - deadZone) * 100f, exponent), 47 | -inMax, inMax, -cursorSensitivity, cursorSensitivity) * input.getRateMultiplier(); 48 | moveCursor(input, d); 49 | } else { 50 | remainingD = 0f; 51 | } 52 | } 53 | 54 | public float getDeadZone() { 55 | return deadZone; 56 | } 57 | 58 | public float getExponent() { 59 | return exponent; 60 | } 61 | 62 | public void setDeadZone(final float deadZone) { 63 | this.deadZone = deadZone; 64 | } 65 | 66 | public void setExponent(final float exponent) { 67 | this.exponent = exponent; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/AxisToKeyAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 23 | import de.bwravencl.controllerbuddy.input.action.gui.AxisValueEditorBuilder; 24 | 25 | @Action(label = "TO_KEY_ACTION", category = ActionCategory.AXIS, order = 40) 26 | public final class AxisToKeyAction extends ToKeyAction implements IAxisToLongPressAction { 27 | 28 | private static final float DEFAULT_MAX_AXIS_VALUE = 1f; 29 | 30 | private static final float DEFAULT_MIN_AXIS_VALUE = 0.5f; 31 | 32 | @ActionProperty(label = "MAX_AXIS_VALUE", editorBuilder = AxisValueEditorBuilder.class, order = 101) 33 | private float maxAxisValue = DEFAULT_MAX_AXIS_VALUE; 34 | 35 | @ActionProperty(label = "MIN_AXIS_VALUE", editorBuilder = AxisValueEditorBuilder.class, order = 100) 36 | private float minAxisValue = DEFAULT_MIN_AXIS_VALUE; 37 | 38 | @Override 39 | public void doAction(final Input input, final int component, Float value) { 40 | value = handleLongPress(input, component, value); 41 | 42 | final var inZone = !input.isAxisSuspended(component) && value >= minAxisValue && value <= maxAxisValue; 43 | handleAction(inZone, input); 44 | } 45 | 46 | @Override 47 | public float getMaxAxisValue() { 48 | return maxAxisValue; 49 | } 50 | 51 | @Override 52 | public float getMinAxisValue() { 53 | return minAxisValue; 54 | } 55 | 56 | @Override 57 | public void setMaxAxisValue(final float maxAxisValue) { 58 | this.maxAxisValue = maxAxisValue; 59 | } 60 | 61 | @Override 62 | public void setMinAxisValue(final float minAxisValue) { 63 | this.minAxisValue = minAxisValue; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/AxisToMouseButtonAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 23 | import de.bwravencl.controllerbuddy.input.action.gui.AxisValueEditorBuilder; 24 | 25 | @Action(label = "TO_MOUSE_BUTTON_ACTION", category = ActionCategory.AXIS, order = 30) 26 | public final class AxisToMouseButtonAction extends ToMouseButtonAction implements IAxisToLongPressAction { 27 | 28 | private static final float DEFAULT_MAX_AXIS_VALUE = 1f; 29 | 30 | private static final float DEFAULT_MIN_AXIS_VALUE = 0.5f; 31 | 32 | @ActionProperty(label = "MAX_AXIS_VALUE", editorBuilder = AxisValueEditorBuilder.class, order = 101) 33 | private float maxAxisValue = DEFAULT_MAX_AXIS_VALUE; 34 | 35 | @ActionProperty(label = "MIN_AXIS_VALUE", editorBuilder = AxisValueEditorBuilder.class, order = 100) 36 | private float minAxisValue = DEFAULT_MIN_AXIS_VALUE; 37 | 38 | @Override 39 | public void doAction(final Input input, final int component, Float value) { 40 | value = handleLongPress(input, component, value); 41 | 42 | final var inZone = !input.isAxisSuspended(component) && value >= minAxisValue && value <= maxAxisValue; 43 | handleAction(inZone, input); 44 | } 45 | 46 | @Override 47 | public float getMaxAxisValue() { 48 | return maxAxisValue; 49 | } 50 | 51 | @Override 52 | public float getMinAxisValue() { 53 | return minAxisValue; 54 | } 55 | 56 | @Override 57 | public void setMaxAxisValue(final float maxAxisValue) { 58 | this.maxAxisValue = maxAxisValue; 59 | } 60 | 61 | @Override 62 | public void setMinAxisValue(final float minAxisValue) { 63 | this.minAxisValue = minAxisValue; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/AxisToRelativeAxisAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 23 | import de.bwravencl.controllerbuddy.input.action.gui.BooleanEditorBuilder; 24 | import de.bwravencl.controllerbuddy.input.action.gui.DetentValueEditorBuilder; 25 | import de.bwravencl.controllerbuddy.input.action.gui.MaxRelativeSpeedEditorBuilder; 26 | 27 | @Action(label = "AXIS_TO_RELATIVE_AXIS_ACTION", category = ActionCategory.AXIS, order = 15) 28 | public final class AxisToRelativeAxisAction extends AxisToAxisAction { 29 | 30 | private static final boolean DEFAULT_HAPTIC_FEEDBACK = false; 31 | 32 | private static final float DEFAULT_MAX_RELATIVE_SPEED = 4f; 33 | 34 | transient float remainingD; 35 | 36 | @ActionProperty(label = "DETENT_VALUE", editorBuilder = DetentValueEditorBuilder.class, order = 203) 37 | private Float detentValue = null; 38 | 39 | @ActionProperty(label = "HAPTIC_FEEDBACK", editorBuilder = BooleanEditorBuilder.class, order = 204) 40 | private boolean hapticFeedback = DEFAULT_HAPTIC_FEEDBACK; 41 | 42 | @ActionProperty(label = "MAX_RELATIVE_SPEED", editorBuilder = MaxRelativeSpeedEditorBuilder.class, order = 201) 43 | private float maxRelativeSpeed = DEFAULT_MAX_RELATIVE_SPEED; 44 | 45 | @Override 46 | public void doAction(final Input input, final int component, final Float value) { 47 | final var absValue = Math.abs(value); 48 | 49 | if (input.isAxisSuspended(component) || absValue <= deadZone) { 50 | return; 51 | } 52 | 53 | final var inMax = (float) Math.pow((1f - deadZone) * 100f, exponent); 54 | 55 | var d = Input.normalize(Math.signum(value) * (float) Math.pow((absValue - deadZone) * 100f, exponent), -inMax, 56 | inMax, -maxRelativeSpeed, maxRelativeSpeed) * input.getRateMultiplier(); 57 | d += remainingD; 58 | 59 | if (Math.abs(d) < input.getPlanckLength()) { 60 | remainingD = d; 61 | return; 62 | } 63 | 64 | final var runMode = input.getRunMode(); 65 | final var oldValue = Input.normalize(input.getAxes().get(virtualAxis), runMode.getMinAxisValue(), 66 | runMode.getMaxAxisValue(), -1f, 1f); 67 | 68 | final var newValue = Math.min(Math.max(oldValue + (invert ? -d : d), minValue), maxValue); 69 | input.setAxis(virtualAxis, newValue, hapticFeedback, detentValue); 70 | 71 | remainingD = 0f; 72 | } 73 | 74 | public Float getDetentValue() { 75 | return detentValue; 76 | } 77 | 78 | public float getMaxRelativeSpeed() { 79 | return maxRelativeSpeed; 80 | } 81 | 82 | public boolean isHapticFeedback() { 83 | return hapticFeedback; 84 | } 85 | 86 | public void setDetentValue(final Float detentValue) { 87 | this.detentValue = detentValue; 88 | } 89 | 90 | public void setHapticFeedback(final boolean hapticFeedback) { 91 | this.hapticFeedback = hapticFeedback; 92 | } 93 | 94 | public void setMaxRelativeSpeed(final float maxRelativeSpeed) { 95 | this.maxRelativeSpeed = maxRelativeSpeed; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/AxisToScrollAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 23 | import de.bwravencl.controllerbuddy.input.action.gui.DeadZoneEditorBuilder; 24 | import de.bwravencl.controllerbuddy.input.action.gui.ExponentEditorBuilder; 25 | 26 | @Action(label = "TO_SCROLL_ACTION", category = ActionCategory.AXIS, order = 35) 27 | public final class AxisToScrollAction extends ToScrollAction implements IAxisToAction { 28 | 29 | private static final float DEFAULT_DEAD_ZONE = 0.1f; 30 | 31 | private static final float DEFAULT_EXPONENT = 1f; 32 | 33 | @ActionProperty(label = "DEAD_ZONE", editorBuilder = DeadZoneEditorBuilder.class, order = 100) 34 | private float deadZone = DEFAULT_DEAD_ZONE; 35 | 36 | @ActionProperty(label = "EXPONENT", editorBuilder = ExponentEditorBuilder.class, order = 101) 37 | private float exponent = DEFAULT_EXPONENT; 38 | 39 | @Override 40 | public void doAction(final Input input, final int component, final Float value) { 41 | if (!input.isAxisSuspended(component) && Math.abs(value) > deadZone) { 42 | final var rateMultiplier = input.getRateMultiplier(); 43 | 44 | final var d = -Input.normalize( 45 | Math.signum(value) * (float) Math.pow(Math.abs(value) * 100f, exponent) * rateMultiplier, 46 | (float) -Math.pow(99.9f, exponent) * rateMultiplier, 47 | (float) Math.pow(99.9f, exponent) * rateMultiplier, -clicks, clicks); 48 | 49 | scroll(input, d); 50 | } else { 51 | remainingD = 0f; 52 | } 53 | } 54 | 55 | public float getDeadZone() { 56 | return deadZone; 57 | } 58 | 59 | public float getExponent() { 60 | return exponent; 61 | } 62 | 63 | public void setDeadZone(final float deadZone) { 64 | this.deadZone = deadZone; 65 | } 66 | 67 | public void setExponent(final float exponent) { 68 | this.exponent = exponent; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ButtonToAxisResetAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.Input.VirtualAxis; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 23 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 24 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 25 | import de.bwravencl.controllerbuddy.input.action.gui.ActivationEditorBuilder; 26 | import de.bwravencl.controllerbuddy.input.action.gui.AxisValueEditorBuilder; 27 | import de.bwravencl.controllerbuddy.input.action.gui.BooleanEditorBuilder; 28 | import de.bwravencl.controllerbuddy.input.action.gui.LongPressEditorBuilder; 29 | import de.bwravencl.controllerbuddy.input.action.gui.VirtualAxisEditorBuilder; 30 | import java.text.MessageFormat; 31 | 32 | @Action(label = "BUTTON_TO_AXIS_RESET_ACTION", category = ActionCategory.BUTTON_AND_CYCLES, order = 135) 33 | public final class ButtonToAxisResetAction extends DescribableAction 34 | implements IButtonToAction, IActivatableAction { 35 | 36 | private static final boolean DEFAULT_FLUID = false; 37 | 38 | private static final float DEFAULT_RESET_VALUE = 0f; 39 | 40 | private transient Activatable activatable; 41 | 42 | @ActionProperty(label = "ACTIVATION", editorBuilder = ActivationEditorBuilder.class, order = 40) 43 | private Activation activation = Activation.SINGLE_IMMEDIATELY; 44 | 45 | @ActionProperty(label = "FLUID", editorBuilder = BooleanEditorBuilder.class, order = 30) 46 | private boolean fluid = DEFAULT_FLUID; 47 | 48 | @ActionProperty(label = "LONG_PRESS", editorBuilder = LongPressEditorBuilder.class, order = 50) 49 | private boolean longPress = DEFAULT_LONG_PRESS; 50 | 51 | @ActionProperty(label = "RESET_VALUE", editorBuilder = AxisValueEditorBuilder.class, order = 20) 52 | private float resetValue = DEFAULT_RESET_VALUE; 53 | 54 | @ActionProperty(label = "VIRTUAL_AXIS", editorBuilder = VirtualAxisEditorBuilder.class, order = 10) 55 | private VirtualAxis virtualAxis = VirtualAxis.X; 56 | 57 | @Override 58 | public void doAction(final Input input, final int component, Boolean value) { 59 | value = handleLongPress(input, component, value); 60 | 61 | switch (activation) { 62 | case REPEAT -> { 63 | if (value) { 64 | resetAxis(input); 65 | } 66 | } 67 | case SINGLE_IMMEDIATELY -> { 68 | if (!value) { 69 | activatable = Activatable.YES; 70 | } else if (activatable == Activatable.YES) { 71 | activatable = Activatable.NO; 72 | resetAxis(input); 73 | } 74 | } 75 | case SINGLE_ON_RELEASE -> { 76 | if (value) { 77 | if (activatable == Activatable.NO) { 78 | activatable = Activatable.YES; 79 | } else if (activatable == Activatable.DENIED_BY_OTHER_ACTION) { 80 | activatable = Activatable.NO; 81 | } 82 | } else if (activatable == Activatable.YES) { 83 | activatable = Activatable.NO; 84 | resetAxis(input); 85 | } 86 | } 87 | } 88 | } 89 | 90 | @Override 91 | public Activatable getActivatable() { 92 | return activatable; 93 | } 94 | 95 | @Override 96 | public Activation getActivation() { 97 | return activation; 98 | } 99 | 100 | @Override 101 | public String getDescription(final Input input) { 102 | if (!isDescriptionEmpty()) { 103 | return super.getDescription(input); 104 | } 105 | 106 | return MessageFormat.format(Main.STRINGS.getString("RESET_JOYSTICK_AXIS_NAME"), virtualAxis); 107 | } 108 | 109 | public float getResetValue() { 110 | return resetValue; 111 | } 112 | 113 | public VirtualAxis getVirtualAxis() { 114 | return virtualAxis; 115 | } 116 | 117 | public boolean isFluid() { 118 | return fluid; 119 | } 120 | 121 | @Override 122 | public boolean isLongPress() { 123 | return longPress; 124 | } 125 | 126 | private void resetAxis(final Input input) { 127 | if (fluid) { 128 | input.moveAxis(virtualAxis, resetValue); 129 | } else { 130 | input.setAxis(virtualAxis, resetValue, false, null); 131 | } 132 | } 133 | 134 | @Override 135 | public void setActivatable(final Activatable activatable) { 136 | this.activatable = activatable; 137 | } 138 | 139 | @Override 140 | public void setActivation(final Activation activation) { 141 | this.activation = activation; 142 | } 143 | 144 | public void setFluid(final boolean fluid) { 145 | this.fluid = fluid; 146 | } 147 | 148 | @Override 149 | public void setLongPress(final boolean longPress) { 150 | this.longPress = longPress; 151 | } 152 | 153 | public void setResetValue(final float resetValue) { 154 | this.resetValue = resetValue; 155 | } 156 | 157 | public void setVirtualAxis(final VirtualAxis virtualAxis) { 158 | this.virtualAxis = virtualAxis; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ButtonToButtonAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 23 | import de.bwravencl.controllerbuddy.input.action.gui.LongPressEditorBuilder; 24 | 25 | @Action(label = "TO_BUTTON_ACTION", category = ActionCategory.BUTTON_AND_CYCLES, order = 110) 26 | public final class ButtonToButtonAction extends ToButtonAction implements IButtonToAction { 27 | 28 | @ActionProperty(label = "LONG_PRESS", editorBuilder = LongPressEditorBuilder.class, order = 400) 29 | private boolean longPress = DEFAULT_LONG_PRESS; 30 | 31 | @Override 32 | public void doAction(final Input input, final int component, Boolean value) { 33 | value = handleLongPress(input, component, value); 34 | value = handleActivationInterval(value); 35 | 36 | if (value && isAlreadyPressed(input)) { 37 | return; 38 | } 39 | 40 | input.setButton(buttonId, value); 41 | } 42 | 43 | @Override 44 | public boolean isLongPress() { 45 | return longPress; 46 | } 47 | 48 | @Override 49 | public void setLongPress(final boolean longPress) { 50 | this.longPress = longPress; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ButtonToCursorAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2020 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 23 | import de.bwravencl.controllerbuddy.input.action.gui.LongPressEditorBuilder; 24 | 25 | @Action(label = "TO_CURSOR_ACTION", category = ActionCategory.BUTTON, order = 125) 26 | public final class ButtonToCursorAction extends ToCursorAction implements IButtonToAction { 27 | 28 | @ActionProperty(label = "LONG_PRESS", editorBuilder = LongPressEditorBuilder.class, order = 400) 29 | private boolean longPress = DEFAULT_LONG_PRESS; 30 | 31 | @Override 32 | public void doAction(final Input input, final int component, Boolean value) { 33 | value = handleLongPress(input, component, value); 34 | 35 | if (!value) { 36 | remainingD = 0f; 37 | 38 | return; 39 | } 40 | 41 | final var d = cursorSensitivity * input.getRateMultiplier(); 42 | moveCursor(input, d); 43 | } 44 | 45 | @Override 46 | public boolean isLongPress() { 47 | return longPress; 48 | } 49 | 50 | @Override 51 | public void setLongPress(final boolean longPress) { 52 | this.longPress = longPress; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ButtonToKeyAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 22 | 23 | @Action(label = "TO_KEY_ACTION", category = ActionCategory.BUTTON_AND_CYCLES, order = 115) 24 | public final class ButtonToKeyAction extends ToKeyAction implements IButtonToAction { 25 | 26 | @Override 27 | public void doAction(final Input input, final int component, Boolean value) { 28 | value = handleLongPress(input, component, value); 29 | handleAction(value, input); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ButtonToLockKeyAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2016 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.LockKey; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 23 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 24 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 25 | import de.bwravencl.controllerbuddy.input.action.gui.BooleanEditorBuilder; 26 | import de.bwravencl.controllerbuddy.input.action.gui.LockKeyEditorBuilder; 27 | import java.text.MessageFormat; 28 | 29 | @Action(label = "BUTTON_TO_LOCK_KEY_ACTION", category = ActionCategory.BUTTON_AND_CYCLES, order = 116) 30 | public final class ButtonToLockKeyAction extends DescribableAction 31 | implements IButtonToAction, IInitializationAction { 32 | 33 | private boolean longPress = DEFAULT_LONG_PRESS; 34 | 35 | @ActionProperty(label = "ON", editorBuilder = BooleanEditorBuilder.class, order = 11) 36 | private boolean on = true; 37 | 38 | @ActionProperty(label = "KEY", editorBuilder = LockKeyEditorBuilder.class, overrideFieldName = "lockKey", overrideFieldType = LockKey.class, order = 10) 39 | private LockKey virtualKeyCode = LockKey.CAPS_LOCK_LOCK_KEY; 40 | 41 | private transient boolean wasUp = true; 42 | 43 | @Override 44 | public void doAction(final Input input, final int component, Boolean value) { 45 | value = handleLongPress(input, component, value); 46 | 47 | if (value) { 48 | if (wasUp) { 49 | wasUp = false; 50 | if (on) { 51 | input.getOnLockKeys().add(virtualKeyCode); 52 | } else { 53 | input.getOffLockKeys().add(virtualKeyCode); 54 | } 55 | } 56 | } else { 57 | wasUp = true; 58 | } 59 | } 60 | 61 | @Override 62 | public String getDescription(final Input input) { 63 | if (!isDescriptionEmpty()) { 64 | return super.getDescription(input); 65 | } 66 | 67 | return MessageFormat.format(Main.STRINGS.getString(on ? "LOCK_KEY_ON" : "LOCK_KEY_OFF"), getLockKey()); 68 | } 69 | 70 | public LockKey getLockKey() { 71 | return virtualKeyCode; 72 | } 73 | 74 | @Override 75 | public void init(final Input input) { 76 | resetWasUp(); 77 | } 78 | 79 | @Override 80 | public boolean isLongPress() { 81 | return longPress; 82 | } 83 | 84 | public boolean isOn() { 85 | return on; 86 | } 87 | 88 | void resetWasUp() { 89 | wasUp = true; 90 | } 91 | 92 | public void setLockKey(final LockKey lockKey) { 93 | virtualKeyCode = lockKey; 94 | } 95 | 96 | @Override 97 | public void setLongPress(final boolean longPress) { 98 | this.longPress = longPress; 99 | } 100 | 101 | public void setOn(final boolean on) { 102 | this.on = on; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ButtonToMouseButtonAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 22 | 23 | @Action(label = "TO_MOUSE_BUTTON_ACTION", category = ActionCategory.BUTTON_AND_CYCLES, order = 120) 24 | public final class ButtonToMouseButtonAction extends ToMouseButtonAction implements IButtonToAction { 25 | 26 | @Override 27 | public void doAction(final Input input, final int component, Boolean value) { 28 | value = handleLongPress(input, component, value); 29 | handleAction(value, input); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ButtonToPressOnScreenKeyboardKeyAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 23 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 24 | import de.bwravencl.controllerbuddy.input.action.gui.BooleanEditorBuilder; 25 | import de.bwravencl.controllerbuddy.input.action.gui.LongPressEditorBuilder; 26 | 27 | @Action(label = "BUTTON_TO_PRESS_ON_SCREEN_KEYBOARD_KEY_ACTION", category = ActionCategory.ON_SCREEN_KEYBOARD_MODE, order = 520) 28 | public final class ButtonToPressOnScreenKeyboardKeyAction implements IButtonToAction, IInitializationAction { 29 | 30 | @ActionProperty(label = "LOCK_KEY", editorBuilder = BooleanEditorBuilder.class, order = 10) 31 | private boolean lockKey; 32 | 33 | @ActionProperty(label = "LONG_PRESS", editorBuilder = LongPressEditorBuilder.class, order = 400) 34 | private boolean longPress = DEFAULT_LONG_PRESS; 35 | 36 | private transient boolean wasDown; 37 | 38 | private transient boolean wasUp = true; 39 | 40 | @Override 41 | public Object clone() throws CloneNotSupportedException { 42 | return super.clone(); 43 | } 44 | 45 | @Override 46 | public void doAction(final Input input, final int component, Boolean value) { 47 | value = handleLongPress(input, component, value); 48 | 49 | final var onScreenKeyboard = input.getMain().getOnScreenKeyboard(); 50 | 51 | if (!value) { 52 | if (lockKey) { 53 | wasUp = true; 54 | } else { 55 | if (wasDown) { 56 | onScreenKeyboard.releaseSelectedButton(); 57 | } 58 | wasDown = false; 59 | } 60 | } else if (lockKey) { 61 | if (wasUp) { 62 | onScreenKeyboard.toggleLock(); 63 | wasUp = false; 64 | } 65 | } else { 66 | onScreenKeyboard.pressSelectedButton(); 67 | wasDown = true; 68 | } 69 | } 70 | 71 | @Override 72 | public String getDescription(final Input input) { 73 | return Main.STRINGS 74 | .getString(lockKey ? "LOCK_SELECTED_ON_SCREEN_KEYBOARD_KEY" : "PRESS_SELECTED_ON_SCREEN_KEYBOARD_KEY"); 75 | } 76 | 77 | @Override 78 | public void init(final Input input) { 79 | wasUp = true; 80 | wasDown = false; 81 | } 82 | 83 | public boolean isLockKey() { 84 | return lockKey; 85 | } 86 | 87 | @Override 88 | public boolean isLongPress() { 89 | return longPress; 90 | } 91 | 92 | public void setLockKey(final boolean lockKey) { 93 | this.lockKey = lockKey; 94 | } 95 | 96 | @Override 97 | public void setLongPress(final boolean longPress) { 98 | this.longPress = longPress; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ButtonToReleaseAllOnScreenKeyboardKeysAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2022 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 23 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 24 | import de.bwravencl.controllerbuddy.input.action.gui.LongPressEditorBuilder; 25 | 26 | @Action(label = "BUTTON_TO_RELEASE_ALL_ON_SCREEN_KEYBOARD_KEYS_ACTION", category = ActionCategory.ON_SCREEN_KEYBOARD_MODE, order = 530) 27 | public final class ButtonToReleaseAllOnScreenKeyboardKeysAction implements IButtonToAction { 28 | 29 | @ActionProperty(label = "LONG_PRESS", editorBuilder = LongPressEditorBuilder.class, order = 400) 30 | private boolean longPress = DEFAULT_LONG_PRESS; 31 | 32 | @Override 33 | public Object clone() throws CloneNotSupportedException { 34 | return super.clone(); 35 | } 36 | 37 | @Override 38 | public void doAction(final Input input, final int component, Boolean value) { 39 | value = handleLongPress(input, component, value); 40 | 41 | if (value) { 42 | input.getMain().getOnScreenKeyboard().releaseAllButtons(); 43 | } 44 | } 45 | 46 | @Override 47 | public String getDescription(final Input input) { 48 | return Main.STRINGS.getString("BUTTON_TO_RELEASE_ALL_ON_SCREEN_KEYBOARD_KEYS_ACTION"); 49 | } 50 | 51 | @Override 52 | public boolean isLongPress() { 53 | return longPress; 54 | } 55 | 56 | @Override 57 | public void setLongPress(final boolean longPress) { 58 | this.longPress = longPress; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ButtonToScrollAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 23 | import de.bwravencl.controllerbuddy.input.action.gui.LongPressEditorBuilder; 24 | 25 | @Action(label = "TO_SCROLL_ACTION", category = ActionCategory.BUTTON_AND_CYCLES, order = 130) 26 | public final class ButtonToScrollAction extends ToScrollAction implements IButtonToAction { 27 | 28 | @ActionProperty(label = "LONG_PRESS", editorBuilder = LongPressEditorBuilder.class, order = 400) 29 | private boolean longPress = DEFAULT_LONG_PRESS; 30 | 31 | @Override 32 | public void doAction(final Input input, final int component, Boolean value) { 33 | value = handleLongPress(input, component, value); 34 | 35 | if (!value) { 36 | remainingD = 0f; 37 | 38 | return; 39 | } 40 | 41 | final var d = clicks * input.getRateMultiplier(); 42 | scroll(input, d); 43 | } 44 | 45 | @Override 46 | public boolean isLongPress() { 47 | return longPress; 48 | } 49 | 50 | @Override 51 | public void setLongPress(final boolean longPress) { 52 | this.longPress = longPress; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ButtonToSelectOnScreenKeyboardKeyAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.gui.OnScreenKeyboard.Direction; 21 | import de.bwravencl.controllerbuddy.input.Input; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 23 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 24 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 25 | import de.bwravencl.controllerbuddy.input.action.gui.DirectionEditorBuilder; 26 | import de.bwravencl.controllerbuddy.input.action.gui.LongPressEditorBuilder; 27 | import java.text.MessageFormat; 28 | import java.util.Locale; 29 | 30 | @Action(label = "BUTTON_TO_SELECT_ON_SCREEN_KEYBOARD_KEY_ACTION", category = ActionCategory.ON_SCREEN_KEYBOARD_MODE, order = 510) 31 | public final class ButtonToSelectOnScreenKeyboardKeyAction implements IButtonToAction, IResetableAction { 32 | 33 | private static final long ACCELERATION_TIME = 300L; 34 | 35 | private static final long INITIAL_MIN_ELAPSE_TIME = 250L; 36 | 37 | private static final long PEAK_MIN_ELAPSE_TIME = 90L; 38 | 39 | private static final float PEAK_ELAPSE_TIME_REDUCTION = (INITIAL_MIN_ELAPSE_TIME - PEAK_MIN_ELAPSE_TIME) 40 | / (float) ACCELERATION_TIME; 41 | 42 | @ActionProperty(label = "DIRECTION", editorBuilder = DirectionEditorBuilder.class, order = 10) 43 | private Direction direction = Direction.UP; 44 | 45 | private transient long initialPressTime; 46 | 47 | private transient long lastPressTime; 48 | 49 | @ActionProperty(label = "LONG_PRESS", editorBuilder = LongPressEditorBuilder.class, order = 400) 50 | private boolean longPress = DEFAULT_LONG_PRESS; 51 | 52 | @Override 53 | public Object clone() throws CloneNotSupportedException { 54 | return super.clone(); 55 | } 56 | 57 | @Override 58 | public void doAction(final Input input, final int component, Boolean value) { 59 | value = handleLongPress(input, component, value); 60 | 61 | if (value) { 62 | final var currentTime = System.currentTimeMillis(); 63 | if (initialPressTime == 0) { 64 | initialPressTime = currentTime; 65 | } 66 | 67 | final var accelerationFactor = Math.min(currentTime - initialPressTime, ACCELERATION_TIME); 68 | final var minElapseTime = INITIAL_MIN_ELAPSE_TIME 69 | - (long) (accelerationFactor * PEAK_ELAPSE_TIME_REDUCTION); 70 | 71 | if (currentTime - lastPressTime >= minElapseTime) { 72 | input.getMain().getOnScreenKeyboard().moveSelector(direction); 73 | lastPressTime = currentTime; 74 | } 75 | } else { 76 | initialPressTime = 0; 77 | } 78 | } 79 | 80 | @Override 81 | public String getDescription(final Input input) { 82 | return MessageFormat.format(Main.STRINGS.getString("ON_SCREEN_KEYBOARD_KEY_SELECTOR"), 83 | direction.toString().toLowerCase(Locale.ROOT)); 84 | } 85 | 86 | public Direction getDirection() { 87 | return direction; 88 | } 89 | 90 | @Override 91 | public boolean isLongPress() { 92 | return longPress; 93 | } 94 | 95 | @Override 96 | public void reset(final Input input) { 97 | initialPressTime = 0L; 98 | lastPressTime = 0L; 99 | } 100 | 101 | public void setDirection(final Direction direction) { 102 | this.direction = direction; 103 | } 104 | 105 | @Override 106 | public void setLongPress(final boolean longPress) { 107 | this.longPress = longPress; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/DescribableAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2020 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 21 | import de.bwravencl.controllerbuddy.input.action.gui.StringEditorBuilder; 22 | import java.lang.constant.Constable; 23 | 24 | public abstract class DescribableAction implements IAction { 25 | 26 | @ActionProperty(label = "DESCRIPTION", editorBuilder = StringEditorBuilder.class, order = 0) 27 | private String description; 28 | 29 | @Override 30 | public Object clone() throws CloneNotSupportedException { 31 | return super.clone(); 32 | } 33 | 34 | public String getDescription() { 35 | return description; 36 | } 37 | 38 | @Override 39 | public String getDescription(final Input input) { 40 | if (!isDescriptionEmpty()) { 41 | return description; 42 | } 43 | 44 | return IAction.getDefaultDescription(this); 45 | } 46 | 47 | boolean isDescriptionEmpty() { 48 | return description == null || description.isEmpty(); 49 | } 50 | 51 | public void setDescription(final String description) { 52 | this.description = description; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/IAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 22 | import java.lang.constant.Constable; 23 | 24 | public interface IAction extends Cloneable { 25 | 26 | static String getDefaultDescription(final IAction action) { 27 | return getLabel(action.getClass()); 28 | } 29 | 30 | static String getLabel(final Class actionClass) { 31 | final var annotation = actionClass.getAnnotation(Action.class); 32 | if (annotation == null) { 33 | throw new RuntimeException( 34 | actionClass.getName() + ": missing " + Action.class.getSimpleName() + " annotation"); 35 | } 36 | 37 | return Main.STRINGS.getString(annotation.label()); 38 | } 39 | 40 | Object clone() throws CloneNotSupportedException; 41 | 42 | void doAction(final Input input, int component, V value); 43 | 44 | String getDescription(final Input input); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/IActivatableAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2020 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import java.lang.constant.Constable; 22 | 23 | public interface IActivatableAction extends IInitializationAction { 24 | 25 | Activatable getActivatable(); 26 | 27 | Activation getActivation(); 28 | 29 | @Override 30 | default void init(final Input input) { 31 | setActivatable(getActivation() == Activation.SINGLE_ON_RELEASE ? Activatable.NO : Activatable.YES); 32 | } 33 | 34 | void setActivatable(final Activatable activatable); 35 | 36 | void setActivation(final Activation activation); 37 | 38 | enum Activatable { 39 | YES, NO, DENIED_BY_OTHER_ACTION, ALWAYS 40 | } 41 | 42 | enum Activation { 43 | 44 | REPEAT("ACTIVATION_REPEAT"), SINGLE_IMMEDIATELY("ACTIVATION_SINGLE_IMMEDIATELY"), 45 | SINGLE_ON_RELEASE("ACTIVATION_SINGLE_ON_RELEASE"); 46 | 47 | private final String label; 48 | 49 | Activation(final String labelKey) { 50 | label = Main.STRINGS.getString(labelKey); 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return label; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/IAxisToAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | public interface IAxisToAction extends IAction { 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/IAxisToLongPressAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2021 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.Mode; 21 | import de.bwravencl.controllerbuddy.input.action.IActivatableAction.Activatable; 22 | import de.bwravencl.controllerbuddy.input.action.IActivatableAction.Activation; 23 | import java.util.HashMap; 24 | import java.util.Map; 25 | 26 | public interface IAxisToLongPressAction extends IAxisToAction, ILongPressAction { 27 | 28 | Map actionToDownSinceMap = new HashMap<>(); 29 | 30 | Map, Boolean> actionToMustDenyActivationMap = new HashMap<>(); 31 | 32 | private static boolean isOnReleaseAction(final IActivatableAction action) { 33 | return action.getActivation() == Activation.SINGLE_ON_RELEASE; 34 | } 35 | 36 | static void onModeActivated(final Mode activeMode, final Mode newMode) { 37 | actionToDownSinceMap.keySet().removeIf(action -> { 38 | if (activeMode.getAllActions().contains(action)) { 39 | final var optionalAxisId = activeMode.getAxisToActionsMap().entrySet().stream() 40 | .filter(entry -> entry.getValue().contains(action)).map(Map.Entry::getKey).findFirst(); 41 | return optionalAxisId.isPresent() && newMode.getButtonToActionsMap().containsKey(optionalAxisId.get()); 42 | } 43 | 44 | return false; 45 | }); 46 | } 47 | 48 | static void onModeDeactivated(final Mode activeMode) { 49 | actionToDownSinceMap.keySet().removeIf(action -> activeMode.getAllActions().contains(action)); 50 | } 51 | 52 | static void reset() { 53 | actionToDownSinceMap.clear(); 54 | actionToMustDenyActivationMap.clear(); 55 | } 56 | 57 | float getMaxAxisValue(); 58 | 59 | float getMinAxisValue(); 60 | 61 | default Float handleLongPress(final Input input, final int component, final Float value) { 62 | if (!isLongPress()) { 63 | return value; 64 | } 65 | 66 | final var currentTime = System.currentTimeMillis(); 67 | 68 | if (value >= getMinAxisValue() && value <= getMaxAxisValue()) { 69 | if (!actionToDownSinceMap.containsKey(this)) { 70 | actionToDownSinceMap.put(this, currentTime); 71 | } else if (currentTime - actionToDownSinceMap.get(this) >= MIN_LONG_PRESS_TIME) { 72 | for (final var mode : input.getProfile().getModes()) { 73 | final var actions = mode.getAxisToActionsMap().get(component); 74 | 75 | if (actions != null && actions.contains(this)) { 76 | for (final IAction action : actions) { 77 | if (action == this) { 78 | continue; 79 | } 80 | 81 | var isUndelayedOnReleaseAction = actionToMustDenyActivationMap.get(action); 82 | 83 | if (isUndelayedOnReleaseAction == null) { 84 | isUndelayedOnReleaseAction = false; 85 | 86 | if (action instanceof final AxisToKeyAction axisToKeyAction) { 87 | if (!axisToKeyAction.isLongPress()) { 88 | isUndelayedOnReleaseAction = isOnReleaseAction(axisToKeyAction); 89 | } 90 | } else if (action instanceof final AxisToMouseButtonAction axisToMouseButtonAction) { 91 | if (!axisToMouseButtonAction.isLongPress()) { 92 | isUndelayedOnReleaseAction = isOnReleaseAction(axisToMouseButtonAction); 93 | } 94 | } 95 | 96 | actionToMustDenyActivationMap.put(action, isUndelayedOnReleaseAction); 97 | } 98 | 99 | if (isUndelayedOnReleaseAction) { 100 | ((IActivatableAction) action).setActivatable(Activatable.DENIED_BY_OTHER_ACTION); 101 | } 102 | } 103 | 104 | break; 105 | } 106 | } 107 | 108 | return value; 109 | } 110 | } else { 111 | actionToDownSinceMap.remove(this); 112 | } 113 | 114 | return Float.MIN_VALUE; 115 | } 116 | 117 | void setMaxAxisValue(final float maxAxisValue); 118 | 119 | void setMinAxisValue(final float minAxisValue); 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/IButtonToAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.Mode; 21 | import de.bwravencl.controllerbuddy.input.action.IActivatableAction.Activatable; 22 | import de.bwravencl.controllerbuddy.input.action.IActivatableAction.Activation; 23 | import java.util.HashMap; 24 | import java.util.Map; 25 | 26 | public interface IButtonToAction extends ILongPressAction { 27 | 28 | Map actionToDownSinceMap = new HashMap<>(); 29 | 30 | Map, Boolean> actionToMustDenyActivationMap = new HashMap<>(); 31 | 32 | private static boolean isOnReleaseAction(final IActivatableAction action) { 33 | return action.getActivation() == Activation.SINGLE_ON_RELEASE; 34 | } 35 | 36 | static void onModeActivated(final Mode activeMode, final Mode newMode) { 37 | actionToDownSinceMap.keySet().removeIf(action -> { 38 | if (activeMode.getAllActions().contains(action)) { 39 | final var optionalButtonId = activeMode.getButtonToActionsMap().entrySet().stream() 40 | .filter(entry -> entry.getValue().contains(action)).map(Map.Entry::getKey).findFirst(); 41 | return optionalButtonId.isPresent() 42 | && newMode.getButtonToActionsMap().containsKey(optionalButtonId.get()); 43 | } 44 | 45 | return false; 46 | }); 47 | } 48 | 49 | static void onModeDeactivated(final Mode activeMode) { 50 | actionToDownSinceMap.keySet().removeIf(action -> activeMode.getAllActions().contains(action)); 51 | } 52 | 53 | static void reset() { 54 | actionToDownSinceMap.clear(); 55 | actionToMustDenyActivationMap.clear(); 56 | } 57 | 58 | default boolean handleLongPress(final Input input, final int component, final boolean value) { 59 | if (!isLongPress()) { 60 | return value; 61 | } 62 | 63 | final var currentTime = System.currentTimeMillis(); 64 | 65 | if (value) { 66 | if (!actionToDownSinceMap.containsKey(this)) { 67 | actionToDownSinceMap.put(this, currentTime); 68 | } else if (currentTime - actionToDownSinceMap.get(this) >= MIN_LONG_PRESS_TIME) { 69 | for (final var mode : input.getProfile().getModes()) { 70 | final var actions = mode.getButtonToActionsMap().get(component); 71 | 72 | if (actions != null && actions.contains(this)) { 73 | for (final IAction action : actions) { 74 | if (action == this) { 75 | continue; 76 | } 77 | 78 | var isUndelayedOnReleaseAction = actionToMustDenyActivationMap.get(action); 79 | 80 | if (isUndelayedOnReleaseAction == null) { 81 | isUndelayedOnReleaseAction = false; 82 | 83 | if (action instanceof final ButtonToKeyAction buttonToKeyAction) { 84 | if (!buttonToKeyAction.isLongPress()) { 85 | isUndelayedOnReleaseAction = isOnReleaseAction(buttonToKeyAction); 86 | } 87 | } else if (action instanceof final ButtonToMouseButtonAction buttonToMouseButtonAction) { 88 | if (!buttonToMouseButtonAction.isLongPress()) { 89 | isUndelayedOnReleaseAction = isOnReleaseAction(buttonToMouseButtonAction); 90 | } 91 | } else if (action instanceof final ButtonToCycleAction buttonToCycleAction) { 92 | if (!buttonToCycleAction.isLongPress()) { 93 | isUndelayedOnReleaseAction = true; 94 | } 95 | } 96 | 97 | actionToMustDenyActivationMap.put(action, isUndelayedOnReleaseAction); 98 | } 99 | 100 | if (isUndelayedOnReleaseAction) { 101 | ((IActivatableAction) action).setActivatable(Activatable.DENIED_BY_OTHER_ACTION); 102 | } 103 | } 104 | 105 | break; 106 | } 107 | } 108 | 109 | return true; 110 | } 111 | } else { 112 | actionToDownSinceMap.remove(this); 113 | } 114 | 115 | return false; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/IInitializationAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import java.lang.constant.Constable; 21 | 22 | public interface IInitializationAction extends IAction { 23 | 24 | void init(final Input input); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ILongPressAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import java.lang.constant.Constable; 20 | 21 | public interface ILongPressAction extends IAction { 22 | 23 | boolean DEFAULT_LONG_PRESS = false; 24 | 25 | long MIN_LONG_PRESS_TIME = 1000L; 26 | 27 | boolean isLongPress(); 28 | 29 | void setLongPress(final boolean longPress); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/IResetableAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import java.lang.constant.Constable; 21 | 22 | public interface IResetableAction extends IAction { 23 | 24 | void reset(final Input input); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/InvertableAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 20 | import de.bwravencl.controllerbuddy.input.action.gui.BooleanEditorBuilder; 21 | import java.lang.constant.Constable; 22 | 23 | abstract class InvertableAction extends DescribableAction { 24 | 25 | @ActionProperty(label = "INVERT", editorBuilder = BooleanEditorBuilder.class, order = 500) 26 | boolean invert; 27 | 28 | public boolean isInvert() { 29 | return invert; 30 | } 31 | 32 | public void setInvert(final boolean invert) { 33 | this.invert = invert; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/NullAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.input.Input; 20 | import de.bwravencl.controllerbuddy.input.action.annotation.Action; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.Action.ActionCategory; 22 | import java.lang.constant.Constable; 23 | 24 | @Action(label = "NULL_ACTION", category = ActionCategory.ALL, order = 999) 25 | public final class NullAction implements IAction { 26 | 27 | @Override 28 | public Object clone() throws CloneNotSupportedException { 29 | return super.clone(); 30 | } 31 | 32 | @Override 33 | public void doAction(final Input input, final int component, final Constable value) { 34 | } 35 | 36 | @Override 37 | public String getDescription(final Input input) { 38 | return IAction.getDefaultDescription(this); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ToAxisAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.Input.VirtualAxis; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 23 | import de.bwravencl.controllerbuddy.input.action.gui.VirtualAxisEditorBuilder; 24 | import java.lang.constant.Constable; 25 | import java.text.MessageFormat; 26 | 27 | abstract class ToAxisAction extends InvertableAction { 28 | 29 | @ActionProperty(label = "VIRTUAL_AXIS", editorBuilder = VirtualAxisEditorBuilder.class, order = 10) 30 | VirtualAxis virtualAxis = VirtualAxis.X; 31 | 32 | @Override 33 | public String getDescription(final Input input) { 34 | if (!isDescriptionEmpty()) { 35 | return super.getDescription(input); 36 | } 37 | 38 | return MessageFormat.format(Main.STRINGS.getString("JOYSTICK_AXIS_NAME"), virtualAxis); 39 | } 40 | 41 | public VirtualAxis getVirtualAxis() { 42 | return virtualAxis; 43 | } 44 | 45 | public void setVirtualAxis(final VirtualAxis virtualAxis) { 46 | this.virtualAxis = virtualAxis; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ToButtonAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 22 | import de.bwravencl.controllerbuddy.input.action.gui.ButtonEditorBuilder; 23 | import java.lang.constant.Constable; 24 | import java.text.MessageFormat; 25 | 26 | public abstract class ToButtonAction extends ActivationIntervalAction { 27 | 28 | @ActionProperty(label = "BUTTON_ID", editorBuilder = ButtonEditorBuilder.class, order = 10) 29 | int buttonId; 30 | 31 | public int getButtonId() { 32 | return buttonId; 33 | } 34 | 35 | @Override 36 | public String getDescription(final Input input) { 37 | if (!isDescriptionEmpty()) { 38 | return super.getDescription(input); 39 | } 40 | 41 | return MessageFormat.format(Main.STRINGS.getString("JOYSTICK_BUTTON_NO"), buttonId + 1); 42 | } 43 | 44 | final boolean isAlreadyPressed(final Input input) { 45 | final var buttons = input.getButtons(); 46 | return buttonId < buttons.length && buttons[buttonId]; 47 | } 48 | 49 | public void setButtonId(final int buttonId) { 50 | this.buttonId = buttonId; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ToCursorAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2020 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 22 | import de.bwravencl.controllerbuddy.input.action.gui.CursorSensitivityEditorBuilder; 23 | import de.bwravencl.controllerbuddy.input.action.gui.MouseAxisEditorBuilder; 24 | import java.lang.constant.Constable; 25 | import java.text.MessageFormat; 26 | 27 | public abstract class ToCursorAction extends InvertableAction { 28 | 29 | private static final int DEFAULT_CURSOR_SENSITIVITY = 2000; 30 | 31 | @ActionProperty(label = "CURSOR_SENSITIVITY", editorBuilder = CursorSensitivityEditorBuilder.class, order = 11) 32 | int cursorSensitivity = DEFAULT_CURSOR_SENSITIVITY; 33 | 34 | transient float remainingD; 35 | 36 | @ActionProperty(label = "MOUSE_AXIS", editorBuilder = MouseAxisEditorBuilder.class, order = 10) 37 | private MouseAxis axis = MouseAxis.X; 38 | 39 | public MouseAxis getAxis() { 40 | return axis; 41 | } 42 | 43 | public int getCursorSensitivity() { 44 | return cursorSensitivity; 45 | } 46 | 47 | @Override 48 | public String getDescription(final Input input) { 49 | if (!isDescriptionEmpty()) { 50 | return super.getDescription(input); 51 | } 52 | 53 | return MessageFormat.format(Main.STRINGS.getString("MOUSE_AXIS_DIR"), axis.toString()); 54 | } 55 | 56 | void moveCursor(final Input input, float d) { 57 | d = invert ? -d : d; 58 | d += remainingD; 59 | 60 | final var roundedD = Math.round(d); 61 | if (roundedD == 0) { 62 | remainingD = d; 63 | return; 64 | } 65 | 66 | if (axis == MouseAxis.X) { 67 | input.setCursorDeltaX(input.getCursorDeltaX() + roundedD); 68 | } else { 69 | input.setCursorDeltaY(input.getCursorDeltaY() + roundedD); 70 | } 71 | 72 | remainingD = d - roundedD; 73 | } 74 | 75 | public void setAxis(final MouseAxis axis) { 76 | this.axis = axis; 77 | } 78 | 79 | public void setCursorSensitivity(final int cursorSensitivity) { 80 | this.cursorSensitivity = cursorSensitivity; 81 | } 82 | 83 | public enum MouseAxis { 84 | 85 | X("MOUSE_AXIS_X"), Y("MOUSE_AXIS_Y"); 86 | 87 | private final String label; 88 | 89 | MouseAxis(final String labelKey) { 90 | label = Main.STRINGS.getString(labelKey); 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | return label; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ToKeyAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.KeyStroke; 22 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 23 | import de.bwravencl.controllerbuddy.input.action.gui.ActivationEditorBuilder; 24 | import de.bwravencl.controllerbuddy.input.action.gui.KeystrokeEditorBuilder; 25 | import de.bwravencl.controllerbuddy.input.action.gui.LongPressEditorBuilder; 26 | import java.lang.constant.Constable; 27 | import java.text.MessageFormat; 28 | 29 | abstract class ToKeyAction extends ActivationIntervalAction 30 | implements IActivatableAction, ILongPressAction, IResetableAction { 31 | 32 | private transient Activatable activatable; 33 | 34 | @ActionProperty(label = "ACTIVATION", editorBuilder = ActivationEditorBuilder.class, order = 11) 35 | private Activation activation = Activation.REPEAT; 36 | 37 | @ActionProperty(label = "KEYSTROKE", editorBuilder = KeystrokeEditorBuilder.class, order = 10) 38 | private KeyStroke keystroke = new KeyStroke(); 39 | 40 | @ActionProperty(label = "LONG_PRESS", editorBuilder = LongPressEditorBuilder.class, order = 400) 41 | private boolean longPress = DEFAULT_LONG_PRESS; 42 | 43 | private transient boolean wasDown; 44 | 45 | @Override 46 | public Object clone() throws CloneNotSupportedException { 47 | final var toKeyAction = (ToKeyAction) super.clone(); 48 | toKeyAction.setKeystroke((KeyStroke) keystroke.clone()); 49 | 50 | return toKeyAction; 51 | } 52 | 53 | @Override 54 | public Activatable getActivatable() { 55 | return activatable; 56 | } 57 | 58 | @Override 59 | public Activation getActivation() { 60 | return activation; 61 | } 62 | 63 | @Override 64 | public String getDescription(final Input input) { 65 | if (!isDescriptionEmpty()) { 66 | return super.getDescription(input); 67 | } 68 | 69 | return MessageFormat.format(Main.STRINGS.getString("PRESS"), keystroke); 70 | } 71 | 72 | public KeyStroke getKeystroke() { 73 | return keystroke; 74 | } 75 | 76 | void handleAction(boolean hot, final Input input) { 77 | hot = handleActivationInterval(hot); 78 | 79 | if (activatable == Activatable.ALWAYS) { 80 | input.getDownUpKeyStrokes().add(keystroke); 81 | return; 82 | } 83 | 84 | switch (activation) { 85 | case REPEAT -> { 86 | final var downKeyStrokes = input.getDownKeyStrokes(); 87 | if (!hot) { 88 | if (wasDown) { 89 | downKeyStrokes.remove(keystroke); 90 | wasDown = false; 91 | } 92 | } else { 93 | downKeyStrokes.add(keystroke); 94 | wasDown = true; 95 | } 96 | } 97 | case SINGLE_IMMEDIATELY -> { 98 | if (!hot) { 99 | activatable = Activatable.YES; 100 | } else if (activatable == Activatable.YES) { 101 | activatable = Activatable.NO; 102 | input.getDownUpKeyStrokes().add(keystroke); 103 | } 104 | } 105 | case SINGLE_ON_RELEASE -> { 106 | if (hot) { 107 | if (activatable == Activatable.NO) { 108 | activatable = Activatable.YES; 109 | } else if (activatable == Activatable.DENIED_BY_OTHER_ACTION) { 110 | activatable = Activatable.NO; 111 | } 112 | } else if (activatable == Activatable.YES) { 113 | activatable = Activatable.NO; 114 | input.getDownUpKeyStrokes().add(keystroke); 115 | } 116 | } 117 | } 118 | } 119 | 120 | @Override 121 | public void init(final Input input) { 122 | super.init(input); 123 | IActivatableAction.super.init(input); 124 | } 125 | 126 | @Override 127 | public boolean isLongPress() { 128 | return longPress; 129 | } 130 | 131 | @Override 132 | public void reset(final Input input) { 133 | wasDown = false; 134 | } 135 | 136 | @Override 137 | public void setActivatable(final Activatable activatable) { 138 | this.activatable = activatable; 139 | } 140 | 141 | @Override 142 | public void setActivation(final Activation activation) { 143 | this.activation = activation; 144 | } 145 | 146 | public void setKeystroke(final KeyStroke keystroke) { 147 | this.keystroke = keystroke; 148 | } 149 | 150 | @Override 151 | public void setLongPress(final boolean longPress) { 152 | this.longPress = longPress; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ToMouseButtonAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 22 | import de.bwravencl.controllerbuddy.input.action.gui.ActivationEditorBuilder; 23 | import de.bwravencl.controllerbuddy.input.action.gui.LongPressEditorBuilder; 24 | import de.bwravencl.controllerbuddy.input.action.gui.MouseButtonEditorBuilder; 25 | import java.lang.constant.Constable; 26 | import java.text.MessageFormat; 27 | 28 | abstract class ToMouseButtonAction extends ActivationIntervalAction 29 | implements IActivatableAction, ILongPressAction { 30 | 31 | private static final int DEFAULT_MOUSE_BUTTON = 1; 32 | 33 | private transient Activatable activatable; 34 | 35 | @ActionProperty(label = "ACTIVATION", editorBuilder = ActivationEditorBuilder.class, order = 11) 36 | private Activation activation = Activation.REPEAT; 37 | 38 | private transient boolean initiator; 39 | 40 | @ActionProperty(label = "LONG_PRESS", editorBuilder = LongPressEditorBuilder.class, order = 400) 41 | private boolean longPress = DEFAULT_LONG_PRESS; 42 | 43 | @ActionProperty(label = "MOUSE_BUTTON", editorBuilder = MouseButtonEditorBuilder.class, order = 10) 44 | private int mouseButton = DEFAULT_MOUSE_BUTTON; 45 | 46 | @Override 47 | public Activatable getActivatable() { 48 | return activatable; 49 | } 50 | 51 | @Override 52 | public Activation getActivation() { 53 | return activation; 54 | } 55 | 56 | @Override 57 | public String getDescription(final Input input) { 58 | if (!isDescriptionEmpty()) { 59 | return super.getDescription(input); 60 | } 61 | 62 | return MessageFormat.format(Main.STRINGS.getString("MOUSE_BUTTON_NO"), mouseButton); 63 | } 64 | 65 | public int getMouseButton() { 66 | return mouseButton; 67 | } 68 | 69 | void handleAction(boolean hot, final Input input) { 70 | hot = handleActivationInterval(hot); 71 | 72 | if (activatable == Activatable.ALWAYS) { 73 | input.getDownUpMouseButtons().add(mouseButton); 74 | return; 75 | } 76 | 77 | switch (activation) { 78 | case REPEAT -> { 79 | final var downMouseButtons = input.getDownMouseButtons(); 80 | if (!hot) { 81 | if (initiator) { 82 | initiator = false; 83 | downMouseButtons.remove(mouseButton); 84 | } 85 | } else { 86 | initiator = true; 87 | downMouseButtons.add(mouseButton); 88 | } 89 | } 90 | case SINGLE_IMMEDIATELY -> { 91 | if (!hot) { 92 | activatable = Activatable.YES; 93 | } else if (activatable == Activatable.YES) { 94 | activatable = Activatable.NO; 95 | input.getDownUpMouseButtons().add(mouseButton); 96 | } 97 | } 98 | case SINGLE_ON_RELEASE -> { 99 | if (hot) { 100 | if (activatable == Activatable.NO) { 101 | activatable = Activatable.YES; 102 | } else if (activatable == Activatable.DENIED_BY_OTHER_ACTION) { 103 | activatable = Activatable.NO; 104 | } 105 | } else if (activatable == Activatable.YES) { 106 | activatable = Activatable.NO; 107 | input.getDownUpMouseButtons().add(mouseButton); 108 | } 109 | } 110 | } 111 | } 112 | 113 | @Override 114 | public void init(final Input input) { 115 | super.init(input); 116 | IActivatableAction.super.init(input); 117 | } 118 | 119 | @Override 120 | public boolean isLongPress() { 121 | return longPress; 122 | } 123 | 124 | @Override 125 | public void setActivatable(final Activatable activatable) { 126 | this.activatable = activatable; 127 | } 128 | 129 | @Override 130 | public void setActivation(final Activation activation) { 131 | this.activation = activation; 132 | } 133 | 134 | @Override 135 | public void setLongPress(final boolean longPress) { 136 | this.longPress = longPress; 137 | } 138 | 139 | public void setMouseButton(final int mouseButton) { 140 | this.mouseButton = mouseButton; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/ToScrollAction.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.action.annotation.ActionProperty; 22 | import de.bwravencl.controllerbuddy.input.action.gui.ClicksEditorBuilder; 23 | import java.lang.constant.Constable; 24 | import java.text.MessageFormat; 25 | import java.util.Locale; 26 | 27 | abstract class ToScrollAction extends InvertableAction { 28 | 29 | private static final int DEFAULT_CLICKS = 10; 30 | 31 | @ActionProperty(label = "CLICKS", editorBuilder = ClicksEditorBuilder.class, order = 10) 32 | int clicks = DEFAULT_CLICKS; 33 | 34 | transient float remainingD = 0f; 35 | 36 | public int getClicks() { 37 | return clicks; 38 | } 39 | 40 | @Override 41 | public String getDescription(final Input input) { 42 | if (!isDescriptionEmpty()) { 43 | return super.getDescription(input); 44 | } 45 | 46 | return MessageFormat.format(Main.STRINGS.getString("SCROLL_DIRECTION"), 47 | Main.STRINGS.getString(invert ? "DIRECTION_DOWN" : "DIRECTION_UP").toLowerCase(Locale.ROOT)); 48 | } 49 | 50 | void scroll(final Input input, float d) { 51 | d = invert ? -d : d; 52 | d += remainingD; 53 | 54 | final var roundedD = Math.round(d); 55 | if (roundedD == 0) { 56 | remainingD = d; 57 | return; 58 | } 59 | 60 | input.setScrollClicks(roundedD); 61 | remainingD = d - roundedD; 62 | } 63 | 64 | public void setClicks(final int clicks) { 65 | this.clicks = clicks; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/annotation/Action.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.annotation; 18 | 19 | import java.lang.annotation.ElementType; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.RetentionPolicy; 22 | import java.lang.annotation.Target; 23 | 24 | @Retention(RetentionPolicy.RUNTIME) 25 | @Target(ElementType.TYPE) 26 | public @interface Action { 27 | 28 | ActionCategory category(); 29 | 30 | String label(); 31 | 32 | int order(); 33 | 34 | enum ActionCategory { 35 | ALL, AXIS, BUTTON, BUTTON_AND_CYCLES, ON_SCREEN_KEYBOARD_MODE 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/annotation/ActionProperty.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.annotation; 18 | 19 | import de.bwravencl.controllerbuddy.input.action.gui.EditorBuilder; 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | @Retention(RetentionPolicy.RUNTIME) 26 | @Target(ElementType.FIELD) 27 | public @interface ActionProperty { 28 | 29 | Class editorBuilder(); 30 | 31 | String label(); 32 | 33 | int order(); 34 | 35 | String overrideFieldName() default ""; 36 | 37 | Class overrideFieldType() default Void.class; 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/ActionsEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.gui.Main; 21 | import de.bwravencl.controllerbuddy.input.action.ButtonToCycleAction; 22 | import de.bwravencl.controllerbuddy.input.action.IAction; 23 | import java.awt.event.ActionEvent; 24 | import java.io.Serial; 25 | import java.lang.reflect.InvocationTargetException; 26 | import java.text.MessageFormat; 27 | import javax.swing.AbstractAction; 28 | import javax.swing.JButton; 29 | import javax.swing.JPanel; 30 | 31 | public final class ActionsEditorBuilder extends EditorBuilder { 32 | 33 | public ActionsEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 34 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 35 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 36 | super(editActionsDialog, action, fieldName, fieldType); 37 | } 38 | 39 | @Override 40 | public void buildEditor(final JPanel parentPanel) { 41 | final var editActionsButton = new JButton(new EditActionsAction()); 42 | editActionsButton.setPreferredSize(Main.BUTTON_DIMENSION); 43 | parentPanel.add(editActionsButton); 44 | } 45 | 46 | private final class EditActionsAction extends AbstractAction { 47 | 48 | @Serial 49 | private static final long serialVersionUID = -6538021954760621595L; 50 | 51 | private EditActionsAction() { 52 | putValue(NAME, Main.STRINGS.getString("EDIT_ACTIONS_ACTION_NAME")); 53 | putValue(SHORT_DESCRIPTION, MessageFormat.format(Main.STRINGS.getString("EDIT_ACTIONS_ACTION_DESCRIPTION"), 54 | IAction.getLabel(action.getClass()))); 55 | } 56 | 57 | @Override 58 | public void actionPerformed(final ActionEvent e) { 59 | final var editComponentDialog = new EditActionsDialog(editActionsDialog, (ButtonToCycleAction) action); 60 | editComponentDialog.setVisible(true); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/ActivationEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.ButtonToCycleAction; 21 | import de.bwravencl.controllerbuddy.input.action.IAction; 22 | import de.bwravencl.controllerbuddy.input.action.IActivatableAction.Activation; 23 | import java.lang.reflect.InvocationTargetException; 24 | import javax.swing.JPanel; 25 | 26 | public final class ActivationEditorBuilder extends ArrayEditorBuilder { 27 | 28 | public ActivationEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 29 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 30 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 31 | super(editActionsDialog, action, fieldName, fieldType); 32 | } 33 | 34 | @Override 35 | public void buildEditor(final JPanel parentPanel) { 36 | final var cycleEditor = editActionsDialog.isCycleEditor(); 37 | 38 | if (cycleEditor) { 39 | initialValue = Activation.SINGLE_IMMEDIATELY; 40 | } 41 | 42 | super.buildEditor(parentPanel); 43 | 44 | if (cycleEditor) { 45 | comboBox.setEnabled(false); 46 | } 47 | } 48 | 49 | @Override 50 | Activation[] getValues() { 51 | if (action instanceof ButtonToCycleAction) { 52 | return new Activation[] { Activation.SINGLE_IMMEDIATELY, Activation.SINGLE_ON_RELEASE }; 53 | } 54 | 55 | return Activation.values(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/ActivationIntervalEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2023 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.gui.Main; 21 | import de.bwravencl.controllerbuddy.input.action.IAction; 22 | import java.lang.reflect.InvocationTargetException; 23 | import javax.swing.JPanel; 24 | import javax.swing.JSpinner; 25 | import javax.swing.text.DefaultFormatter; 26 | 27 | public final class ActivationIntervalEditorBuilder extends NumberEditorBuilder { 28 | 29 | public ActivationIntervalEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 30 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 31 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 32 | super(editActionsDialog, action, fieldName, fieldType); 33 | } 34 | 35 | @Override 36 | public void buildEditor(final JPanel parentPanel) { 37 | super.buildEditor(parentPanel); 38 | 39 | final var editor = new JSpinner.NumberEditor(spinner, "# " + Main.STRINGS.getString("MILLISECOND_SYMBOL")); 40 | spinner.setEditor(editor); 41 | textField = editor.getTextField(); 42 | textField.setColumns(6); 43 | 44 | final var formatter = (DefaultFormatter) textField.getFormatter(); 45 | formatter.setCommitsOnValidEdit(true); 46 | } 47 | 48 | @Override 49 | Comparable getMaximum() { 50 | return 10_000; 51 | } 52 | 53 | @Override 54 | Comparable getMinimum() { 55 | return 0; 56 | } 57 | 58 | @Override 59 | Number getStepSize() { 60 | return 10; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/ArrayEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import java.awt.event.ActionEvent; 22 | import java.io.Serial; 23 | import java.lang.reflect.InvocationTargetException; 24 | import java.lang.reflect.Method; 25 | import java.util.Arrays; 26 | import java.util.logging.Level; 27 | import java.util.logging.Logger; 28 | import javax.swing.JComboBox; 29 | import javax.swing.JPanel; 30 | 31 | abstract class ArrayEditorBuilder extends EditorBuilder { 32 | 33 | private static final Logger LOGGER = Logger.getLogger(ArrayEditorBuilder.class.getName()); 34 | 35 | JComboBox comboBox; 36 | 37 | ArrayEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, final String fieldName, 38 | final Class fieldType) throws SecurityException, NoSuchMethodException, IllegalAccessException, 39 | IllegalArgumentException, InvocationTargetException { 40 | super(editActionsDialog, action, fieldName, fieldType); 41 | } 42 | 43 | @Override 44 | public void buildEditor(final JPanel parentPanel) { 45 | final var values = getValues(); 46 | 47 | comboBox = new JComboBox<>(values); 48 | comboBox.setAction(new JComboBoxSetPropertyAction(action, setterMethod)); 49 | if (initialValue != null && Arrays.stream(values).noneMatch(initialValue::equals)) { 50 | comboBox.setSelectedItem(null); 51 | } else { 52 | comboBox.setSelectedItem(initialValue); 53 | } 54 | 55 | parentPanel.add(comboBox); 56 | } 57 | 58 | abstract T[] getValues(); 59 | 60 | private static final class JComboBoxSetPropertyAction extends PropertySetterAction { 61 | 62 | @Serial 63 | private static final long serialVersionUID = 1938012378184518954L; 64 | 65 | JComboBoxSetPropertyAction(final IAction action, final Method setterMethod) { 66 | super(action, setterMethod); 67 | } 68 | 69 | @Override 70 | public void actionPerformed(final ActionEvent e) { 71 | try { 72 | setterMethod.invoke(action, ((JComboBox) e.getSource()).getSelectedItem()); 73 | } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) { 74 | LOGGER.log(Level.SEVERE, e1.getMessage(), e1); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/AxisValueEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import java.lang.reflect.InvocationTargetException; 22 | 23 | public class AxisValueEditorBuilder extends NumberEditorBuilder { 24 | 25 | public AxisValueEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 26 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 27 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 28 | super(editActionsDialog, action, fieldName, fieldType); 29 | } 30 | 31 | @Override 32 | Comparable getMaximum() { 33 | return 1f; 34 | } 35 | 36 | @Override 37 | Comparable getMinimum() { 38 | return -1f; 39 | } 40 | 41 | @Override 42 | Number getStepSize() { 43 | return 0.01f; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/BooleanEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import java.awt.event.ActionEvent; 22 | import java.io.Serial; 23 | import java.lang.reflect.InvocationTargetException; 24 | import java.lang.reflect.Method; 25 | import java.util.logging.Level; 26 | import java.util.logging.Logger; 27 | import javax.swing.JCheckBox; 28 | import javax.swing.JPanel; 29 | 30 | public class BooleanEditorBuilder extends EditorBuilder { 31 | 32 | private static final Logger LOGGER = Logger.getLogger(BooleanEditorBuilder.class.getName()); 33 | 34 | JCheckBox checkBox; 35 | 36 | public BooleanEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 37 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 38 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 39 | super(editActionsDialog, action, fieldName, fieldType); 40 | } 41 | 42 | @Override 43 | public void buildEditor(final JPanel parentPanel) { 44 | checkBox = new JCheckBox(new JCheckBoxSetPropertyAction(action, setterMethod)); 45 | checkBox.setSelected((boolean) initialValue); 46 | parentPanel.add(checkBox); 47 | } 48 | 49 | private static final class JCheckBoxSetPropertyAction extends PropertySetterAction { 50 | 51 | @Serial 52 | private static final long serialVersionUID = -33052386834598414L; 53 | 54 | private JCheckBoxSetPropertyAction(final IAction action, final Method setterMethod) { 55 | super(action, setterMethod); 56 | } 57 | 58 | @Override 59 | public void actionPerformed(final ActionEvent e) { 60 | try { 61 | final var selected = ((JCheckBox) e.getSource()).isSelected(); 62 | setterMethod.invoke(action, selected); 63 | } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) { 64 | LOGGER.log(Level.SEVERE, e1.getMessage(), e1); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/ButtonEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.action.IAction; 22 | import java.io.Serial; 23 | import java.lang.reflect.InvocationTargetException; 24 | import javax.swing.JFormattedTextField; 25 | import javax.swing.JFormattedTextField.AbstractFormatter; 26 | import javax.swing.JPanel; 27 | import javax.swing.text.DefaultFormatter; 28 | import javax.swing.text.DefaultFormatterFactory; 29 | 30 | public final class ButtonEditorBuilder extends NumberEditorBuilder { 31 | 32 | public ButtonEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 33 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 34 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 35 | super(editActionsDialog, action, fieldName, fieldType); 36 | } 37 | 38 | @Override 39 | public void buildEditor(final JPanel parentPanel) { 40 | super.buildEditor(parentPanel); 41 | 42 | final var formatterFactory = new ZeroBasedFormatterFactory(); 43 | textField.setFormatterFactory(formatterFactory); 44 | 45 | final var formatter = (DefaultFormatter) textField.getFormatter(); 46 | formatter.setCommitsOnValidEdit(true); 47 | } 48 | 49 | @Override 50 | Comparable getMaximum() { 51 | return Input.MAX_N_BUTTONS - 1; 52 | } 53 | 54 | @Override 55 | Comparable getMinimum() { 56 | return 0; 57 | } 58 | 59 | @Override 60 | Number getStepSize() { 61 | return 1; 62 | } 63 | 64 | private static final class ZeroBasedFormatter extends DefaultFormatter { 65 | 66 | @Serial 67 | private static final long serialVersionUID = -7229427356426148291L; 68 | 69 | @Override 70 | public Object stringToValue(final String text) { 71 | if (text == null || text.isBlank()) { 72 | return null; 73 | } 74 | 75 | return Integer.parseInt(text) - 1; 76 | } 77 | 78 | @Override 79 | public String valueToString(final Object value) { 80 | return Integer.toString((int) value + 1); 81 | } 82 | } 83 | 84 | private static final class ZeroBasedFormatterFactory extends DefaultFormatterFactory { 85 | 86 | @Serial 87 | private static final long serialVersionUID = -7273246342105584827L; 88 | 89 | @Override 90 | public AbstractFormatter getFormatter(final JFormattedTextField tf) { 91 | return new ZeroBasedFormatter(); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/ClicksEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import java.lang.reflect.InvocationTargetException; 22 | 23 | public final class ClicksEditorBuilder extends NumberEditorBuilder { 24 | 25 | public ClicksEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 26 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 27 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 28 | super(editActionsDialog, action, fieldName, fieldType); 29 | } 30 | 31 | @Override 32 | Comparable getMaximum() { 33 | return 1000; 34 | } 35 | 36 | @Override 37 | Comparable getMinimum() { 38 | return 1; 39 | } 40 | 41 | @Override 42 | Number getStepSize() { 43 | return 1; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/CursorSensitivityEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import java.lang.reflect.InvocationTargetException; 22 | 23 | public final class CursorSensitivityEditorBuilder extends NumberEditorBuilder { 24 | 25 | public CursorSensitivityEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 26 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 27 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 28 | super(editActionsDialog, action, fieldName, fieldType); 29 | } 30 | 31 | @Override 32 | Comparable getMaximum() { 33 | return 100_000; 34 | } 35 | 36 | @Override 37 | Comparable getMinimum() { 38 | return 1; 39 | } 40 | 41 | @Override 42 | Number getStepSize() { 43 | return 1; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/DeadZoneEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import java.lang.reflect.InvocationTargetException; 22 | 23 | public final class DeadZoneEditorBuilder extends NumberEditorBuilder { 24 | 25 | public DeadZoneEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 26 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 27 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 28 | super(editActionsDialog, action, fieldName, fieldType); 29 | } 30 | 31 | @Override 32 | Comparable getMaximum() { 33 | return 1f; 34 | } 35 | 36 | @Override 37 | Comparable getMinimum() { 38 | return 0f; 39 | } 40 | 41 | @Override 42 | Number getStepSize() { 43 | return 0.01f; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/DetentValueEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import java.awt.event.ActionEvent; 22 | import java.io.Serial; 23 | import java.lang.reflect.InvocationTargetException; 24 | import java.util.logging.Level; 25 | import java.util.logging.Logger; 26 | import javax.swing.AbstractAction; 27 | import javax.swing.JCheckBox; 28 | import javax.swing.JPanel; 29 | 30 | public final class DetentValueEditorBuilder extends NumberEditorBuilder { 31 | 32 | private static final Logger LOGGER = Logger.getLogger(DetentValueEditorBuilder.class.getName()); 33 | 34 | public DetentValueEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 35 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 36 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 37 | super(editActionsDialog, action, fieldName, fieldType); 38 | } 39 | 40 | @Override 41 | public void buildEditor(final JPanel parentPanel) { 42 | final boolean enabled; 43 | if (initialValue == null) { 44 | enabled = false; 45 | initialValue = 0f; 46 | } else { 47 | enabled = true; 48 | } 49 | 50 | super.buildEditor(parentPanel); 51 | spinner.setEnabled(enabled); 52 | 53 | final var checkBox = new JCheckBox(new AbstractAction() { 54 | 55 | @Serial 56 | private static final long serialVersionUID = 3326369393786088402L; 57 | 58 | @Override 59 | public void actionPerformed(final ActionEvent e) { 60 | final var selected = ((JCheckBox) e.getSource()).isSelected(); 61 | 62 | spinner.setEnabled(selected); 63 | 64 | final Float value; 65 | if (selected) { 66 | value = roundFloat((Float) spinner.getValue()); 67 | } else { 68 | value = null; 69 | } 70 | 71 | try { 72 | setterMethod.invoke(action, value); 73 | } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) { 74 | LOGGER.log(Level.SEVERE, e1.getMessage(), e1); 75 | } 76 | 77 | spinner.setEnabled(selected); 78 | } 79 | }); 80 | checkBox.setSelected(enabled); 81 | parentPanel.add(checkBox, 1); 82 | } 83 | 84 | @Override 85 | Comparable getMaximum() { 86 | return 1f; 87 | } 88 | 89 | @Override 90 | Comparable getMinimum() { 91 | return -1f; 92 | } 93 | 94 | @Override 95 | Number getStepSize() { 96 | return 0.05f; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/DirectionEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.gui.OnScreenKeyboard.Direction; 21 | import de.bwravencl.controllerbuddy.input.action.IAction; 22 | import java.lang.reflect.InvocationTargetException; 23 | 24 | public final class DirectionEditorBuilder extends ArrayEditorBuilder { 25 | 26 | public DirectionEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 27 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 28 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 29 | super(editActionsDialog, action, fieldName, fieldType); 30 | } 31 | 32 | @Override 33 | Direction[] getValues() { 34 | return Direction.values(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/EditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.Mode; 22 | import de.bwravencl.controllerbuddy.input.action.IAction; 23 | import java.io.NotSerializableException; 24 | import java.io.ObjectInputStream; 25 | import java.io.ObjectOutputStream; 26 | import java.io.Serial; 27 | import java.lang.reflect.InvocationTargetException; 28 | import java.lang.reflect.Method; 29 | import javax.swing.AbstractAction; 30 | import javax.swing.JPanel; 31 | 32 | public abstract class EditorBuilder { 33 | 34 | protected final IAction action; 35 | 36 | protected final EditActionsDialog editActionsDialog; 37 | 38 | protected final Method setterMethod; 39 | 40 | protected Object initialValue; 41 | 42 | EditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, final String fieldName, 43 | final Class fieldType) throws SecurityException, NoSuchMethodException, IllegalAccessException, 44 | IllegalArgumentException, InvocationTargetException { 45 | this.editActionsDialog = editActionsDialog; 46 | this.action = action; 47 | 48 | final var clazz = action.getClass(); 49 | 50 | final var fieldNameChars = fieldName.toCharArray(); 51 | fieldNameChars[0] = Character.toUpperCase(fieldNameChars[0]); 52 | final var capitalizedFieldName = String.valueOf(fieldNameChars); 53 | 54 | setterMethod = clazz.getMethod("set" + capitalizedFieldName, fieldType); 55 | 56 | final var getterMethodPrefix = fieldType == boolean.class || fieldType == Boolean.class ? "is" : "get"; 57 | final var modeProperty = fieldType == Mode.class; 58 | 59 | final var getterParams = modeProperty ? new Class[] { Input.class } : null; 60 | final var getterMethod = clazz.getMethod(getterMethodPrefix + capitalizedFieldName, getterParams); 61 | 62 | final var getterArgs = modeProperty ? new Object[] { editActionsDialog.getInput() } : null; 63 | initialValue = getterMethod.invoke(action, getterArgs); 64 | } 65 | 66 | public abstract void buildEditor(final JPanel parentPanel); 67 | 68 | abstract static class PropertySetter { 69 | 70 | final IAction action; 71 | 72 | final Method setterMethod; 73 | 74 | PropertySetter(final IAction action, final Method setterMethod) { 75 | this.action = action; 76 | this.setterMethod = setterMethod; 77 | } 78 | } 79 | 80 | abstract static class PropertySetterAction extends AbstractAction { 81 | 82 | @Serial 83 | private static final long serialVersionUID = 4141747329971720525L; 84 | 85 | @SuppressWarnings({ "serial", "RedundantSuppression" }) 86 | final IAction action; 87 | 88 | @SuppressWarnings({ "serial", "RedundantSuppression" }) 89 | final Method setterMethod; 90 | 91 | PropertySetterAction(final IAction action, final Method setterMethod) { 92 | this.action = action; 93 | this.setterMethod = setterMethod; 94 | } 95 | 96 | @Serial 97 | private void readObject(final ObjectInputStream ignoredStream) throws NotSerializableException { 98 | throw new NotSerializableException(PropertySetterAction.class.getName()); 99 | } 100 | 101 | @Serial 102 | private void writeObject(final ObjectOutputStream ignoredStream) throws NotSerializableException { 103 | throw new NotSerializableException(PropertySetterAction.class.getName()); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/ExponentEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import com.formdev.flatlaf.ui.FlatRoundBorder; 20 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 21 | import de.bwravencl.controllerbuddy.gui.Main; 22 | import de.bwravencl.controllerbuddy.input.action.IAction; 23 | import java.awt.Color; 24 | import java.awt.Dimension; 25 | import java.awt.Graphics; 26 | import java.io.Serial; 27 | import java.lang.reflect.InvocationTargetException; 28 | import java.util.Arrays; 29 | import java.util.function.Consumer; 30 | import javax.swing.Box; 31 | import javax.swing.JComponent; 32 | import javax.swing.JPanel; 33 | import javax.swing.UIManager; 34 | 35 | public final class ExponentEditorBuilder extends NumberEditorBuilder { 36 | 37 | public ExponentEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 38 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 39 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 40 | super(editActionsDialog, action, fieldName, fieldType); 41 | } 42 | 43 | @Override 44 | public void buildEditor(final JPanel parentPanel) { 45 | super.buildEditor(parentPanel); 46 | 47 | parentPanel.add(Box.createHorizontalStrut(Main.DEFAULT_HGAP)); 48 | 49 | final var powerFunctionPlotter = new PowerFunctionPlotter((float) initialValue); 50 | parentPanel.add(powerFunctionPlotter); 51 | 52 | Arrays.stream(spinner.getChangeListeners()) 53 | .filter(changeListener -> changeListener instanceof JSpinnerSetPropertyChangeListener).findFirst() 54 | .ifPresent(changeListener -> ((JSpinnerSetPropertyChangeListener) changeListener) 55 | .setValueConsumer(powerFunctionPlotter)); 56 | } 57 | 58 | @Override 59 | Comparable getMaximum() { 60 | return 10f; 61 | } 62 | 63 | @Override 64 | Comparable getMinimum() { 65 | return 0.1f; 66 | } 67 | 68 | @Override 69 | Number getStepSize() { 70 | return 0.1f; 71 | } 72 | 73 | private static final class PowerFunctionPlotter extends JComponent implements Consumer { 74 | 75 | @Serial 76 | private static final long serialVersionUID = 5075932419255249325L; 77 | 78 | private final Color defaultBackground; 79 | 80 | private final Color defaultForeground; 81 | 82 | private float power; 83 | 84 | private PowerFunctionPlotter(final float power) { 85 | this.power = power; 86 | 87 | defaultBackground = UIManager.getColor("Button.background"); 88 | defaultForeground = UIManager.getColor("Button.foreground"); 89 | 90 | setBorder(new FlatRoundBorder()); 91 | setPreferredSize(new Dimension(48, 48)); 92 | } 93 | 94 | @Override 95 | public void accept(final Object t) { 96 | if (t instanceof final Float floatValue) { 97 | power = floatValue; 98 | repaint(); 99 | } 100 | } 101 | 102 | private int calculateY(final int x, final int plotWidth, final int plotHeight) { 103 | return plotHeight - 1 104 | - (x == 0 ? 0 : (int) (plotHeight / Math.pow((double) (plotWidth - 1) / (double) x, power))); 105 | } 106 | 107 | @Override 108 | public void paintComponent(final Graphics g) { 109 | super.paintComponent(g); 110 | 111 | final var insets = getInsets(); 112 | 113 | final var plotWidth = getWidth() - (insets.left + insets.right); 114 | final var plotHeight = getHeight() - (insets.bottom + insets.top); 115 | 116 | g.setColor(defaultBackground); 117 | g.fillRect(insets.left, insets.top, plotWidth, plotHeight); 118 | 119 | g.setColor(defaultForeground); 120 | 121 | for (var x1 = 0; x1 < plotWidth - 1; x1++) { 122 | final var y1 = calculateY(x1, plotWidth, plotHeight); 123 | final var x2 = x1 + 1; 124 | final var y2 = calculateY(x2, plotWidth, plotHeight); 125 | 126 | g.drawLine(x1 + insets.left, y1 + insets.bottom, x2 + insets.left, y2 + insets.bottom); 127 | } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/LockKeyEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.LockKey; 21 | import de.bwravencl.controllerbuddy.input.action.IAction; 22 | import java.lang.reflect.InvocationTargetException; 23 | 24 | public final class LockKeyEditorBuilder extends ArrayEditorBuilder { 25 | 26 | public LockKeyEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 27 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 28 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 29 | super(editActionsDialog, action, fieldName, fieldType); 30 | } 31 | 32 | @Override 33 | LockKey[] getValues() { 34 | return LockKey.LOCK_KEYS.toArray(LockKey[]::new); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/LongPressEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import java.lang.reflect.InvocationTargetException; 22 | import javax.swing.JPanel; 23 | 24 | public final class LongPressEditorBuilder extends BooleanEditorBuilder { 25 | 26 | public LongPressEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 27 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 28 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 29 | super(editActionsDialog, action, fieldName, fieldType); 30 | } 31 | 32 | @Override 33 | public void buildEditor(final JPanel parentPanel) { 34 | final var cycleEditor = editActionsDialog.isCycleEditor(); 35 | 36 | if (cycleEditor) { 37 | initialValue = false; 38 | } 39 | 40 | super.buildEditor(parentPanel); 41 | 42 | if (cycleEditor) { 43 | checkBox.setEnabled(false); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/MaxAxisValueEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import java.lang.reflect.InvocationTargetException; 22 | 23 | public final class MaxAxisValueEditorBuilder extends AxisValueEditorBuilder { 24 | 25 | public MaxAxisValueEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 26 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 27 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 28 | super(editActionsDialog, action, fieldName, fieldType); 29 | } 30 | 31 | @Override 32 | Comparable getMinimum() { 33 | return 0f; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/MaxRelativeSpeedEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import java.lang.reflect.InvocationTargetException; 22 | 23 | public final class MaxRelativeSpeedEditorBuilder extends NumberEditorBuilder { 24 | 25 | public MaxRelativeSpeedEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 26 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 27 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 28 | super(editActionsDialog, action, fieldName, fieldType); 29 | } 30 | 31 | @Override 32 | Comparable getMaximum() { 33 | return 100f; 34 | } 35 | 36 | @Override 37 | Comparable getMinimum() { 38 | return 0.1f; 39 | } 40 | 41 | @Override 42 | Number getStepSize() { 43 | return 0.01f; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/MinAxisValueEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import java.lang.reflect.InvocationTargetException; 22 | 23 | public final class MinAxisValueEditorBuilder extends AxisValueEditorBuilder { 24 | 25 | public MinAxisValueEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 26 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 27 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 28 | super(editActionsDialog, action, fieldName, fieldType); 29 | } 30 | 31 | @Override 32 | Comparable getMaximum() { 33 | return 0f; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/ModeEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.gui.OnScreenKeyboard; 21 | import de.bwravencl.controllerbuddy.input.Mode; 22 | import de.bwravencl.controllerbuddy.input.Profile; 23 | import de.bwravencl.controllerbuddy.input.action.IAction; 24 | import java.lang.reflect.InvocationTargetException; 25 | import java.util.stream.Collectors; 26 | 27 | public final class ModeEditorBuilder extends ArrayEditorBuilder { 28 | 29 | public ModeEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, final String fieldName, 30 | final Class fieldType) throws SecurityException, NoSuchMethodException, IllegalAccessException, 31 | IllegalArgumentException, InvocationTargetException { 32 | super(editActionsDialog, action, fieldName, fieldType); 33 | } 34 | 35 | @Override 36 | Mode[] getValues() { 37 | final var profile = editActionsDialog.getInput().getProfile(); 38 | 39 | final var modes = profile.getModes().stream().filter(m -> !Profile.DEFAULT_MODE.equals(m)) 40 | .collect(Collectors.toList()); 41 | 42 | if (!profile.getModes().contains(OnScreenKeyboard.ON_SCREEN_KEYBOARD_MODE)) { 43 | modes.add(OnScreenKeyboard.ON_SCREEN_KEYBOARD_MODE); 44 | } 45 | 46 | return modes.toArray(Mode[]::new); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/MouseAxisEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import de.bwravencl.controllerbuddy.input.action.ToCursorAction.MouseAxis; 22 | import java.lang.reflect.InvocationTargetException; 23 | 24 | public final class MouseAxisEditorBuilder extends ArrayEditorBuilder { 25 | 26 | public MouseAxisEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 27 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 28 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 29 | super(editActionsDialog, action, fieldName, fieldType); 30 | } 31 | 32 | @Override 33 | MouseAxis[] getValues() { 34 | return MouseAxis.values(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/MouseButtonEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import java.lang.reflect.InvocationTargetException; 22 | 23 | public final class MouseButtonEditorBuilder extends NumberEditorBuilder { 24 | 25 | public MouseButtonEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 26 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 27 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 28 | super(editActionsDialog, action, fieldName, fieldType); 29 | } 30 | 31 | @Override 32 | Comparable getMaximum() { 33 | return 3; 34 | } 35 | 36 | @Override 37 | Comparable getMinimum() { 38 | return 1; 39 | } 40 | 41 | @Override 42 | Number getStepSize() { 43 | return 1; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/NumberEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.action.IAction; 21 | import java.lang.reflect.InvocationTargetException; 22 | import java.lang.reflect.Method; 23 | import java.math.BigDecimal; 24 | import java.math.RoundingMode; 25 | import java.util.function.Consumer; 26 | import java.util.logging.Level; 27 | import java.util.logging.Logger; 28 | import javax.swing.JFormattedTextField; 29 | import javax.swing.JPanel; 30 | import javax.swing.JSpinner; 31 | import javax.swing.SpinnerNumberModel; 32 | import javax.swing.event.ChangeEvent; 33 | import javax.swing.event.ChangeListener; 34 | import javax.swing.text.DefaultFormatter; 35 | 36 | abstract class NumberEditorBuilder extends EditorBuilder { 37 | 38 | private static final int FLOAT_ROUNDING_DECIMALS = 3; 39 | 40 | private static final Logger LOGGER = Logger.getLogger(NumberEditorBuilder.class.getName()); 41 | 42 | JSpinner spinner; 43 | 44 | JFormattedTextField textField; 45 | 46 | NumberEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, final String fieldName, 47 | final Class fieldType) throws SecurityException, NoSuchMethodException, IllegalAccessException, 48 | IllegalArgumentException, InvocationTargetException { 49 | super(editActionsDialog, action, fieldName, fieldType); 50 | } 51 | 52 | static float roundFloat(final Float value) { 53 | return new BigDecimal(value.toString()).setScale(FLOAT_ROUNDING_DECIMALS, RoundingMode.HALF_UP).floatValue(); 54 | } 55 | 56 | @Override 57 | public void buildEditor(final JPanel parentPanel) { 58 | final var model = new SpinnerNumberModel((Number) initialValue, getMinimum(), getMaximum(), getStepSize()); 59 | spinner = new JSpinner(model); 60 | 61 | final var editor = spinner.getEditor(); 62 | textField = ((JSpinner.DefaultEditor) editor).getTextField(); 63 | textField.setColumns(4); 64 | 65 | final var formatter = (DefaultFormatter) textField.getFormatter(); 66 | formatter.setCommitsOnValidEdit(true); 67 | 68 | spinner.addChangeListener(new JSpinnerSetPropertyChangeListener(action, setterMethod)); 69 | 70 | parentPanel.add(spinner); 71 | } 72 | 73 | abstract Comparable getMaximum(); 74 | 75 | abstract Comparable getMinimum(); 76 | 77 | abstract Number getStepSize(); 78 | 79 | static final class JSpinnerSetPropertyChangeListener extends PropertySetter implements ChangeListener { 80 | 81 | private Consumer valueConsumer; 82 | 83 | private JSpinnerSetPropertyChangeListener(final IAction action, final Method setterMethod) { 84 | super(action, setterMethod); 85 | } 86 | 87 | void setValueConsumer(final Consumer valueConsumer) { 88 | this.valueConsumer = valueConsumer; 89 | } 90 | 91 | @Override 92 | public void stateChanged(final ChangeEvent e) { 93 | try { 94 | var value = ((JSpinner) e.getSource()).getValue(); 95 | 96 | if (value instanceof final Float floatValue) { 97 | value = roundFloat(floatValue); 98 | } 99 | 100 | setterMethod.invoke(action, value); 101 | 102 | if (valueConsumer != null) { 103 | valueConsumer.accept(value); 104 | } 105 | } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) { 106 | LOGGER.log(Level.SEVERE, e1.getMessage(), e1); 107 | } 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/StringEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2020 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.gui.GuiUtils; 21 | import de.bwravencl.controllerbuddy.input.action.IAction; 22 | import java.awt.EventQueue; 23 | import java.awt.event.ActionEvent; 24 | import java.awt.event.ActionListener; 25 | import java.awt.event.FocusEvent; 26 | import java.awt.event.FocusListener; 27 | import java.lang.reflect.InvocationTargetException; 28 | import java.lang.reflect.Method; 29 | import java.util.logging.Level; 30 | import java.util.logging.Logger; 31 | import javax.swing.JPanel; 32 | import javax.swing.JTextField; 33 | import javax.swing.event.DocumentEvent; 34 | import javax.swing.event.DocumentListener; 35 | 36 | public final class StringEditorBuilder extends EditorBuilder { 37 | 38 | private static final Logger LOGGER = Logger.getLogger(StringEditorBuilder.class.getName()); 39 | 40 | public StringEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 41 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 42 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 43 | super(editActionsDialog, action, fieldName, fieldType); 44 | } 45 | 46 | @Override 47 | public void buildEditor(final JPanel parentPanel) { 48 | final var textField = GuiUtils.createTextFieldWithMenu((String) initialValue, 17); 49 | textField.setCaretPosition(0); 50 | 51 | final var textFieldPropertySetter = new TextFieldPropertySetter(textField, action, setterMethod); 52 | textField.addActionListener(textFieldPropertySetter); 53 | textField.addFocusListener(textFieldPropertySetter); 54 | textField.getDocument().addDocumentListener(textFieldPropertySetter); 55 | 56 | parentPanel.add(textField); 57 | } 58 | 59 | private static class TextFieldPropertySetter extends PropertySetter 60 | implements ActionListener, DocumentListener, FocusListener { 61 | 62 | private final JTextField textField; 63 | 64 | private TextFieldPropertySetter(final JTextField textField, final IAction action, 65 | final Method setterMethod) { 66 | super(action, setterMethod); 67 | 68 | this.textField = textField; 69 | } 70 | 71 | @Override 72 | public void actionPerformed(final ActionEvent e) { 73 | setString(true); 74 | } 75 | 76 | @Override 77 | public void changedUpdate(final DocumentEvent e) { 78 | setString(false); 79 | } 80 | 81 | @Override 82 | public void focusGained(final FocusEvent e) { 83 | } 84 | 85 | @Override 86 | public void focusLost(final FocusEvent e) { 87 | setString(true); 88 | } 89 | 90 | @Override 91 | public void insertUpdate(final DocumentEvent e) { 92 | setString(false); 93 | } 94 | 95 | @Override 96 | public void removeUpdate(final DocumentEvent e) { 97 | setString(false); 98 | } 99 | 100 | private void setString(final boolean updateTextField) { 101 | var text = textField.getText(); 102 | 103 | if (text != null && !text.isEmpty()) { 104 | final var strippedText = text.strip(); 105 | 106 | if (updateTextField && !strippedText.equals(text)) { 107 | EventQueue.invokeLater(() -> textField.setText(strippedText)); 108 | } 109 | 110 | text = strippedText; 111 | } 112 | 113 | try { 114 | setterMethod.invoke(action, text); 115 | } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 116 | LOGGER.log(Level.SEVERE, e.getMessage(), e); 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/input/action/gui/VirtualAxisEditorBuilder.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.input.action.gui; 18 | 19 | import de.bwravencl.controllerbuddy.gui.EditActionsDialog; 20 | import de.bwravencl.controllerbuddy.input.Input.VirtualAxis; 21 | import de.bwravencl.controllerbuddy.input.action.IAction; 22 | import java.lang.reflect.InvocationTargetException; 23 | 24 | public final class VirtualAxisEditorBuilder extends ArrayEditorBuilder { 25 | 26 | public VirtualAxisEditorBuilder(final EditActionsDialog editActionsDialog, final IAction action, 27 | final String fieldName, final Class fieldType) throws SecurityException, NoSuchMethodException, 28 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 29 | super(editActionsDialog, action, fieldName, fieldType); 30 | } 31 | 32 | @Override 33 | VirtualAxis[] getValues() { 34 | return VirtualAxis.values(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/json/ActionTypeAdapter.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.json; 18 | 19 | import com.google.gson.JsonDeserializationContext; 20 | import com.google.gson.JsonDeserializer; 21 | import com.google.gson.JsonElement; 22 | import com.google.gson.JsonObject; 23 | import com.google.gson.JsonParseException; 24 | import com.google.gson.JsonSerializationContext; 25 | import com.google.gson.JsonSerializer; 26 | import de.bwravencl.controllerbuddy.input.action.IAction; 27 | import de.bwravencl.controllerbuddy.input.action.NullAction; 28 | import java.lang.reflect.ParameterizedType; 29 | import java.lang.reflect.Type; 30 | import java.util.HashSet; 31 | import java.util.Set; 32 | import java.util.logging.Level; 33 | import java.util.logging.Logger; 34 | 35 | public final class ActionTypeAdapter implements JsonSerializer>, JsonDeserializer> { 36 | 37 | private static final Logger LOGGER = Logger.getLogger(ActionTypeAdapter.class.getName()); 38 | 39 | private static final String PROPERTY_DATA = "data"; 40 | 41 | private static final String PROPERTY_TYPE = "type"; 42 | 43 | private final Set unknownActionClasses = new HashSet<>(); 44 | 45 | private static JsonElement get(final JsonObject wrapper, final String memberName) { 46 | final var jsonElement = wrapper.get(memberName); 47 | if (jsonElement == null) { 48 | throw new JsonParseException( 49 | "No member '" + memberName + "' found in what was expected to be an interface wrapper"); 50 | } 51 | 52 | return jsonElement; 53 | } 54 | 55 | @Override 56 | public IAction deserialize(final JsonElement json, Type typeOfT, final JsonDeserializationContext context) 57 | throws JsonParseException { 58 | final var wrapper = json.getAsJsonObject(); 59 | final var typeName = get(wrapper, PROPERTY_TYPE); 60 | final var typeNameString = typeName.getAsString(); 61 | final var data = get(wrapper, PROPERTY_DATA); 62 | 63 | try { 64 | final var actualType = Class.forName(typeNameString); 65 | return context.deserialize(data, actualType); 66 | } catch (final ClassNotFoundException e) { 67 | if (typeOfT instanceof final ParameterizedType parameterizedType) { 68 | typeOfT = parameterizedType.getRawType(); 69 | } 70 | 71 | if (typeOfT == IAction.class) { 72 | LOGGER.log(Level.WARNING, "Action class '" + typeNameString + "' not found, substituting with '" 73 | + NullAction.class.getSimpleName() + "'"); 74 | unknownActionClasses.add(typeNameString); 75 | 76 | return new NullAction(); 77 | } 78 | 79 | throw new JsonParseException(e); 80 | } 81 | } 82 | 83 | public Set getUnknownActionClasses() { 84 | return unknownActionClasses; 85 | } 86 | 87 | @Override 88 | public JsonElement serialize(final IAction src, final Type typeOfSrc, final JsonSerializationContext context) { 89 | final var wrapper = new JsonObject(); 90 | wrapper.addProperty(PROPERTY_TYPE, src.getClass().getName()); 91 | wrapper.add(PROPERTY_DATA, context.serialize(src)); 92 | 93 | return wrapper; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/json/ColorTypeAdapter.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2021 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.json; 18 | 19 | import com.google.gson.JsonDeserializationContext; 20 | import com.google.gson.JsonDeserializer; 21 | import com.google.gson.JsonElement; 22 | import com.google.gson.JsonParseException; 23 | import com.google.gson.JsonPrimitive; 24 | import com.google.gson.JsonSerializationContext; 25 | import com.google.gson.JsonSerializer; 26 | import java.awt.Color; 27 | import java.lang.reflect.Type; 28 | 29 | public final class ColorTypeAdapter implements JsonSerializer, JsonDeserializer { 30 | 31 | @Override 32 | public Color deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context) 33 | throws JsonParseException { 34 | try { 35 | Integer rgba = null; 36 | if (json.isJsonPrimitive() && ((JsonPrimitive) json).isNumber()) { 37 | rgba = json.getAsInt(); 38 | } else if (json.isJsonObject()) { 39 | final var jsonObject = json.getAsJsonObject(); 40 | 41 | final var valueMember = jsonObject.get("value"); 42 | if (valueMember != null && valueMember.isJsonPrimitive() && ((JsonPrimitive) valueMember).isNumber()) { 43 | rgba = valueMember.getAsInt(); 44 | } 45 | } 46 | 47 | if (rgba == null) { 48 | throw new JsonParseException("Could not deserialize as " + Color.class.getSimpleName() + ": " + json); 49 | } 50 | 51 | return new Color(rgba, true); 52 | } catch (final JsonParseException e) { 53 | throw e; 54 | } catch (final Throwable t) { 55 | throw new JsonParseException(t); 56 | } 57 | } 58 | 59 | @Override 60 | public JsonElement serialize(final Color src, final Type typeOfSrc, final JsonSerializationContext context) { 61 | return new JsonPrimitive(src.getRGB()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/json/LockKeyAdapter.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2022 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.json; 18 | 19 | import com.google.gson.JsonDeserializationContext; 20 | import com.google.gson.JsonDeserializer; 21 | import com.google.gson.JsonElement; 22 | import com.google.gson.JsonParseException; 23 | import com.google.gson.JsonPrimitive; 24 | import com.google.gson.JsonSerializationContext; 25 | import com.google.gson.JsonSerializer; 26 | import de.bwravencl.controllerbuddy.input.LockKey; 27 | import java.lang.reflect.Type; 28 | 29 | public final class LockKeyAdapter implements JsonSerializer, JsonDeserializer { 30 | 31 | @Override 32 | public LockKey deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context) 33 | throws JsonParseException { 34 | try { 35 | LockKey lockKey = null; 36 | if (json.isJsonPrimitive()) { 37 | final var jsonPrimitive = (JsonPrimitive) json; 38 | 39 | if (jsonPrimitive.isNumber()) { 40 | lockKey = LockKey.VIRTUAL_KEY_CODE_TO_LOCK_KEY_MAP.get(jsonPrimitive.getAsInt()); 41 | } else if (jsonPrimitive.isString()) { 42 | lockKey = LockKey.NAME_TO_LOCK_KEY_MAP.get(jsonPrimitive.getAsString()); 43 | } 44 | } 45 | 46 | if (lockKey == null) { 47 | throw new JsonParseException("Could not deserialize as " + LockKey.class.getSimpleName() + ": " + json); 48 | } 49 | 50 | return lockKey; 51 | } catch (final JsonParseException e) { 52 | throw e; 53 | } catch (final Throwable t) { 54 | throw new JsonParseException(t); 55 | } 56 | } 57 | 58 | @Override 59 | public JsonElement serialize(final LockKey src, final Type typeOfSrc, final JsonSerializationContext context) { 60 | return new JsonPrimitive(src.name()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/json/ScanCodeAdapter.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2022 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.json; 18 | 19 | import com.google.gson.JsonDeserializationContext; 20 | import com.google.gson.JsonDeserializer; 21 | import com.google.gson.JsonElement; 22 | import com.google.gson.JsonParseException; 23 | import com.google.gson.JsonPrimitive; 24 | import com.google.gson.JsonSerializationContext; 25 | import com.google.gson.JsonSerializer; 26 | import de.bwravencl.controllerbuddy.input.ScanCode; 27 | import java.lang.reflect.Type; 28 | 29 | public final class ScanCodeAdapter implements JsonSerializer, JsonDeserializer { 30 | 31 | @Override 32 | public ScanCode deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context) 33 | throws JsonParseException { 34 | try { 35 | ScanCode scanCode = null; 36 | if (json.isJsonPrimitive()) { 37 | final var jsonPrimitive = (JsonPrimitive) json; 38 | 39 | if (jsonPrimitive.isNumber()) { 40 | scanCode = ScanCode.KEY_CODE_TO_SCAN_CODE_MAP.get(jsonPrimitive.getAsInt()); 41 | } else if (jsonPrimitive.isString()) { 42 | scanCode = ScanCode.NAME_TO_SCAN_CODE_MAP.get(jsonPrimitive.getAsString()); 43 | } 44 | } 45 | 46 | if (scanCode == null) { 47 | throw new JsonParseException( 48 | "Could not deserialize as " + ScanCode.class.getSimpleName() + ": " + json); 49 | } 50 | 51 | return scanCode; 52 | } catch (final JsonParseException e) { 53 | throw e; 54 | } catch (final Throwable t) { 55 | throw new JsonParseException(t); 56 | } 57 | } 58 | 59 | @Override 60 | public JsonElement serialize(final ScanCode src, final Type typeOfSrc, final JsonSerializationContext context) { 61 | return new JsonPrimitive(src.name()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/runmode/LocalRunMode.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2022 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.runmode; 18 | 19 | import de.bwravencl.controllerbuddy.gui.Main; 20 | import de.bwravencl.controllerbuddy.input.Input; 21 | import de.bwravencl.controllerbuddy.input.ScanCode; 22 | import java.io.IOException; 23 | import java.util.Arrays; 24 | import java.util.HashSet; 25 | import java.util.logging.Logger; 26 | 27 | public final class LocalRunMode extends OutputRunMode { 28 | 29 | private static final Logger LOGGER = Logger.getLogger(LocalRunMode.class.getName()); 30 | 31 | private final HashSet sourceKeyCodes = new HashSet<>(); 32 | 33 | private final HashSet sourceModifiersCodes = new HashSet<>(); 34 | 35 | public LocalRunMode(final Main main, final Input input) { 36 | super(main, input); 37 | } 38 | 39 | @Override 40 | Logger getLogger() { 41 | return LOGGER; 42 | } 43 | 44 | @Override 45 | boolean readInput() throws IOException { 46 | super.readInput(); 47 | 48 | if (!input.poll()) { 49 | controllerDisconnected(); 50 | 51 | return false; 52 | } 53 | 54 | final var inputAxes = input.getAxes(); 55 | 56 | final var inputAxisX = inputAxes.get(Input.VirtualAxis.X); 57 | axisX.set(inputAxisX); 58 | 59 | final var inputAxisY = inputAxes.get(Input.VirtualAxis.Y); 60 | axisY.set(inputAxisY); 61 | 62 | final var inputAxisZ = inputAxes.get(Input.VirtualAxis.Z); 63 | axisZ.set(inputAxisZ); 64 | 65 | final var inputAxisRX = inputAxes.get(Input.VirtualAxis.RX); 66 | axisRX.set(inputAxisRX); 67 | 68 | final var inputAxisRY = inputAxes.get(Input.VirtualAxis.RY); 69 | axisRY.set(inputAxisRY); 70 | 71 | final var inputAxisRZ = inputAxes.get(Input.VirtualAxis.RZ); 72 | axisRZ.set(inputAxisRZ); 73 | 74 | final var inputAxisS0 = inputAxes.get(Input.VirtualAxis.S0); 75 | axisS0.set(inputAxisS0); 76 | 77 | final var inputAxisS1 = inputAxes.get(Input.VirtualAxis.S1); 78 | axisS1.set(inputAxisS1); 79 | 80 | final var inputButtons = input.getButtons(); 81 | for (var i = 0; i < numButtons; i++) { 82 | buttons[i].set(inputButtons[i] ? 1 : 0); 83 | } 84 | 85 | cursorDeltaX = input.getCursorDeltaX(); 86 | input.setCursorDeltaX(0); 87 | cursorDeltaY = input.getCursorDeltaY(); 88 | input.setCursorDeltaY(0); 89 | 90 | updateOutputSets(input.getDownMouseButtons(), oldDownMouseButtons, newUpMouseButtons, newDownMouseButtons, 91 | false); 92 | 93 | downUpMouseButtons.clear(); 94 | final var inputDownUpMouseButtons = input.getDownUpMouseButtons(); 95 | downUpMouseButtons.addAll(inputDownUpMouseButtons); 96 | inputDownUpMouseButtons.clear(); 97 | 98 | sourceModifiersCodes.clear(); 99 | sourceKeyCodes.clear(); 100 | input.getDownKeyStrokes().forEach(keyStroke -> { 101 | sourceModifiersCodes.addAll(Arrays.asList(keyStroke.getModifierCodes())); 102 | sourceKeyCodes.addAll(Arrays.asList(keyStroke.getKeyCodes())); 103 | }); 104 | 105 | updateOutputSets(sourceModifiersCodes, oldDownModifiers, newUpModifiers, newDownModifiers, false); 106 | updateOutputSets(sourceKeyCodes, oldDownNormalKeys, newUpNormalKeys, newDownNormalKeys, true); 107 | 108 | downUpKeyStrokes.clear(); 109 | final var inputDownUpKeyStrokes = input.getDownUpKeyStrokes(); 110 | downUpKeyStrokes.addAll(inputDownUpKeyStrokes); 111 | inputDownUpKeyStrokes.clear(); 112 | 113 | scrollClicks = input.getScrollClicks(); 114 | input.setScrollClicks(0); 115 | 116 | onLockKeys.clear(); 117 | final var inputOnLockKeys = input.getOnLockKeys(); 118 | onLockKeys.addAll(inputOnLockKeys); 119 | inputOnLockKeys.clear(); 120 | 121 | offLockKeys.clear(); 122 | final var inputOffLockKeys = input.getOffLockKeys(); 123 | offLockKeys.addAll(inputOffLockKeys); 124 | inputOffLockKeys.clear(); 125 | 126 | return true; 127 | } 128 | 129 | @Override 130 | public void run() { 131 | logStart(); 132 | 133 | try { 134 | if (init()) { 135 | while (!Thread.currentThread().isInterrupted()) { 136 | if (readInput()) { 137 | writeOutput(); 138 | } 139 | // noinspection BusyWait 140 | Thread.sleep(pollInterval); 141 | } 142 | } else { 143 | forceStop = true; 144 | } 145 | } catch (final IOException e) { 146 | handleIOException(e); 147 | } catch (final InterruptedException _) { 148 | // expected whenever the run mode gets stopped 149 | } finally { 150 | deInit(); 151 | } 152 | 153 | logStop(); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/runmode/RunMode.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.runmode; 18 | 19 | import de.bwravencl.controllerbuddy.gui.GuiUtils; 20 | import de.bwravencl.controllerbuddy.gui.Main; 21 | import de.bwravencl.controllerbuddy.input.Input; 22 | import java.awt.EventQueue; 23 | import java.util.logging.Level; 24 | import java.util.logging.Logger; 25 | import javax.swing.JOptionPane; 26 | 27 | public abstract class RunMode implements Runnable { 28 | 29 | public static final int DEFAULT_POLL_INTERVAL = 1; 30 | 31 | private static final Logger LOGGER = Logger.getLogger(RunMode.class.getName()); 32 | 33 | final Input input; 34 | 35 | final Main main; 36 | 37 | int maxAxisValue; 38 | 39 | int minAxisValue; 40 | 41 | int numButtons; 42 | 43 | long pollInterval; 44 | 45 | private boolean stopping; 46 | 47 | RunMode(final Main main, final Input input) { 48 | this.main = main; 49 | this.input = input; 50 | pollInterval = main.getPollInterval(); 51 | 52 | input.setRunMode(this); 53 | } 54 | 55 | final void controllerDisconnected() { 56 | if (stopping) { 57 | return; 58 | } 59 | 60 | Thread.startVirtualThread(() -> main.stopAll(true, !main.isAutoRestartOutput(), true)); 61 | 62 | final var controller = input.getSelectedController(); 63 | if (controller != null) { 64 | LOGGER.log(Level.WARNING, 65 | Main.assembleControllerLoggingMessage("Could not read from controller ", controller)); 66 | } 67 | 68 | if (!main.isSkipControllerDialogs()) { 69 | EventQueue.invokeLater(() -> GuiUtils.showMessageDialog(main, main.getFrame(), 70 | Main.STRINGS.getString("COULD_NOT_READ_FROM_CONTROLLER_DIALOG_TEXT"), 71 | Main.STRINGS.getString("ERROR_DIALOG_TITLE"), JOptionPane.ERROR_MESSAGE)); 72 | } 73 | 74 | stopping = true; 75 | } 76 | 77 | abstract Logger getLogger(); 78 | 79 | public final int getMaxAxisValue() { 80 | return maxAxisValue; 81 | } 82 | 83 | public final int getMinAxisValue() { 84 | return minAxisValue; 85 | } 86 | 87 | public final int getNumButtons() { 88 | return numButtons; 89 | } 90 | 91 | public final long getPollInterval() { 92 | return pollInterval; 93 | } 94 | 95 | final void logStart() { 96 | getLogger().log(Level.INFO, "Starting output"); 97 | } 98 | 99 | final void logStop() { 100 | getLogger().log(Level.INFO, "Stopped output"); 101 | } 102 | 103 | final void process() { 104 | main.pollSdlEvents(); 105 | main.getMainLoop().yield(); 106 | } 107 | 108 | void setNumButtons(final int numButtons) { 109 | this.numButtons = numButtons; 110 | input.initButtons(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/util/RunnableWithDefaultExceptionHandler.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2023 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.util; 18 | 19 | public final class RunnableWithDefaultExceptionHandler implements Runnable { 20 | 21 | private final Runnable runnable; 22 | 23 | public RunnableWithDefaultExceptionHandler(final Runnable runnable) { 24 | this.runnable = runnable; 25 | } 26 | 27 | @Override 28 | public void run() { 29 | try { 30 | runnable.run(); 31 | } catch (final Throwable t) { 32 | Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), t); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/bwravencl/controllerbuddy/util/VersionUtils.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Matteo Hausner 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | package de.bwravencl.controllerbuddy.util; 18 | 19 | import de.bwravencl.controllerbuddy.constants.Constants; 20 | import java.util.Arrays; 21 | import java.util.Optional; 22 | 23 | public final class VersionUtils { 24 | 25 | public static Optional compareVersions(final String otherVersion) throws IllegalArgumentException { 26 | if (otherVersion == null) { 27 | return Optional.empty(); 28 | } 29 | 30 | try { 31 | final var otherVersionParts = getVersionIntegerParts(otherVersion); 32 | if (otherVersionParts.length < 2) { 33 | return Optional.empty(); 34 | } 35 | 36 | final var currentVersionParts = getVersionIntegerParts(Constants.VERSION); 37 | for (var i = 0; i < 2; i++) { 38 | if (otherVersionParts[i] < currentVersionParts[i]) { 39 | return Optional.of(-1); 40 | } 41 | if (otherVersionParts[i] > currentVersionParts[i]) { 42 | return Optional.of(1); 43 | } 44 | } 45 | } catch (final NumberFormatException e) { 46 | return Optional.empty(); 47 | } 48 | 49 | return Optional.of(0); 50 | } 51 | 52 | public static String getMajorAndMinorVersion() { 53 | final var versionWithoutSuffix = stripHashSuffix(Constants.VERSION); 54 | return versionWithoutSuffix.substring(0, versionWithoutSuffix.lastIndexOf('.')); 55 | } 56 | 57 | public static int[] getVersionIntegerParts(final String version) { 58 | final var versionWithoutSuffix = stripHashSuffix(version); 59 | return Arrays.stream(versionWithoutSuffix.split("\\.")).mapToInt(Integer::parseInt).toArray(); 60 | } 61 | 62 | private static String stripHashSuffix(final String version) { 63 | final var dashIndex = version.indexOf('-'); 64 | 65 | if (dashIndex < 0) { 66 | return version; 67 | } 68 | 69 | return version.substring(0, dashIndex); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/resources/icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/src/main/resources/icon_128.png -------------------------------------------------------------------------------- /src/main/resources/icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/src/main/resources/icon_16.png -------------------------------------------------------------------------------- /src/main/resources/icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/src/main/resources/icon_32.png -------------------------------------------------------------------------------- /src/main/resources/icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/src/main/resources/icon_64.png -------------------------------------------------------------------------------- /src/main/resources/tray_icon_hint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwRavencl/ControllerBuddy/91a12d4ee6541c4cc39ecb8d9ddfd623fc05da39/src/main/resources/tray_icon_hint.png --------------------------------------------------------------------------------