├── .github └── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── Feature_request.md ├── .gitignore ├── CHANGELOG.md ├── README.md ├── build.gradle ├── build.properties ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src ├── main ├── java │ └── com │ │ └── mattsmeets │ │ └── macrokey │ │ ├── MacroKey.java │ │ ├── ModReference.java │ │ ├── command │ │ ├── CommandLayer.java │ │ ├── CommandMacroKey.java │ │ ├── CommandOpenGUI.java │ │ └── StrippedCommand.java │ │ ├── config │ │ ├── ModConfig.java │ │ └── ModState.java │ │ ├── event │ │ ├── ExecuteOnTickEvent.java │ │ ├── InGameTickEvent.java │ │ ├── LayerEvent.java │ │ ├── MacroActivationEvent.java │ │ └── MacroEvent.java │ │ ├── exception │ │ └── PropertyInitalizationException.java │ │ ├── gui │ │ ├── GuiLayerManagement.java │ │ ├── GuiMacroManagement.java │ │ ├── GuiModifyLayer.java │ │ ├── GuiModifyMacro.java │ │ └── fragment │ │ │ ├── LayerListFragment.java │ │ │ └── MacroListFragment.java │ │ ├── handler │ │ ├── ChangeHandler.java │ │ ├── GameTickHandler.java │ │ ├── GuiHandler.java │ │ └── hook │ │ │ ├── ClientTickHandler.java │ │ │ ├── GuiEventHandler.java │ │ │ └── KeyInputHandler.java │ │ ├── model │ │ ├── AbstractCommand.java │ │ ├── BindingsFile.java │ │ ├── BindingsFileInterface.java │ │ ├── CommandInterface.java │ │ ├── Layer.java │ │ ├── LayerInterface.java │ │ ├── Macro.java │ │ ├── MacroInterface.java │ │ ├── StringCommand.java │ │ ├── lambda │ │ │ └── ExecuteOnTickInterface.java │ │ └── serializer │ │ │ └── CommandSerializer.java │ │ ├── proxy │ │ ├── ClientProxy.java │ │ └── CommonProxy.java │ │ ├── repository │ │ └── BindingsRepository.java │ │ └── service │ │ ├── JSONService.java │ │ ├── JsonConfig.java │ │ └── LogHelper.java └── resources │ ├── assets │ └── macrokey │ │ └── lang │ │ └── en_US.lang │ ├── mcmod.info │ └── pack.mcmeta └── test └── java └── com └── mattsmeets └── macrokey ├── handler └── GameTickHandlerTest.java ├── model └── serializer │ └── CommandSerializerTest.java ├── repository └── BindingsRepositoryTest.java └── service ├── JSONServiceTest.java └── LogHelperTest.java /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behaviour: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behaviour** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. Windows 10] 25 | - Minecraft Version: [e.g. 1.12.2] 26 | - MacroKey Version: [e.g. 2.0] 27 | - Release Type: [e.g. ALPHA, BETA, DEV, RELEASE] 28 | 29 | **Downloaded From** 30 | usually, this is from CurseForge.com, but please add if you downloaded the mod from an unauthorized third-party source, as this source can be outdated. 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse 2 | bin 3 | *.launch 4 | .settings 5 | .metadata 6 | .classpath 7 | .project 8 | 9 | # idea 10 | out 11 | *.ipr 12 | *.iws 13 | *.iml 14 | .idea 15 | 16 | # gradle 17 | build 18 | .gradle 19 | 20 | # other 21 | eclipse 22 | run 23 | 24 | .gradle/ 25 | build/ 26 | eclipse/ 27 | run/ 28 | *.class 29 | 30 | # Mobile Tools for Java (J2ME) 31 | .mtj.tmp/ 32 | 33 | # Package Files # 34 | *.jar 35 | !gradle/**/*.jar 36 | *.war 37 | *.ear 38 | 39 | logs 40 | 41 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 42 | hs_err_pid* 43 | /.nb-gradle/ 44 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | | Version | Released at | 2 | | :-----: | :---------: | 3 | | v2.0.0 | 04/11/2018 | 4 | | v2.0.1 | 29/12/2018 | 5 | | v2.0.2 | 08/12/2019 | 6 | | v2.0.3 | 08/12/2019 | 7 | 8 | Changelog 9 | ======= 10 | 11 | v2.0.3 12 | ----- 13 | - [BUG] Required to press a button twice when you press over a tick (\#51) 14 | 15 | v2.0.2 16 | ----- 17 | - [BUG] Required to press a button twice when you press over a tick (\#51) 18 | 19 | v2.0.1 20 | ----- 21 | - [BUG] Game crashes when deleting layer while on master (\#48) 22 | 23 | v2.0.0 24 | ----- 25 | - Right click layers 26 | - Add commands 27 | - UTF-8 (#6) 28 | - Add way to move buttons (#2) 29 | - Add buttons 30 | - Modify & add layers 31 | - Added layer support 32 | - Send anonymous usage data 33 | - Add version checking 34 | - Repeatable commands 35 | - Modify & add keybindings 36 | - Reimplemented Key handling 37 | - Loading keybindings via service 38 | - Redefining saving mechanism 39 | - Rewrite MacroKey from scratch -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MacroKey 2 | MacroKey Keybinding is a Minecraft Forge mod that allows you to bind commands to keys. 3 | 4 | [![Build Status](https://ci.mattsmeets.com/buildStatus/icon?job=MacroKey)](https://ci.mattsmeets.com/job/MacroKey/) 5 | [![Documentation Status](https://readthedocs.org/projects/macrokey/badge/?version=latest)](http://macrokey.readthedocs.io/en/latest/?badge=latest) 6 | 7 | ### Ad Material 8 | When you find yourself in a situation where you want to be able to access a command fast, you may realize you can be 1 click away. 9 | 10 | One of the biggest complaints I have found about macro mods in the past is that they aren't for forge, but also that they sometimes just don't work on servers without the mod installed on the server. With MacroKey I made that the mod is fully functional while in single- and multiplayer worlds. No server side mods required! 11 | 12 | ### Version Support 13 | | Version | Release Date | End of Life | Released MC Versions | 14 | |-------------|------------------|-----------------|-----------------------| 15 | | 1.0.* | April 2016 | June 2016 | 1.8 | 16 | | 1.1.5.* | June 2016 | June 2016 | 1.8.9 | 17 | | 1.1.6.1 | 12 July 2016 | March 2017 | 1.9.\*, 1.10.\* | 18 | | 1.1.6.3 | 24 July 2016 | January 2018 | 1.11.\*, 1.12.\* | 19 | | 2.0 | 04 November 2018 | *TBA* | 1.12.\*, 1.11.\*, 1.10.\*, 1.9.\*, 1.8.\* | 20 | | 2.1 | *TBA* | *TBA* | *TBA* | 21 | 22 | ### Useful Links 23 | Issue Tracker: https://github.com/Matts/MacroKey/issues 24 | 25 | Project Backlog: https://github.com/Matts/MacroKey/projects/1 26 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | maven { url = "http://files.minecraftforge.net/maven" } 5 | } 6 | dependencies { 7 | classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' 8 | } 9 | } 10 | 11 | // setup plugins to use 12 | plugins { 13 | id 'de.fuerstenau.buildconfig' version '1.1.8' 14 | id 'idea' 15 | id 'net.minecraftforge.gradle.forge' version '2.0.2' 16 | } 17 | 18 | // setup external properties file 19 | ext.configFile = file "build.properties" 20 | 21 | // read external properties file 22 | configFile.withReader { 23 | def prop = new Properties() 24 | prop.load(it) 25 | project.ext.config = new ConfigSlurper().parse prop 26 | } 27 | 28 | // set default version, group and package namespace 29 | version = config.mc_version + '-' + config.mod_version 30 | group = config.mod_group 31 | archivesBaseName = config.mod_name 32 | 33 | // if we are building from pipeline, then add build number to the version 34 | if (System.getenv().BUILD_NUMBER) 35 | version = "${version}.${System.getenv().BUILD_NUMBER}" 36 | 37 | // if we are not building with a key, add this to the version 38 | if (!project.hasProperty('signingKeystore')) { 39 | project.properties.put('signingFingerprint', 'unsigned') 40 | version = version + '-unsigned' 41 | } 42 | 43 | sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly. 44 | 45 | compileJava { 46 | sourceCompatibility = targetCompatibility = '1.8' 47 | } 48 | 49 | minecraft { 50 | version = "${config.mc_version}-${config.forge_version}" 51 | runDir = "run" 52 | 53 | mappings = 'stable_39' 54 | makeObfSourceJar = false 55 | } 56 | 57 | dependencies { 58 | testCompile "junit:junit:4.11" 59 | testCompile 'org.mockito:mockito-core:2.7.22' 60 | } 61 | 62 | buildConfig { 63 | sourceSets{ 64 | appName = config.mod_name 65 | main { 66 | buildConfigField "String", "acceptedVersions", config.accepted_versions 67 | buildConfigField "String", "fingerprint", project.findProperty('signingFingerprint') 68 | buildConfigField "String", "updateJSON", 69 | config.update_url + 70 | '?mkver=' + project.version + 71 | '&mcver=' + config.mc_version + 72 | '&fmver=' + config.forge_version + 73 | '&fngpt=' + project.findProperty('signingFingerprint') 74 | } 75 | } 76 | } 77 | 78 | processResources { 79 | // this will ensure that this task is redone when the versions change. 80 | inputs.property "mod_version", project.version 81 | inputs.property "mod_name", config.mod_name 82 | inputs.property "mc_version", project.minecraft.version 83 | 84 | // replace stuff in mcmod.info, nothing else 85 | from(sourceSets.main.resources.srcDirs) { 86 | include 'mcmod.info' 87 | 88 | // replace variable 89 | expand 'mod_name':config.mod_name, 'mod_version':project.version, 'mc_version':project.minecraft.version 90 | } 91 | 92 | // copy everything else except the mcmod.info 93 | from(sourceSets.main.resources.srcDirs) { 94 | exclude 'mcmod.info' 95 | } 96 | } 97 | 98 | task signJar(dependsOn: ['jar']){ 99 | doLast { 100 | // Skip the task if our secret data isn't available 101 | if (project.hasProperty('signingKeystore')) { 102 | ant.signjar( 103 | destDir: "$buildDir/libs", 104 | jar: "$buildDir/libs/*.jar", 105 | alias: signingAlias, 106 | storetype: "jks", 107 | keystore: signingKeystore, 108 | storepass: signingPassword 109 | ) 110 | } else { 111 | println("Skipping jar signing. Signing keystore isn't available.") 112 | } 113 | } 114 | } 115 | build.dependsOn signJar -------------------------------------------------------------------------------- /build.properties: -------------------------------------------------------------------------------- 1 | mod_version=2.0.3 2 | mod_name=MacroKey Keybinding 3 | mod_group=com.mattsmeets.macrokey 4 | mc_version=1.12 5 | forge_version=14.21.1.2387 6 | update_url=http://mod-versioning.mattsmeets.com/macrokey.json 7 | accepted_versions=[1.12,1.12.2] 8 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Sets default memory used for gradle commands. Can be overridden by user or command line properties. 2 | # This is required to provide enough memory for the Minecraft decompilation process. 3 | org.gradle.jvmargs=-Xmx3G 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matts/MacroKey/f8a1eeba773b6d80a328cb623d2fa6e063c1cfc1/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jan 24 18:38:21 CET 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/MacroKey.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey; 2 | 3 | import com.mattsmeets.macrokey.config.ModConfig; 4 | import com.mattsmeets.macrokey.config.ModState; 5 | import com.mattsmeets.macrokey.proxy.CommonProxy; 6 | import com.mattsmeets.macrokey.repository.BindingsRepository; 7 | import com.mattsmeets.macrokey.service.JsonConfig; 8 | import com.mattsmeets.macrokey.service.LogHelper; 9 | import net.minecraft.client.settings.KeyBinding; 10 | import net.minecraftforge.fml.common.Mod; 11 | import net.minecraftforge.fml.common.SidedProxy; 12 | import net.minecraftforge.fml.common.event.FMLFingerprintViolationEvent; 13 | import net.minecraftforge.fml.common.event.FMLInitializationEvent; 14 | import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; 15 | import net.minecraftforge.fml.relauncher.Side; 16 | 17 | import java.io.IOException; 18 | 19 | @Mod( 20 | modid = ModReference.MOD_ID, 21 | name = BuildConfig.NAME, 22 | version = BuildConfig.VERSION, 23 | clientSideOnly = true, 24 | useMetadata = true, 25 | acceptedMinecraftVersions = BuildConfig.acceptedVersions, 26 | updateJSON = BuildConfig.updateJSON, 27 | certificateFingerprint = BuildConfig.fingerprint 28 | ) 29 | public class MacroKey { 30 | 31 | @Mod.Instance 32 | public static MacroKey instance; 33 | 34 | @SidedProxy(clientSide = ModReference.CLIENT_PROXY) 35 | public static CommonProxy proxy; 36 | 37 | public LogHelper logger; 38 | 39 | public JsonConfig bindingsJSONConfig; 40 | 41 | public BindingsRepository bindingsRepository; 42 | 43 | public ModState modState; 44 | 45 | public KeyBinding[] forgeKeybindings; 46 | 47 | @Mod.EventHandler 48 | public void preInit(FMLPreInitializationEvent event) throws IOException { 49 | this.logger = new LogHelper(event.getModLog()); 50 | // MacroKey is a client side only mod, so we never want a server to run it 51 | if (event.getSide() == Side.SERVER) { 52 | this.logger.warn("Whoops! It seems you are trying to run MacroKey on a server... No worries, we will just disable."); 53 | } 54 | 55 | this.logger.info("Hello World! Welcome to MacroKey Keybinding. Please sit back while we initialize..."); 56 | this.logger.debug("PreInitialization"); 57 | 58 | // set-up the bindings.json service & files 59 | this.bindingsJSONConfig = new JsonConfig(event.getModConfigurationDirectory().getAbsolutePath(), ModConfig.bindingFile); 60 | this.bindingsJSONConfig.initializeFile(); 61 | 62 | // BindingsRepository has a dependency on the bindings.json file being created 63 | this.bindingsRepository = new BindingsRepository(this.bindingsJSONConfig); 64 | // Initialize the mod's state 65 | this.modState = new ModState(this.bindingsRepository.findActiveLayer(true)); 66 | } 67 | 68 | @Mod.EventHandler 69 | public void init(FMLInitializationEvent event) throws IOException { 70 | this.logger.info("Getting ready to take over the world!"); 71 | this.logger.debug("PreInitialization"); 72 | 73 | proxy.init(); 74 | } 75 | 76 | @Mod.EventHandler 77 | public void invalidFingerprint(FMLFingerprintViolationEvent event) { 78 | this.logger = new LogHelper(ModReference.MOD_ID); 79 | 80 | this.logger.warn("Invalid fingerprint detected! The version of the mod is most likely modified or an unofficial release."); 81 | this.logger.warn("Please download the latest version from http://curse.com/project/243479"); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/ModReference.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey; 2 | 3 | import static com.mattsmeets.macrokey.MacroKey.instance; 4 | 5 | public class ModReference { 6 | public static final String MOD_ID = "macrokey"; 7 | public static final String MOD_NAME = BuildConfig.NAME; 8 | public static final String MOD_VERSION = BuildConfig.VERSION; 9 | 10 | public static final String COMMON_PROXY = "com.mattsmeets.macrokey.proxy.CommonProxy"; 11 | public static final String CLIENT_PROXY = "com.mattsmeets.macrokey.proxy.ClientProxy"; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/command/CommandLayer.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.command; 2 | 3 | import com.mattsmeets.macrokey.MacroKey; 4 | import com.mattsmeets.macrokey.model.LayerInterface; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.resources.I18n; 7 | import net.minecraft.command.CommandException; 8 | import net.minecraft.command.ICommandSender; 9 | import net.minecraft.server.MinecraftServer; 10 | import net.minecraft.util.math.BlockPos; 11 | import net.minecraft.util.text.TextComponentString; 12 | import net.minecraft.util.text.TextComponentTranslation; 13 | import scala.actors.threadpool.Arrays; 14 | 15 | import javax.annotation.Nullable; 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.Collections; 19 | import java.util.List; 20 | 21 | public class CommandLayer extends StrippedCommand { 22 | public final String 23 | layerMasterText = I18n.format("text.layer.master"); 24 | 25 | @Override 26 | public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { 27 | if (args.length < 1) { 28 | return; 29 | } 30 | 31 | if (args.length == 1) { 32 | this.printLayerInformation(sender); 33 | 34 | return; 35 | } 36 | 37 | if (args[1].equals("toggle")) { 38 | this.nextLayer(server, sender, new String[] {args[0]}); 39 | 40 | return; 41 | } 42 | 43 | sender.sendMessage(new TextComponentString(this.getUsage(sender))); 44 | } 45 | 46 | @Override 47 | public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) { 48 | List list = new ArrayList(); 49 | list.add("toggle"); 50 | 51 | return list; 52 | } 53 | 54 | @Override 55 | public String getUsage(ICommandSender sender) { 56 | return "Usage: /macrokey layer [toggle]"; 57 | } 58 | 59 | private void printLayerInformation(ICommandSender sender) { 60 | LayerInterface activeLayer = MacroKey.instance.modState.getActiveLayer(); 61 | 62 | String layerDisplayName = layerMasterText; 63 | int countMacroEnabled = 0; 64 | 65 | if (activeLayer != null) { 66 | layerDisplayName = activeLayer.getDisplayName(); 67 | countMacroEnabled = activeLayer.getMacros().size(); 68 | } else { 69 | try { 70 | countMacroEnabled = MacroKey.instance.bindingsRepository.findAllMacros(false).size(); 71 | } catch (IOException e) { 72 | e.printStackTrace(); 73 | } 74 | } 75 | 76 | sender.sendMessage( 77 | new TextComponentTranslation( 78 | "command.layer.information", 79 | layerDisplayName, 80 | countMacroEnabled 81 | ) 82 | ); 83 | } 84 | 85 | private void nextLayer(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { 86 | try { 87 | MacroKey.instance.modState.nextLayer(); 88 | 89 | this.execute(server, sender, args); 90 | } catch (IOException e) { 91 | e.printStackTrace(); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/command/CommandMacroKey.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.command; 2 | 3 | import net.minecraft.command.CommandBase; 4 | import net.minecraft.command.CommandException; 5 | import net.minecraft.command.ICommand; 6 | import net.minecraft.command.ICommandSender; 7 | import net.minecraft.server.MinecraftServer; 8 | import net.minecraft.util.math.BlockPos; 9 | import net.minecraft.util.text.TextComponentString; 10 | 11 | import javax.annotation.Nullable; 12 | import java.util.ArrayList; 13 | import java.util.Arrays; 14 | import java.util.HashMap; 15 | import java.util.List; 16 | 17 | public class CommandMacroKey extends CommandBase implements ICommand { 18 | 19 | private HashMap subCommands; 20 | 21 | public CommandMacroKey() { 22 | this.subCommands = new HashMap<>(); 23 | 24 | subCommands.put("open", new CommandOpenGUI()); 25 | subCommands.put("layer", new CommandLayer()); 26 | } 27 | 28 | @Override 29 | public String getName() { 30 | return "macrokey"; 31 | } 32 | 33 | @Override 34 | public String getUsage(ICommandSender sender) { 35 | return "Usage: /macrokey [open / layer]"; 36 | } 37 | 38 | @Override 39 | public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { 40 | if (args.length == 0) { 41 | this.subCommands.get("open").execute(server, sender, args); 42 | 43 | return; 44 | } 45 | 46 | if (this.subCommands.containsKey(args[0].toLowerCase())) { 47 | this.subCommands.get(args[0].toLowerCase()).execute(server, sender, args); 48 | 49 | return; 50 | } 51 | 52 | sender.sendMessage(new TextComponentString(this.getUsage(sender))); 53 | } 54 | 55 | @Override 56 | public boolean checkPermission(MinecraftServer server, ICommandSender sender) { 57 | return true; 58 | } 59 | 60 | @Override 61 | public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) { 62 | if (args.length >= 1 && this.subCommands.containsKey(args[0].toLowerCase())) { 63 | return this.subCommands.get(args[0].toLowerCase()).getTabCompletions(server, sender, args, targetPos); 64 | } 65 | 66 | List list = new ArrayList(); 67 | list.add("open"); 68 | list.add("layer"); 69 | 70 | return list; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/command/CommandOpenGUI.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.command; 2 | 3 | import com.mattsmeets.macrokey.event.ExecuteOnTickEvent; 4 | import com.mattsmeets.macrokey.model.lambda.ExecuteOnTickInterface; 5 | import net.minecraft.command.CommandException; 6 | import net.minecraft.command.ICommandSender; 7 | import net.minecraft.server.MinecraftServer; 8 | import net.minecraft.util.math.BlockPos; 9 | import net.minecraftforge.common.MinecraftForge; 10 | import net.minecraftforge.fml.relauncher.Side; 11 | import net.minecraftforge.fml.relauncher.SideOnly; 12 | 13 | import javax.annotation.Nullable; 14 | import java.util.ArrayList; 15 | import java.util.Arrays; 16 | import java.util.Collections; 17 | import java.util.List; 18 | 19 | public class CommandOpenGUI extends StrippedCommand { 20 | 21 | @Override 22 | @SideOnly(Side.CLIENT) 23 | public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { 24 | MinecraftForge.EVENT_BUS.post(new ExecuteOnTickEvent(ExecuteOnTickInterface.openMacroKeyGUI)); 25 | } 26 | 27 | @Override 28 | public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) { 29 | List list = new ArrayList(); 30 | 31 | return list; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/command/StrippedCommand.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.command; 2 | 3 | import net.minecraft.command.CommandException; 4 | import net.minecraft.command.ICommand; 5 | import net.minecraft.command.ICommandSender; 6 | import net.minecraft.server.MinecraftServer; 7 | import net.minecraft.util.math.BlockPos; 8 | 9 | import javax.annotation.Nullable; 10 | import java.util.List; 11 | 12 | public abstract class StrippedCommand implements ICommand { 13 | @Override 14 | public abstract void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException; 15 | 16 | @Override 17 | public abstract List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos); 18 | 19 | @Override 20 | public String getName() { 21 | return null; 22 | } 23 | 24 | @Override 25 | public String getUsage(ICommandSender sender) { 26 | return null; 27 | } 28 | 29 | @Override 30 | public List getAliases() { 31 | return null; 32 | } 33 | 34 | @Override 35 | public boolean checkPermission(MinecraftServer server, ICommandSender sender) { 36 | return false; 37 | } 38 | 39 | @Override 40 | public boolean isUsernameIndex(String[] args, int index) { 41 | return false; 42 | } 43 | 44 | @Override 45 | public int compareTo(ICommand o) { 46 | return 0; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/config/ModConfig.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.config; 2 | 3 | import com.mattsmeets.macrokey.ModReference; 4 | import net.minecraftforge.common.config.Config; 5 | import net.minecraftforge.common.config.ConfigManager; 6 | import net.minecraftforge.fml.client.event.ConfigChangedEvent; 7 | import net.minecraftforge.fml.common.Mod; 8 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 9 | 10 | @Config(modid = ModReference.MOD_ID) 11 | @Config.LangKey("macrokey.config.title") 12 | public class ModConfig { 13 | 14 | @Config.Comment("How many ticks need to pass for the repeatable command cooldown timer to expire (default: 20 ticks -> 1 second)") 15 | public static int repeatDelay = 20; 16 | 17 | @Config.Comment("What file should be used for saving the bindings and various other dynamic information (default: bindings.json)") 18 | public static String bindingFile = "bindings.json"; 19 | 20 | @Config.Comment("Customize the ID that is used when calling the macro management GUI (default: 423458971)") 21 | public static int guiMacroManagementId = 423458971; 22 | 23 | @Config.Comment("Customize the ID that is used when creating the button for switching layers (default: 823358142), (-1 = disabled)") 24 | public static int buttonLayerSwitcherId = 823358142; 25 | 26 | @Config.Comment("Customize the position that the button for switching layer should use, expected is {x, y, width, height} (default: -100, 128, 200, 20)") 27 | public static int[] buttonLayerSwitchSettings = {-100, 128, 200, 20}; 28 | 29 | @Mod.EventBusSubscriber(modid = ModReference.MOD_ID) 30 | public static class EventHandler { 31 | @SubscribeEvent 32 | public static void onConfigChanged(final ConfigChangedEvent.OnConfigChangedEvent event) { 33 | if (event.getModID().equals(ModReference.MOD_ID)) { 34 | ConfigManager.sync(ModReference.MOD_ID, Config.Type.INSTANCE); 35 | } 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/config/ModState.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.config; 2 | 3 | import com.mattsmeets.macrokey.MacroKey; 4 | import com.mattsmeets.macrokey.model.LayerInterface; 5 | 6 | import java.io.IOException; 7 | import java.util.Comparator; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | import static com.mattsmeets.macrokey.MacroKey.instance; 12 | 13 | public class ModState { 14 | 15 | private LayerInterface activeLayer; 16 | 17 | public ModState(LayerInterface activeLayer) { 18 | this.activeLayer = activeLayer; 19 | } 20 | 21 | public LayerInterface getActiveLayer() { 22 | return this.activeLayer; 23 | } 24 | 25 | public ModState setActiveLayer(LayerInterface layer) throws IOException { 26 | this.activeLayer = layer; 27 | 28 | instance.bindingsRepository.setActiveLayer(layer == null ? null : layer.getULID(), true); 29 | 30 | return this; 31 | } 32 | 33 | public List getLayers(boolean sync) throws IOException { 34 | return instance.bindingsRepository.findAllLayers(sync) 35 | .stream() 36 | .sorted(Comparator.comparing(LayerInterface::getULID)) 37 | .collect(Collectors.toList()); 38 | } 39 | 40 | public LayerInterface nextLayer() throws IOException { 41 | List layers = this.getLayers(true); 42 | LayerInterface layer = null; 43 | 44 | // get the index within all the 45 | // layers for the one currently active 46 | int indexOfCurrent = layers.indexOf(this.getActiveLayer()); 47 | 48 | // if there are more layers than the next 49 | // layer being selected, then select the next one 50 | if (layers.size() > indexOfCurrent + 1) { 51 | layer = layers.get(indexOfCurrent + 1); 52 | } 53 | 54 | this.setActiveLayer(layer); 55 | 56 | return layer; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/event/ExecuteOnTickEvent.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.event; 2 | 3 | import com.mattsmeets.macrokey.model.lambda.ExecuteOnTickInterface; 4 | import net.minecraftforge.fml.common.eventhandler.Event; 5 | 6 | public class ExecuteOnTickEvent extends Event { 7 | 8 | private ExecuteOnTickInterface executor; 9 | 10 | public ExecuteOnTickEvent(ExecuteOnTickInterface executor) { 11 | this.executor = executor; 12 | } 13 | 14 | public ExecuteOnTickInterface getExecutor() { 15 | return executor; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/event/InGameTickEvent.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.event; 2 | 3 | import net.minecraft.client.entity.EntityPlayerSP; 4 | import net.minecraftforge.fml.common.eventhandler.Event; 5 | 6 | public class InGameTickEvent extends Event { 7 | 8 | /** 9 | * Current player / sender 10 | */ 11 | private EntityPlayerSP currentPlayer; 12 | /** 13 | * Is this a limited tick event 14 | */ 15 | private boolean limitedTickEvent; 16 | 17 | public InGameTickEvent(EntityPlayerSP entityPlayerSP, boolean limited) { 18 | this.currentPlayer = entityPlayerSP; 19 | this.limitedTickEvent = limited; 20 | } 21 | 22 | public InGameTickEvent(EntityPlayerSP entityPlayerSP) { 23 | this.currentPlayer = entityPlayerSP; 24 | this.limitedTickEvent = false; 25 | } 26 | 27 | public EntityPlayerSP getCurrentPlayer() { 28 | return currentPlayer; 29 | } 30 | 31 | public boolean isLimitedTick() { 32 | return limitedTickEvent; 33 | } 34 | 35 | public static class LimitedInGameTickEvent extends InGameTickEvent { 36 | public LimitedInGameTickEvent(EntityPlayerSP entityPlayerSP) { 37 | super(entityPlayerSP, true); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/event/LayerEvent.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.event; 2 | 3 | import com.mattsmeets.macrokey.model.LayerInterface; 4 | import net.minecraftforge.fml.common.eventhandler.Event; 5 | 6 | public class LayerEvent { 7 | 8 | public static class LayerChangedEvent extends Event { 9 | private final LayerInterface layer; 10 | 11 | public LayerChangedEvent(LayerInterface layer) { 12 | this.layer = layer; 13 | } 14 | 15 | public LayerInterface getLayerChanged() { 16 | return layer; 17 | } 18 | } 19 | 20 | public static class LayerAddedEvent extends Event { 21 | private final LayerInterface layer; 22 | 23 | public LayerAddedEvent(LayerInterface layer) { 24 | this.layer = layer; 25 | } 26 | 27 | public LayerInterface getLayer() { 28 | return layer; 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/event/MacroActivationEvent.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.event; 2 | 3 | import com.mattsmeets.macrokey.model.MacroInterface; 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraft.client.entity.EntityPlayerSP; 6 | import net.minecraftforge.fml.common.eventhandler.Event; 7 | import net.minecraftforge.fml.relauncher.Side; 8 | import net.minecraftforge.fml.relauncher.SideOnly; 9 | 10 | import java.util.Set; 11 | 12 | @SideOnly(Side.CLIENT) 13 | public class MacroActivationEvent extends Event { 14 | 15 | /** 16 | * The macro('s) that have been activated 17 | */ 18 | private Set macros; 19 | /** 20 | * Current player / sender 21 | */ 22 | private EntityPlayerSP currentPlayer; 23 | /** 24 | * Current state of the button 25 | */ 26 | private MacroState pressed; 27 | 28 | public MacroActivationEvent(Set macros, MacroState pressed) { 29 | this.macros = macros; 30 | this.pressed = pressed; 31 | 32 | this.currentPlayer = Minecraft.getMinecraft().player; 33 | } 34 | 35 | public Set getMacros() { 36 | return this.macros; 37 | } 38 | 39 | public EntityPlayerSP getCurrentPlayer() { 40 | return currentPlayer; 41 | } 42 | 43 | public MacroState getMacroState() { 44 | return pressed; 45 | } 46 | 47 | /** 48 | * States the key pressed event can be in 49 | */ 50 | public static enum MacroState { 51 | KEY_UP(false), 52 | KEY_DOWN(true); 53 | 54 | private boolean state; 55 | 56 | MacroState(boolean state) { 57 | this.state = state; 58 | } 59 | 60 | public boolean isKeyDown() { 61 | return this.state; 62 | } 63 | 64 | public boolean isKeyUp() { 65 | return !this.state; 66 | } 67 | } 68 | 69 | public static class MacroActivationPressEvent extends MacroActivationEvent { 70 | public MacroActivationPressEvent(Set macros) { 71 | super(macros, MacroState.KEY_DOWN); 72 | } 73 | } 74 | 75 | public static class MacroActivationReleaseEvent extends MacroActivationEvent { 76 | public MacroActivationReleaseEvent(Set macros) { 77 | super(macros, MacroState.KEY_UP); 78 | } 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/event/MacroEvent.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.event; 2 | 3 | import com.mattsmeets.macrokey.model.MacroInterface; 4 | import net.minecraftforge.fml.common.eventhandler.Event; 5 | 6 | public class MacroEvent { 7 | 8 | public static class MacroChangedEvent extends Event { 9 | private final MacroInterface macroChanged; 10 | 11 | public MacroChangedEvent(MacroInterface macroChanged) { 12 | this.macroChanged = macroChanged; 13 | } 14 | 15 | public MacroInterface getMacroChanged() { 16 | return macroChanged; 17 | } 18 | } 19 | 20 | public static class MacroAddedEvent extends Event { 21 | private final MacroInterface macro; 22 | 23 | public MacroAddedEvent(MacroInterface macro) { 24 | this.macro = macro; 25 | } 26 | 27 | public MacroInterface getMacro() { 28 | return macro; 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/exception/PropertyInitalizationException.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.exception; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * An error that may occur during setup of the properties 7 | */ 8 | public class PropertyInitalizationException extends IOException { 9 | 10 | public PropertyInitalizationException(String message) { 11 | super(message); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/gui/GuiLayerManagement.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.gui; 2 | 3 | import com.mattsmeets.macrokey.gui.fragment.LayerListFragment; 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraft.client.gui.GuiButton; 6 | import net.minecraft.client.gui.GuiScreen; 7 | import net.minecraft.client.resources.I18n; 8 | 9 | import java.io.IOException; 10 | 11 | public class GuiLayerManagement extends GuiScreen { 12 | private final GuiScreen parentScreen; 13 | private final String 14 | screenTitle = I18n.format("gui.manage.layer.text.title"), 15 | addLayerButtonText = I18n.format("gui.manage.text.layer.add"); 16 | private final String 17 | doneText = I18n.format("gui.done"); 18 | private LayerListFragment layerListFragment; 19 | private GuiButton 20 | buttonDone, 21 | buttonAdd; 22 | 23 | public GuiLayerManagement(GuiScreen screen) { 24 | this.parentScreen = screen; 25 | } 26 | 27 | @Override 28 | public void drawScreen(int mouseX, int mouseY, float partialTicks) { 29 | this.drawDefaultBackground(); 30 | super.drawScreen(mouseX, mouseY, partialTicks); 31 | 32 | this.layerListFragment.drawScreen(mouseX, mouseY, partialTicks); 33 | 34 | buttonDone.drawButton(Minecraft.getMinecraft(), mouseX, mouseY, 0.0f); 35 | buttonAdd.drawButton(Minecraft.getMinecraft(), mouseX, mouseY, 0.0f); 36 | 37 | this.drawCenteredString(this.fontRenderer, this.screenTitle, this.width / 2, 8, 16777215); 38 | } 39 | 40 | @Override 41 | protected void actionPerformed(GuiButton button) { 42 | switch (button.id) { 43 | case 0: 44 | this.mc.displayGuiScreen(this.parentScreen); 45 | break; 46 | case 1: 47 | this.mc.displayGuiScreen(new GuiModifyLayer(this)); 48 | break; 49 | } 50 | } 51 | 52 | @Override 53 | public void initGui() { 54 | this.buttonList.add(buttonDone = new GuiButton(0, this.width / 2 - 155, this.height - 29, 150, 20, this.doneText)); 55 | this.buttonList.add(buttonAdd = new GuiButton(1, this.width / 2 - 155 + 160, this.height - 29, 150, 20, this.addLayerButtonText)); 56 | 57 | try { 58 | this.layerListFragment = new LayerListFragment(this); 59 | } catch (IOException e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | 64 | @Override 65 | public void updateScreen() { 66 | super.updateScreen(); 67 | } 68 | 69 | @Override 70 | protected void keyTyped(char typedChar, int keyCode) throws IOException { 71 | super.keyTyped(typedChar, keyCode); 72 | } 73 | 74 | @Override 75 | protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { 76 | if (mouseButton != 0 || !this.layerListFragment.mouseClicked(mouseX, mouseY, mouseButton)) { 77 | super.mouseClicked(mouseX, mouseY, mouseButton); 78 | } 79 | } 80 | 81 | @Override 82 | public void handleMouseInput() throws IOException { 83 | super.handleMouseInput(); 84 | this.layerListFragment.handleMouseInput(); 85 | } 86 | 87 | @Override 88 | public boolean doesGuiPauseGame() { 89 | return false; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/gui/GuiMacroManagement.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.gui; 2 | 3 | import com.mattsmeets.macrokey.event.MacroEvent; 4 | import com.mattsmeets.macrokey.gui.fragment.MacroListFragment; 5 | import com.mattsmeets.macrokey.model.LayerInterface; 6 | import com.mattsmeets.macrokey.model.MacroInterface; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.client.gui.GuiButton; 9 | import net.minecraft.client.gui.GuiScreen; 10 | import net.minecraft.client.resources.I18n; 11 | import net.minecraft.world.BossInfo; 12 | import net.minecraftforge.common.MinecraftForge; 13 | import org.lwjgl.input.Keyboard; 14 | import org.lwjgl.input.Mouse; 15 | 16 | import java.awt.*; 17 | import java.io.IOException; 18 | import java.util.List; 19 | 20 | import static com.mattsmeets.macrokey.MacroKey.instance; 21 | 22 | public class GuiMacroManagement extends GuiScreen { 23 | 24 | private final GuiScreen parentScreen; 25 | private final String 26 | screenTitle = I18n.format("gui.manage.text.title"), 27 | layerMasterText = I18n.format("text.layer.master"), 28 | addMacroButtonText = I18n.format("gui.manage.text.macro.add"), 29 | layerEditorButtonText = I18n.format("gui.manage.text.layer.edit"), 30 | layerSwitcherButtonText = I18n.format("gui.manage.text.layer.switch"); 31 | private final String 32 | doneText = I18n.format("gui.done"); 33 | public MacroInterface macroModify; 34 | private MacroListFragment macroListFragment; 35 | private GuiButton 36 | buttonDone, 37 | buttonAdd, 38 | layerEditor, 39 | layerSwitcher; 40 | 41 | private int currentSelectedLayer; 42 | private List layers; 43 | 44 | private volatile boolean updateList = false; 45 | 46 | public GuiMacroManagement(GuiScreen screen) { 47 | this.parentScreen = screen; 48 | this.currentSelectedLayer = -1; 49 | } 50 | 51 | @Override 52 | public void drawScreen(int mouseX, int mouseY, float partialTicks) { 53 | this.drawDefaultBackground(); 54 | super.drawScreen(mouseX, mouseY, partialTicks); 55 | 56 | if (this.updateList) { 57 | this.updateScreen(); 58 | } 59 | 60 | this.macroListFragment.drawScreen(mouseX, mouseY, partialTicks); 61 | 62 | this.buttonDone.drawButton(Minecraft.getMinecraft(), mouseX, mouseY, 0.0f); 63 | this.buttonAdd.drawButton(Minecraft.getMinecraft(), mouseX, mouseY, 0.0f); 64 | 65 | this.layerEditor.drawButton(Minecraft.getMinecraft(), mouseX, mouseY, 0.0f); 66 | 67 | this.layerSwitcher.drawButton(Minecraft.getMinecraft(), mouseX, mouseY, 0.0f); 68 | 69 | this.drawCenteredString(this.fontRenderer, this.screenTitle, this.width / 2, 8, 16777215); 70 | } 71 | 72 | @Override 73 | protected void actionPerformed(GuiButton button) { 74 | switch (button.id) { 75 | case 0: 76 | this.mc.displayGuiScreen(this.parentScreen); 77 | break; 78 | case 1: 79 | this.mc.displayGuiScreen(new GuiModifyMacro(this)); 80 | break; 81 | case 2: 82 | this.mc.displayGuiScreen(new GuiLayerManagement(this)); 83 | break; 84 | case 3: 85 | if (this.currentSelectedLayer < this.layers.size() - 1) { 86 | this.currentSelectedLayer++; 87 | } else { 88 | this.currentSelectedLayer = -1; 89 | } 90 | 91 | this.updateList = true; 92 | break; 93 | } 94 | } 95 | 96 | 97 | @SuppressWarnings("unchecked") 98 | @Override 99 | public void initGui() { 100 | this.buttonList.add(this.buttonDone = new GuiButton(0, this.width / 2 - 155, this.height - 29, 150, 20, this.doneText)); 101 | this.buttonList.add(this.buttonAdd = new GuiButton(1, this.width / 2 - 155 + 160, this.height - 29, 150, 20, this.addMacroButtonText)); 102 | 103 | this.buttonList.add(this.layerEditor = new GuiButton(2, this.width / 2 - 155 + 160, 40, 150, 20, this.layerEditorButtonText)); 104 | this.buttonList.add(this.layerSwitcher = new GuiButton(3, this.width / 2 - 155, 40, 150, 20, this.layerSwitcherButtonText)); 105 | 106 | this.updateList = true; 107 | } 108 | 109 | 110 | @Override 111 | public void updateScreen() { 112 | super.updateScreen(); 113 | 114 | if (!this.updateList) { 115 | return; 116 | } 117 | 118 | try { 119 | this.layers = instance.modState.getLayers(true); 120 | 121 | LayerInterface currentLayer = 122 | currentSelectedLayer == -1 ? null : this.layers.get(currentSelectedLayer); 123 | 124 | this.macroListFragment = new MacroListFragment(this, currentLayer); 125 | 126 | this.layerSwitcher.displayString = 127 | I18n.format("text.layer.display", 128 | currentLayer == null ? this.layerMasterText : currentLayer.getDisplayName() 129 | ); 130 | } catch (IOException e) { 131 | e.printStackTrace(); 132 | } finally { 133 | this.updateList = false; 134 | } 135 | } 136 | 137 | @Override 138 | protected void keyTyped(char typedChar, int keyCode) throws IOException { 139 | if (this.macroModify == null) { 140 | super.keyTyped(typedChar, keyCode); 141 | 142 | return; 143 | } 144 | 145 | if (keyCode == Keyboard.KEY_ESCAPE) { 146 | this.macroModify.setKeyCode(0); 147 | } else if (keyCode != 0) { 148 | this.macroModify.setKeyCode(keyCode); 149 | } else if (typedChar > 0) { 150 | this.macroModify.setKeyCode(typedChar + 256); 151 | } 152 | 153 | MinecraftForge.EVENT_BUS.post(new MacroEvent.MacroChangedEvent(this.macroModify)); 154 | 155 | this.macroModify = null; 156 | } 157 | 158 | @Override 159 | protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { 160 | if (this.macroModify != null) { 161 | this.macroModify = null; 162 | } else if (mouseButton != 0 || !this.macroListFragment.mouseClicked(mouseX, mouseY, mouseButton)) { 163 | super.mouseClicked(mouseX, mouseY, mouseButton); 164 | } 165 | } 166 | 167 | 168 | @Override 169 | public void handleMouseInput() throws IOException { 170 | super.handleMouseInput(); 171 | 172 | this.macroListFragment.handleMouseInput(); 173 | } 174 | 175 | @Override 176 | public boolean doesGuiPauseGame() { 177 | return false; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/gui/GuiModifyLayer.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.gui; 2 | 3 | import com.mattsmeets.macrokey.event.LayerEvent; 4 | import com.mattsmeets.macrokey.model.Layer; 5 | import com.mattsmeets.macrokey.model.LayerInterface; 6 | import net.minecraft.client.gui.GuiButton; 7 | import net.minecraft.client.gui.GuiScreen; 8 | import net.minecraft.client.gui.GuiTextField; 9 | import net.minecraft.client.resources.I18n; 10 | import net.minecraftforge.common.MinecraftForge; 11 | 12 | import java.io.IOException; 13 | 14 | public class GuiModifyLayer extends GuiScreen { 15 | 16 | private final GuiScreen parentScreen; 17 | private final LayerInterface result; 18 | 19 | private final String 20 | defaultScreenTitleText = I18n.format("gui.modify.layer.text.title.new"), 21 | editScreenTitleText = I18n.format("gui.modify.layer.text.title.edit"), 22 | saveLayerButtonText = I18n.format("gui.modify.layer.text.save"); 23 | 24 | private final String 25 | cancelText = I18n.format("gui.cancel"); 26 | 27 | private GuiButton addButton, cancelButton; 28 | 29 | private GuiTextField textFieldName; 30 | 31 | private boolean existing; 32 | 33 | public GuiModifyLayer(GuiScreen guiScreen, LayerInterface layer) { 34 | this.parentScreen = guiScreen; 35 | this.result = layer == null ? new Layer() : layer; 36 | this.existing = layer != null; 37 | } 38 | 39 | public GuiModifyLayer(GuiScreen guiScreen) { 40 | this(guiScreen, null); 41 | } 42 | 43 | @Override 44 | public void drawScreen(int mouseX, int mouseY, float partialTicks) { 45 | super.drawScreen(mouseX, mouseY, partialTicks); 46 | this.drawDefaultBackground(); 47 | 48 | this.drawCenteredString(this.fontRenderer, !existing ? this.defaultScreenTitleText : this.editScreenTitleText, this.width / 2, 8, 16777215); 49 | 50 | addButton.drawButton(parentScreen.mc, mouseX, mouseY, 0.0f); 51 | cancelButton.drawButton(parentScreen.mc, mouseX, mouseY, 0.0f); 52 | 53 | this.textFieldName.drawTextBox(); 54 | } 55 | 56 | public void updateScreen() { 57 | this.textFieldName.updateCursorCounter(); 58 | } 59 | 60 | @Override 61 | public void initGui() { 62 | super.initGui(); 63 | 64 | this.buttonList.add(addButton = new GuiButton(0, this.width / 2 - 155, this.height - 29, 150, 20, this.saveLayerButtonText)); 65 | this.buttonList.add(cancelButton = new GuiButton(1, this.width / 2 - 155 + 160, this.height - 29, 150, 20, this.cancelText)); 66 | 67 | this.textFieldName = new GuiTextField(9, this.fontRenderer, this.width / 2 - 100, 50, 200, 20); 68 | this.textFieldName.setFocused(true); 69 | this.textFieldName.setMaxStringLength(20); 70 | 71 | if (existing) { 72 | textFieldName.setText(result.getDisplayName()); 73 | } 74 | } 75 | 76 | @Override 77 | protected void actionPerformed(GuiButton button) throws IOException { 78 | super.actionPerformed(button); 79 | 80 | switch (button.id) { 81 | case 0: 82 | if (this.textFieldName.getText().length() <= 1) { 83 | break; 84 | } 85 | 86 | this.result.setDisplayName(this.textFieldName.getText()); 87 | 88 | if (this.existing) { 89 | MinecraftForge.EVENT_BUS.post(new LayerEvent.LayerChangedEvent(this.result)); 90 | } else { 91 | MinecraftForge.EVENT_BUS.post(new LayerEvent.LayerAddedEvent(this.result)); 92 | } 93 | case 1: 94 | this.mc.displayGuiScreen(parentScreen); 95 | break; 96 | } 97 | } 98 | 99 | @Override 100 | protected void keyTyped(char typedChar, int keyCode) throws IOException { 101 | if (this.textFieldName.isFocused()) { 102 | this.textFieldName.textboxKeyTyped(typedChar, keyCode); 103 | 104 | return; 105 | } 106 | 107 | super.keyTyped(typedChar, keyCode); 108 | } 109 | 110 | @Override 111 | protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { 112 | super.mouseClicked(mouseX, mouseY, mouseButton); 113 | 114 | this.textFieldName.mouseClicked(mouseX, mouseY, mouseButton); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/gui/GuiModifyMacro.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.gui; 2 | 3 | import com.mattsmeets.macrokey.event.MacroEvent; 4 | import com.mattsmeets.macrokey.model.Macro; 5 | import com.mattsmeets.macrokey.model.MacroInterface; 6 | import com.mattsmeets.macrokey.model.StringCommand; 7 | import net.minecraft.client.gui.GuiButton; 8 | import net.minecraft.client.gui.GuiScreen; 9 | import net.minecraft.client.gui.GuiTextField; 10 | import net.minecraft.client.resources.I18n; 11 | import net.minecraft.client.settings.GameSettings; 12 | import net.minecraft.client.settings.KeyBinding; 13 | import net.minecraft.util.text.TextFormatting; 14 | import net.minecraftforge.common.MinecraftForge; 15 | import org.lwjgl.input.Keyboard; 16 | 17 | import java.io.IOException; 18 | 19 | public class GuiModifyMacro extends GuiScreen { 20 | private final GuiScreen parentScreen; 21 | 22 | private final String 23 | defaultScreenTitleText = I18n.format("gui.modify.text.title.new"), 24 | editScreenTitleText = I18n.format("gui.modify.text.title.edit"), 25 | repeatOnHoldText = I18n.format("gui.modify.text.repeat"), 26 | enableCommandText = I18n.format("gui.modify.text.enable"), 27 | commandBoxTitleText = I18n.format("gui.modify.text.command"), 28 | keyBoxTitleText = I18n.format("gui.modify.text.key"), 29 | saveButtonText = I18n.format("gui.modify.text.save"); 30 | 31 | private final String 32 | enabledText = I18n.format("enabled"), 33 | disabledText = I18n.format("disabled"), 34 | cancelText = I18n.format("gui.cancel"); 35 | 36 | private final boolean existing; 37 | private final MacroInterface result; 38 | 39 | private GuiTextField command; 40 | 41 | private GuiButton btnKeyBinding; 42 | private GuiButton repeatCommand, commandActive; 43 | private GuiButton addButton, cancelButton; 44 | 45 | private boolean changingKey = false; 46 | 47 | public GuiModifyMacro(GuiScreen guiScreen, MacroInterface key) { 48 | // does the macro already exist, if not create a new one 49 | this.result = key == null ? new Macro() : key; 50 | this.parentScreen = guiScreen; 51 | this.existing = key != null; 52 | } 53 | 54 | public GuiModifyMacro(GuiScreen guiScreen) { 55 | this(guiScreen, null); 56 | } 57 | 58 | @Override 59 | public void initGui() { 60 | super.initGui(); 61 | this.buttonList.add(this.addButton = new GuiButton(0, this.width / 2 - 155, this.height - 29, 150, 20, saveButtonText)); 62 | this.buttonList.add(this.cancelButton = new GuiButton(1, this.width / 2 - 155 + 160, this.height - 29, 150, 20, cancelText)); 63 | 64 | this.buttonList.add(this.btnKeyBinding = new GuiButton(3, this.width / 2 - 75, 100, 150, 20, GameSettings.getKeyDisplayString(0))); 65 | this.buttonList.add(this.repeatCommand = new GuiButton(4, this.width / 2 - 75, 140, 75, 20, disabledText)); 66 | this.buttonList.add(this.commandActive = new GuiButton(5, this.width / 2 - 75, 163, 75, 20, disabledText)); 67 | 68 | this.command = new GuiTextField(9, this.fontRenderer, this.width / 2 - 100, 50, 200, 20); 69 | this.command.setFocused(true); 70 | this.command.setMaxStringLength(Integer.MAX_VALUE); 71 | 72 | if (this.existing) { 73 | this.command.setText(result.getCommand().toString()); 74 | 75 | this.btnKeyBinding.displayString = GameSettings.getKeyDisplayString(result.getKeyCode()); 76 | this.repeatCommand.displayString = result.willRepeat() ? enabledText : disabledText; 77 | this.commandActive.displayString = result.isActive() ? enabledText : disabledText; 78 | } 79 | } 80 | 81 | @Override 82 | protected void actionPerformed(GuiButton button) throws IOException { 83 | super.actionPerformed(button); 84 | switch (button.id) { 85 | case 0: 86 | if (this.command.getText().length() <= 1) { 87 | break; 88 | } 89 | 90 | this.result.setCommand(new StringCommand(command.getText())); 91 | 92 | if (this.existing) { 93 | MinecraftForge.EVENT_BUS.post(new MacroEvent.MacroChangedEvent(this.result)); 94 | } else { 95 | MinecraftForge.EVENT_BUS.post(new MacroEvent.MacroAddedEvent(this.result)); 96 | } 97 | case 1: 98 | this.mc.displayGuiScreen(parentScreen); 99 | break; 100 | } 101 | } 102 | 103 | @Override 104 | public void drawScreen(int mouseX, int mouseY, float partialTicks) { 105 | super.drawScreen(mouseX, mouseY, partialTicks); 106 | this.drawDefaultBackground(); 107 | 108 | // draw title 109 | this.drawCenteredString(this.fontRenderer, existing ? this.editScreenTitleText : this.defaultScreenTitleText, this.width / 2, 8, 16777215); 110 | 111 | // render add and cancel buttons 112 | this.addButton.drawButton(parentScreen.mc, mouseX, mouseY, 0.0f); 113 | this.cancelButton.drawButton(parentScreen.mc, mouseX, mouseY, 0.0f); 114 | 115 | // draw keycode as keyboard key 116 | this.btnKeyBinding.displayString = GameSettings.getKeyDisplayString(this.result.getKeyCode()); 117 | 118 | this.repeatCommand.displayString = this.result.willRepeat() ? enabledText : disabledText; 119 | this.commandActive.displayString = this.result.isActive() ? enabledText : disabledText; 120 | 121 | this.repeatCommand.drawButton(parentScreen.mc, mouseX, mouseY, 0.0f); 122 | this.commandActive.drawButton(parentScreen.mc, mouseX, mouseY, 0.0f); 123 | 124 | this.command.drawTextBox(); 125 | 126 | this.drawString(this.fontRenderer, repeatOnHoldText, this.width / 2 + 50 - mc.fontRenderer.getStringWidth(repeatOnHoldText) - 140, 145, -6250336); 127 | this.drawString(this.fontRenderer, enableCommandText, this.width / 2 + 50 - mc.fontRenderer.getStringWidth(enableCommandText) - 140, 168, -6250336); 128 | this.drawCenteredString(this.fontRenderer, commandBoxTitleText, this.width / 2, 37, -6250336); 129 | this.drawCenteredString(this.fontRenderer, keyBoxTitleText, this.width / 2, 90, -6250336); 130 | 131 | this.btnKeyBinding.displayString = GameSettings.getKeyDisplayString(this.result.getKeyCode()); 132 | 133 | boolean macroKeyCodeModifyFlag = false; 134 | 135 | if (this.result.getKeyCode() != 0) { 136 | for (KeyBinding keybinding : mc.gameSettings.keyBindings) { 137 | if (keybinding.getKeyCode() == this.result.getKeyCode()) { 138 | macroKeyCodeModifyFlag = true; 139 | break; 140 | } 141 | } 142 | } 143 | 144 | if (this.changingKey) { 145 | this.btnKeyBinding.displayString = TextFormatting.WHITE + "> " + TextFormatting.YELLOW + this.btnKeyBinding.displayString + TextFormatting.WHITE + " <"; 146 | } else if (macroKeyCodeModifyFlag) { 147 | this.btnKeyBinding.displayString = TextFormatting.GOLD + this.btnKeyBinding.displayString; 148 | } 149 | 150 | this.btnKeyBinding.drawButton(mc, mouseX, mouseY, 0.0f); 151 | } 152 | 153 | @Override 154 | protected void keyTyped(char typedChar, int keyCode) throws IOException { 155 | if (this.changingKey) { 156 | if (keyCode == Keyboard.KEY_ESCAPE) { 157 | this.result.setKeyCode(0); 158 | } else if (keyCode != 0) { 159 | this.result.setKeyCode(keyCode); 160 | } else if (typedChar > 0) { 161 | this.result.setKeyCode(typedChar + 256); 162 | } 163 | 164 | this.changingKey = false; 165 | 166 | return; 167 | } 168 | 169 | if (this.command.isFocused()) { 170 | if (keyCode == Keyboard.KEY_ESCAPE) 171 | this.command.setFocused(false); 172 | 173 | this.command.textboxKeyTyped(typedChar, keyCode); 174 | } else { 175 | super.keyTyped(typedChar, keyCode); 176 | } 177 | } 178 | 179 | @Override 180 | protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { 181 | super.mouseClicked(mouseX, mouseY, mouseButton); 182 | this.command.mouseClicked(mouseX, mouseY, mouseButton); 183 | 184 | if (this.changingKey) { 185 | this.changingKey = false; 186 | } 187 | 188 | if (this.btnKeyBinding.mousePressed(mc, mouseX, mouseY)) { 189 | this.changingKey = true; 190 | } 191 | 192 | if (this.repeatCommand.mousePressed(mc, mouseX, mouseY)) { 193 | this.result.setRepeat(!this.result.willRepeat()); 194 | } 195 | 196 | if (this.commandActive.mousePressed(mc, mouseX, mouseY)) { 197 | this.result.setActive(!this.result.isActive()); 198 | } 199 | } 200 | 201 | public void updateScreen() { 202 | this.command.updateCursorCounter(); 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/gui/fragment/LayerListFragment.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.gui.fragment; 2 | 3 | import com.mattsmeets.macrokey.gui.GuiLayerManagement; 4 | import com.mattsmeets.macrokey.gui.GuiModifyLayer; 5 | import com.mattsmeets.macrokey.model.LayerInterface; 6 | import net.minecraft.client.gui.GuiButton; 7 | import net.minecraft.client.gui.GuiListExtended; 8 | import net.minecraft.client.resources.I18n; 9 | import net.minecraftforge.fml.relauncher.Side; 10 | import net.minecraftforge.fml.relauncher.SideOnly; 11 | 12 | import java.io.IOException; 13 | import java.util.List; 14 | 15 | import static com.mattsmeets.macrokey.MacroKey.instance; 16 | 17 | public class LayerListFragment extends GuiListExtended { 18 | 19 | private final GuiLayerManagement guiLayerManagement; 20 | 21 | private final GuiListExtended.IGuiListEntry[] listEntries; 22 | 23 | public LayerListFragment(GuiLayerManagement guiLayerManagement) throws IOException { 24 | super(guiLayerManagement.mc, guiLayerManagement.width + 45, guiLayerManagement.height, 63, guiLayerManagement.height - 32, 20); 25 | 26 | this.guiLayerManagement = guiLayerManagement; 27 | 28 | List layers = instance.modState.getLayers(true); 29 | 30 | this.listEntries = new GuiListExtended.IGuiListEntry[layers.size()]; 31 | 32 | for (int i = 0; i < layers.size(); i++) { 33 | LayerInterface layer = layers.get(i); 34 | 35 | this.listEntries[i] = new LayerListFragment.KeyEntry(layer); 36 | } 37 | } 38 | 39 | @Override 40 | public IGuiListEntry getListEntry(int index) { 41 | return this.listEntries[index]; 42 | } 43 | 44 | @Override 45 | protected int getSize() { 46 | return this.listEntries.length; 47 | } 48 | 49 | 50 | @SideOnly(Side.CLIENT) 51 | public class KeyEntry implements GuiListExtended.IGuiListEntry { 52 | private final LayerInterface layer; 53 | 54 | private final String keyDesc; 55 | 56 | private final GuiButton 57 | btnRemove, 58 | btnEdit; 59 | 60 | private final String 61 | removeLayerText = I18n.format("fragment.list.text.remove"), 62 | editLayerText = I18n.format("edit"); 63 | 64 | private boolean deleted = false; 65 | 66 | private KeyEntry(LayerInterface layer) { 67 | this.layer = layer; 68 | this.keyDesc = layer.getDisplayName(); 69 | 70 | this.btnRemove = new GuiButton(1, 0, 0, 15, 20, this.removeLayerText); 71 | this.btnEdit = new GuiButton(2, 0, 0, 60, 20, this.editLayerText); 72 | } 73 | 74 | @Override 75 | public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected, float f) { 76 | if (deleted) { 77 | return; 78 | } 79 | 80 | mc.fontRenderer.drawString(this.keyDesc, x + 90 - mc.fontRenderer.getStringWidth(layer.getDisplayName()), y + slotHeight / 2 - mc.fontRenderer.FONT_HEIGHT / 2, 16777215); 81 | 82 | this.btnEdit.x = x + 140; 83 | this.btnEdit.y = y; 84 | this.btnEdit.displayString = this.editLayerText; 85 | 86 | this.btnEdit.drawButton(mc, mouseX, mouseY, 0.0f); 87 | 88 | this.btnRemove.x = x + 200; 89 | this.btnRemove.y = y; 90 | this.btnRemove.enabled = true; 91 | this.btnRemove.drawButton(mc, mouseX, mouseY, 0.0f); 92 | } 93 | 94 | @Override 95 | public boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY) { 96 | if (this.btnEdit.mousePressed(mc, mouseX, mouseY)) { 97 | mc.displayGuiScreen(new GuiModifyLayer(guiLayerManagement, layer)); 98 | 99 | return true; 100 | } 101 | 102 | if (this.btnRemove.mousePressed(mc, mouseX, mouseY)) { 103 | try { 104 | if (this.layer.equals(instance.modState.getActiveLayer())) 105 | instance.modState.setActiveLayer(null); 106 | 107 | instance.bindingsRepository.deleteLayer(this.layer, true); 108 | 109 | this.deleted = true; 110 | } catch (IOException e) { 111 | e.printStackTrace(); 112 | } finally { 113 | mc.displayGuiScreen(guiLayerManagement); 114 | } 115 | 116 | return true; 117 | } 118 | 119 | return false; 120 | } 121 | 122 | @Override 123 | public void mouseReleased(int slotIndex, int x, int y, int mouseEvent, int relativeX, int relativeY) { 124 | this.btnEdit.mouseReleased(x, y); 125 | } 126 | 127 | @Override 128 | public void updatePosition(int p_192633_1_, int p_192633_2_, int p_192633_3_, float p_192633_4_) { 129 | } 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/gui/fragment/MacroListFragment.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.gui.fragment; 2 | 3 | import com.mattsmeets.macrokey.event.LayerEvent; 4 | import com.mattsmeets.macrokey.gui.GuiMacroManagement; 5 | import com.mattsmeets.macrokey.gui.GuiModifyMacro; 6 | import com.mattsmeets.macrokey.model.LayerInterface; 7 | import com.mattsmeets.macrokey.model.MacroInterface; 8 | import net.minecraft.client.gui.GuiButton; 9 | import net.minecraft.client.gui.GuiListExtended; 10 | import net.minecraft.client.resources.I18n; 11 | import net.minecraft.client.settings.GameSettings; 12 | import net.minecraft.client.settings.KeyBinding; 13 | import net.minecraft.util.text.TextFormatting; 14 | import net.minecraftforge.common.MinecraftForge; 15 | import net.minecraftforge.fml.relauncher.Side; 16 | import net.minecraftforge.fml.relauncher.SideOnly; 17 | 18 | import java.io.IOException; 19 | import java.util.Comparator; 20 | import java.util.List; 21 | import java.util.stream.Collectors; 22 | 23 | import static com.mattsmeets.macrokey.MacroKey.instance; 24 | 25 | public class MacroListFragment extends GuiListExtended { 26 | 27 | private final GuiMacroManagement guiMacroManagement; 28 | private final GuiListExtended.IGuiListEntry[] listEntries; 29 | 30 | private final LayerInterface currentLayer; 31 | 32 | public MacroListFragment(GuiMacroManagement guiMacroManagement, LayerInterface layer) throws IOException { 33 | super(guiMacroManagement.mc, guiMacroManagement.width + 45, guiMacroManagement.height, 63, guiMacroManagement.height - 32, 20); 34 | 35 | this.guiMacroManagement = guiMacroManagement; 36 | this.currentLayer = layer; 37 | 38 | List macros = instance.bindingsRepository.findAllMacros(true) 39 | .stream() 40 | .sorted(Comparator.comparing(MacroInterface::getUMID)) 41 | .collect(Collectors.toList()); 42 | 43 | this.listEntries = new GuiListExtended.IGuiListEntry[macros.size()]; 44 | 45 | for (int i = 0; i < macros.size(); i++) { 46 | MacroInterface macro = macros.get(i); 47 | 48 | this.listEntries[i] = new MacroListFragment.KeyEntry(macro); 49 | } 50 | } 51 | 52 | @Override 53 | public IGuiListEntry getListEntry(int index) { 54 | return this.listEntries[index]; 55 | } 56 | 57 | @Override 58 | protected int getSize() { 59 | return this.listEntries.length; 60 | } 61 | 62 | 63 | @SideOnly(Side.CLIENT) 64 | public class KeyEntry implements GuiListExtended.IGuiListEntry { 65 | 66 | private final MacroInterface macro; 67 | 68 | private final GuiButton 69 | btnChangeKeyBinding, 70 | btnRemoveKeyBinding, 71 | btnEdit, 72 | btnEnabledInLayer; 73 | private final String 74 | removeMacroText = I18n.format("fragment.list.text.remove"), 75 | editMacroText = I18n.format("edit"); 76 | private final String 77 | enabledText = I18n.format("enabled"), 78 | disabledText = I18n.format("disabled"); 79 | private boolean enabledInLayer; 80 | private boolean deleted = false; 81 | 82 | private KeyEntry(MacroInterface macro) { 83 | this.macro = macro; 84 | 85 | this.btnChangeKeyBinding = new GuiButton(0, 0, 0, 75, 20, macro.getCommand().toString()); 86 | this.btnRemoveKeyBinding = new GuiButton(1, 0, 0, 15, 20, this.removeMacroText); 87 | this.btnEdit = new GuiButton(2, 0, 0, 30, 20, this.editMacroText); 88 | this.btnEnabledInLayer = new GuiButton(3, 0, 0, 75, 20, this.disabledText); 89 | 90 | if (currentLayer != null) { 91 | enabledInLayer = instance.bindingsRepository.isMacroInLayer(this.macro, currentLayer); 92 | } 93 | } 94 | 95 | @Override 96 | public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected, float f) { 97 | if (this.deleted) { 98 | return; 99 | } 100 | 101 | boolean macroKeyCodeModifyFlag = this.macro.equals(guiMacroManagement.macroModify); 102 | 103 | mc.fontRenderer.drawString(this.macro.getCommand().toString(), x + 90 - mc.fontRenderer.getStringWidth(macro.getCommand().toString()), y + slotHeight / 2 - mc.fontRenderer.FONT_HEIGHT / 2, 16777215); 104 | 105 | if (currentLayer == null) { 106 | this.btnChangeKeyBinding.x = x + 95; 107 | this.btnChangeKeyBinding.y = y; 108 | this.btnChangeKeyBinding.displayString = GameSettings.getKeyDisplayString(this.macro.getKeyCode()); 109 | 110 | this.btnEdit.x = x + 170; 111 | this.btnEdit.y = y; 112 | this.btnEdit.drawButton(mc, mouseX, mouseY, 0.0f); 113 | 114 | this.btnRemoveKeyBinding.x = x + 200; 115 | this.btnRemoveKeyBinding.y = y; 116 | this.btnRemoveKeyBinding.enabled = true; 117 | this.btnRemoveKeyBinding.drawButton(mc, mouseX, mouseY, 0.0f); 118 | } else { 119 | this.btnEnabledInLayer.x = x + 95; 120 | this.btnEnabledInLayer.y = y; 121 | 122 | if (enabledInLayer) { 123 | this.btnEnabledInLayer.displayString = this.enabledText; 124 | } else { 125 | this.btnEnabledInLayer.displayString = this.disabledText; 126 | } 127 | 128 | this.btnEnabledInLayer.drawButton(mc, mouseX, mouseY, 0.0f); 129 | } 130 | 131 | boolean currentKeyAlreadyUsedFlag = false; 132 | 133 | if (this.macro.getKeyCode() != 0) { 134 | for (KeyBinding keybinding : mc.gameSettings.keyBindings) { 135 | if (keybinding.getKeyCode() == this.macro.getKeyCode()) { 136 | currentKeyAlreadyUsedFlag = true; 137 | break; 138 | } 139 | } 140 | } 141 | 142 | if (macroKeyCodeModifyFlag) { 143 | this.btnChangeKeyBinding.displayString = TextFormatting.WHITE + "> " + TextFormatting.YELLOW + this.btnChangeKeyBinding.displayString + TextFormatting.WHITE + " <"; 144 | } else if (currentKeyAlreadyUsedFlag) { 145 | this.btnChangeKeyBinding.displayString = TextFormatting.GOLD + this.btnChangeKeyBinding.displayString; 146 | } 147 | 148 | this.btnChangeKeyBinding.drawButton(mc, mouseX, mouseY, 0.0f); 149 | } 150 | 151 | 152 | @Override 153 | public boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY) { 154 | if (this.btnEdit.mousePressed(mc, mouseX, mouseY)) { 155 | mc.displayGuiScreen(new GuiModifyMacro(guiMacroManagement, macro)); 156 | 157 | return true; 158 | } 159 | if (this.btnChangeKeyBinding.mousePressed(mc, mouseX, mouseY)) { 160 | guiMacroManagement.macroModify = this.macro; 161 | 162 | return true; 163 | } 164 | if (this.btnRemoveKeyBinding.mousePressed(mc, mouseX, mouseY)) { 165 | try { 166 | instance.bindingsRepository.deleteMacro(this.macro, true, true); 167 | 168 | this.deleted = true; 169 | } catch (IOException e) { 170 | e.printStackTrace(); 171 | } finally { 172 | mc.displayGuiScreen(guiMacroManagement); 173 | } 174 | 175 | return true; 176 | } 177 | if (this.btnEnabledInLayer.mousePressed(mc, mouseX, mouseY)) { 178 | enabledInLayer = !enabledInLayer; 179 | if (enabledInLayer) { 180 | currentLayer.addMacro(this.macro); 181 | } else { 182 | currentLayer.removeMacro(this.macro); 183 | } 184 | 185 | MinecraftForge.EVENT_BUS.post(new LayerEvent.LayerChangedEvent(currentLayer)); 186 | 187 | return true; 188 | } 189 | 190 | return false; 191 | } 192 | 193 | @Override 194 | public void mouseReleased(int slotIndex, int x, int y, int mouseEvent, int relativeX, int relativeY) { 195 | this.btnChangeKeyBinding.mouseReleased(x, y); 196 | this.btnEdit.mouseReleased(x, y); 197 | } 198 | 199 | @Override 200 | public void updatePosition(int p_192633_1_, int p_192633_2_, int p_192633_3_, float p_192633_4_) { 201 | } 202 | 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/handler/ChangeHandler.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.handler; 2 | 3 | import com.mattsmeets.macrokey.event.LayerEvent; 4 | import com.mattsmeets.macrokey.event.MacroEvent; 5 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 6 | import net.minecraftforge.fml.relauncher.Side; 7 | import net.minecraftforge.fml.relauncher.SideOnly; 8 | 9 | import java.io.IOException; 10 | 11 | import static com.mattsmeets.macrokey.MacroKey.instance; 12 | 13 | public class ChangeHandler { 14 | 15 | @SideOnly(Side.CLIENT) 16 | public static class MacroChangeHandler { 17 | 18 | @SubscribeEvent 19 | public void macroChangedEvent(MacroEvent.MacroChangedEvent event) throws IOException { 20 | instance.bindingsRepository.updateMacro(event.getMacroChanged(), true); 21 | } 22 | 23 | @SubscribeEvent 24 | public void macroAddedEvent(MacroEvent.MacroAddedEvent event) throws IOException { 25 | instance.bindingsRepository.addMacro(event.getMacro(), true); 26 | } 27 | } 28 | 29 | @SideOnly(Side.CLIENT) 30 | public static class LayerChangeHandler { 31 | 32 | @SubscribeEvent 33 | public void layerAddedEvent(LayerEvent.LayerAddedEvent event) throws IOException { 34 | instance.bindingsRepository.addLayer(event.getLayer(), true); 35 | } 36 | 37 | @SubscribeEvent 38 | public void layerChangedEvent(LayerEvent.LayerChangedEvent event) throws IOException { 39 | instance.bindingsRepository.updateLayer(event.getLayerChanged(), true); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/handler/GameTickHandler.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.handler; 2 | 3 | import com.mattsmeets.macrokey.MacroKey; 4 | import com.mattsmeets.macrokey.model.lambda.ExecuteOnTickInterface; 5 | import com.mattsmeets.macrokey.event.ExecuteOnTickEvent; 6 | import com.mattsmeets.macrokey.event.InGameTickEvent; 7 | import com.mattsmeets.macrokey.event.MacroActivationEvent; 8 | import com.mattsmeets.macrokey.model.MacroInterface; 9 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 10 | import net.minecraftforge.fml.relauncher.Side; 11 | import net.minecraftforge.fml.relauncher.SideOnly; 12 | 13 | import java.util.HashSet; 14 | import java.util.Set; 15 | 16 | @SideOnly(Side.CLIENT) 17 | public class GameTickHandler { 18 | 19 | /** 20 | * private stash of macro's to run 21 | */ 22 | private Set macrosToRun; 23 | 24 | /** 25 | * private stash of executor's to run 26 | */ 27 | private Set executorsToRun; 28 | 29 | public GameTickHandler(HashSet macrosToRun, HashSet executorsToRun) { 30 | this.macrosToRun = macrosToRun == null ? new HashSet<>() : macrosToRun; 31 | this.executorsToRun = executorsToRun == null ? new HashSet<>() : executorsToRun; 32 | } 33 | 34 | @SubscribeEvent 35 | public void onKeyEvent(MacroActivationEvent event) { 36 | if (event.getMacroState().isKeyDown()) { 37 | this.macrosToRun.addAll(event.getMacros()); 38 | } else { 39 | this.macrosToRun.removeIf(macro -> event.getMacros().contains(macro) && macro.willRepeat()); 40 | } 41 | } 42 | 43 | @SubscribeEvent 44 | public void onExecutorEvent(ExecuteOnTickEvent event) { 45 | executorsToRun.add(event.getExecutor()); 46 | } 47 | 48 | @SubscribeEvent 49 | public void onTick(InGameTickEvent event) { 50 | // loop through all pending macro's sending their command 51 | // on a off-tick, it will only send normal macro's, on a 52 | // delayed tick it will also execute the repeatable macro's 53 | // finally removing them from the list if it is not set to repeat 54 | this.macrosToRun 55 | .stream() 56 | .filter(macro -> !macro.willRepeat() || event.isLimitedTick()) 57 | .forEach(macro -> macro.getCommand().execute(event.getCurrentPlayer())); 58 | 59 | // loop through all executors and run them. 60 | this.executorsToRun 61 | .forEach(executor -> executor.execute(event.isLimitedTick())); 62 | 63 | // remove the command from the pending 64 | // list if it is not to be re-executed 65 | this.macrosToRun.removeIf(macro -> !macro.willRepeat()); 66 | this.executorsToRun.clear(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/handler/GuiHandler.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.handler; 2 | 3 | import com.mattsmeets.macrokey.config.ModConfig; 4 | import com.mattsmeets.macrokey.gui.GuiMacroManagement; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.entity.player.EntityPlayer; 7 | import net.minecraft.world.World; 8 | import net.minecraftforge.fml.common.network.IGuiHandler; 9 | 10 | public class GuiHandler implements IGuiHandler { 11 | 12 | @Override 13 | public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { 14 | return null; 15 | } 16 | 17 | @Override 18 | public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { 19 | if (id == ModConfig.guiMacroManagementId) { 20 | return new GuiMacroManagement(Minecraft.getMinecraft().currentScreen); 21 | } 22 | 23 | return null; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/handler/hook/ClientTickHandler.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.handler.hook; 2 | 3 | import com.mattsmeets.macrokey.config.ModConfig; 4 | import com.mattsmeets.macrokey.event.InGameTickEvent; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.entity.EntityPlayerSP; 7 | import net.minecraftforge.common.MinecraftForge; 8 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 9 | import net.minecraftforge.fml.common.gameevent.TickEvent; 10 | import net.minecraftforge.fml.relauncher.Side; 11 | import net.minecraftforge.fml.relauncher.SideOnly; 12 | 13 | @SideOnly(Side.CLIENT) 14 | public class ClientTickHandler { 15 | 16 | /** 17 | * Amount of ticks since last limited tick 18 | */ 19 | private int delta; 20 | 21 | @SubscribeEvent 22 | public void onTick(TickEvent.ClientTickEvent event) { 23 | EntityPlayerSP player = Minecraft.getMinecraft().player; 24 | 25 | // check if we are in-game 26 | if (player == null) { 27 | return; 28 | } 29 | 30 | // every tick post an event for the normal, 31 | // non repeating commands to trigger 32 | MinecraftForge.EVENT_BUS.post(new InGameTickEvent(player, false)); 33 | 34 | // rate-limiting so users can define 35 | // how fast a repeating command should execute 36 | // retrieve the given delay within the config, 37 | // this will by default be 20 ticks 38 | if (delta < ModConfig.repeatDelay) { 39 | delta++; 40 | return; 41 | } 42 | 43 | // once the delta time has reached the delay, 44 | // post a tick event for the repeating commands 45 | MinecraftForge.EVENT_BUS.post(new InGameTickEvent.LimitedInGameTickEvent(player)); 46 | 47 | // set delta back to zero 48 | delta = 0; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/handler/hook/GuiEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.handler.hook; 2 | 3 | import com.mattsmeets.macrokey.MacroKey; 4 | import com.mattsmeets.macrokey.config.ModConfig; 5 | import com.mattsmeets.macrokey.event.ExecuteOnTickEvent; 6 | import com.mattsmeets.macrokey.model.LayerInterface; 7 | import com.mattsmeets.macrokey.model.lambda.ExecuteOnTickInterface; 8 | import net.minecraft.client.gui.GuiButton; 9 | import net.minecraft.client.gui.GuiIngameMenu; 10 | import net.minecraft.client.gui.GuiScreen; 11 | import net.minecraft.client.resources.I18n; 12 | import net.minecraftforge.client.event.GuiScreenEvent; 13 | import net.minecraftforge.common.MinecraftForge; 14 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 15 | import net.minecraftforge.fml.relauncher.Side; 16 | import net.minecraftforge.fml.relauncher.SideOnly; 17 | import org.lwjgl.input.Mouse; 18 | 19 | import java.io.IOException; 20 | 21 | import static com.mattsmeets.macrokey.MacroKey.instance; 22 | 23 | public class GuiEventHandler { 24 | 25 | private String 26 | layerMasterText = I18n.format("text.layer.master"); 27 | 28 | private GuiButton switchButton = null; 29 | 30 | @SideOnly(Side.CLIENT) 31 | @SubscribeEvent 32 | public void event(GuiScreenEvent.InitGuiEvent event) { 33 | GuiScreen gui = event.getGui(); 34 | // check if the current GUI is the in-game menu 35 | // and if the layer switch button is not disabled 36 | if (!(event.getGui() instanceof GuiIngameMenu) || ModConfig.buttonLayerSwitcherId == -1) { 37 | return; 38 | } 39 | 40 | LayerInterface layer = instance.modState.getActiveLayer(); 41 | // render the layer switcher button 42 | event.getButtonList().add( 43 | switchButton = new GuiButton( 44 | ModConfig.buttonLayerSwitcherId, 45 | gui.width / 2 + ModConfig.buttonLayerSwitchSettings[0], 46 | gui.height / 4 + ModConfig.buttonLayerSwitchSettings[1], 47 | ModConfig.buttonLayerSwitchSettings[2], 48 | ModConfig.buttonLayerSwitchSettings[3], 49 | I18n.format("text.layer.display", 50 | layer == null ? this.layerMasterText : layer.getDisplayName() 51 | ) 52 | )); 53 | } 54 | 55 | @SubscribeEvent 56 | public void postActionPerformed(GuiScreenEvent.ActionPerformedEvent.Post event) throws IOException { 57 | if (!(event.getGui() instanceof GuiIngameMenu) 58 | || event.getButton().id != ModConfig.buttonLayerSwitcherId) { 59 | return; 60 | } 61 | 62 | LayerInterface layer = MacroKey.instance.modState.nextLayer(); 63 | 64 | event.getButton().displayString = 65 | I18n.format("text.layer.display", 66 | layer == null ? this.layerMasterText : layer.getDisplayName() 67 | ); 68 | } 69 | 70 | @SubscribeEvent(receiveCanceled = true) 71 | @SideOnly(Side.CLIENT) 72 | public void mouseInputEvent(GuiScreenEvent.MouseInputEvent.Post event) { 73 | if (!(event.getGui() instanceof GuiIngameMenu) || 74 | ModConfig.buttonLayerSwitcherId == -1 || 75 | switchButton == null || 76 | !switchButton.isMouseOver()) { 77 | return; 78 | } 79 | 80 | if (Mouse.getEventButton() != 1 && !Mouse.isButtonDown(1)) { 81 | return; 82 | } 83 | 84 | MinecraftForge.EVENT_BUS.post(new ExecuteOnTickEvent(ExecuteOnTickInterface.openMacroKeyGUI)); 85 | } 86 | 87 | @SubscribeEvent(receiveCanceled = true) 88 | @SideOnly(Side.CLIENT) 89 | public void render(GuiScreenEvent.DrawScreenEvent.Post event) { 90 | if (!(event.getGui() instanceof GuiIngameMenu) || 91 | ModConfig.buttonLayerSwitcherId == -1 || 92 | switchButton == null || 93 | !switchButton.isMouseOver()) { 94 | return; 95 | } 96 | 97 | GuiScreen screen = event.getGui(); 98 | 99 | screen.drawHoveringText( 100 | I18n.format("text.layer.hover.right_click"), 101 | Mouse.getEventX() / 2, 102 | screen.height - (Mouse.getY() / 2) 103 | ); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/handler/hook/KeyInputHandler.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.handler.hook; 2 | 3 | import com.mattsmeets.macrokey.MacroKey; 4 | import com.mattsmeets.macrokey.event.ExecuteOnTickEvent; 5 | import com.mattsmeets.macrokey.event.MacroActivationEvent; 6 | import com.mattsmeets.macrokey.model.MacroInterface; 7 | import com.mattsmeets.macrokey.model.lambda.ExecuteOnTickInterface; 8 | import net.minecraftforge.common.MinecraftForge; 9 | import net.minecraftforge.fml.common.eventhandler.EventPriority; 10 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 11 | import net.minecraftforge.fml.common.gameevent.InputEvent; 12 | import net.minecraftforge.fml.relauncher.Side; 13 | import net.minecraftforge.fml.relauncher.SideOnly; 14 | import org.lwjgl.input.Keyboard; 15 | 16 | import java.io.IOException; 17 | import java.util.HashSet; 18 | import java.util.Set; 19 | 20 | import static com.mattsmeets.macrokey.MacroKey.instance; 21 | 22 | public class KeyInputHandler { 23 | 24 | // private stash of pressed keys 25 | private Set pressedKeys; 26 | 27 | public KeyInputHandler() { 28 | this.pressedKeys = new HashSet<>(); 29 | } 30 | 31 | @SideOnly(Side.CLIENT) 32 | @SubscribeEvent(priority = EventPriority.NORMAL, receiveCanceled = true) 33 | public void onKeyInputEvent(InputEvent.KeyInputEvent event) throws IOException { 34 | int keyCode = Keyboard.getEventKey(); 35 | 36 | // find if the current key being pressed is the dedicated 37 | // MacroKey gui button. If so, open its GUI 38 | if (instance.forgeKeybindings[0].isPressed()) { 39 | MinecraftForge.EVENT_BUS.post(new ExecuteOnTickEvent(ExecuteOnTickInterface.openMacroKeyGUI)); 40 | } 41 | 42 | // find all macro's by the current key pressed, while not syncing 43 | Set macros = 44 | instance.bindingsRepository.findMacroByKeycode(keyCode, instance.modState.getActiveLayer(), false); 45 | 46 | // if the list is not empty 47 | if (macros.size() == 0) { 48 | macros = null; 49 | return; 50 | } 51 | 52 | if (Keyboard.getEventKeyState() && !this.pressedKeys.contains(keyCode)) { 53 | /* 54 | * if the key has not been pressed during last events, send 55 | * an event, and add it to the current index of pressed keys 56 | */ 57 | MinecraftForge.EVENT_BUS.post(new MacroActivationEvent.MacroActivationPressEvent(macros)); 58 | this.pressedKeys.add(keyCode); 59 | } else if (!Keyboard.getEventKeyState() && this.pressedKeys.contains(keyCode)) { 60 | /* 61 | * if the key has been pressed during last events, send 62 | * an event, and remove it from the current index of pressed keys 63 | */ 64 | MinecraftForge.EVENT_BUS.post(new MacroActivationEvent.MacroActivationReleaseEvent(macros)); 65 | this.pressedKeys.remove(keyCode); 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/model/AbstractCommand.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.model; 2 | 3 | public abstract class AbstractCommand implements CommandInterface { 4 | 5 | private final String type; 6 | 7 | AbstractCommand(String type) { 8 | this.type = type; 9 | } 10 | 11 | @Override 12 | public String getCommandType() { 13 | return this.type; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/model/BindingsFile.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.model; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | import java.util.UUID; 6 | 7 | public class BindingsFile implements BindingsFileInterface { 8 | 9 | private int version; 10 | private Set macros; 11 | private Set layers; 12 | private UUID activeLayer; 13 | 14 | public BindingsFile(int version, Set macros, Set layers) { 15 | this.version = version; 16 | this.macros = macros; 17 | this.layers = layers; 18 | } 19 | 20 | public BindingsFile(int version, Set macros) { 21 | this(version, macros, new HashSet<>()); 22 | } 23 | 24 | public BindingsFile(int version) { 25 | this(version, new HashSet<>(), new HashSet<>()); 26 | } 27 | 28 | public int getVersion() { 29 | return version; 30 | } 31 | 32 | public void setVersion(int version) { 33 | this.version = version; 34 | } 35 | 36 | public Set getMacros() { 37 | return macros; 38 | } 39 | 40 | public void setMacros(Set macros) { 41 | this.macros = macros; 42 | } 43 | 44 | public void addMacro(MacroInterface macro) { 45 | this.macros.add(macro); 46 | } 47 | 48 | public Set getLayers() { 49 | return layers; 50 | } 51 | 52 | public void setLayers(Set layers) { 53 | this.layers = layers; 54 | } 55 | 56 | public void addLayer(LayerInterface layer) { 57 | this.layers.add(layer); 58 | } 59 | 60 | public UUID getActiveLayer() { 61 | return activeLayer; 62 | } 63 | 64 | public void setActiveLayer(UUID activeLayer) { 65 | this.activeLayer = activeLayer; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/model/BindingsFileInterface.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.model; 2 | 3 | import java.util.Set; 4 | import java.util.UUID; 5 | 6 | public interface BindingsFileInterface { 7 | 8 | /** 9 | * @return version of the file 10 | */ 11 | public int getVersion(); 12 | 13 | /** 14 | * @param version of the file 15 | */ 16 | public void setVersion(int version); 17 | 18 | /** 19 | * @return Set of Macro's 20 | */ 21 | public Set getMacros(); 22 | 23 | /** 24 | * @param macros Set of macro's 25 | */ 26 | public void setMacros(Set macros); 27 | 28 | /** 29 | * @param macro macro to add 30 | */ 31 | public void addMacro(MacroInterface macro); 32 | 33 | /** 34 | * @return Set of Layer's 35 | */ 36 | public Set getLayers(); 37 | 38 | /** 39 | * @param layers Set of Layer's 40 | */ 41 | public void setLayers(Set layers); 42 | 43 | /** 44 | * @param layer layer to add 45 | */ 46 | public void addLayer(LayerInterface layer); 47 | 48 | /** 49 | * @return Active layer UUID 50 | */ 51 | public UUID getActiveLayer(); 52 | 53 | /** 54 | * @param activeLayer UUID of the new active layer 55 | */ 56 | public void setActiveLayer(UUID activeLayer); 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/model/CommandInterface.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.model; 2 | 3 | import net.minecraft.client.entity.EntityPlayerSP; 4 | 5 | public interface CommandInterface { 6 | 7 | /** 8 | * toString to save into file 9 | * 10 | * @return stringified command 11 | */ 12 | String toString(); 13 | 14 | /** 15 | * Run Command 16 | * @param player the player 17 | */ 18 | void execute(EntityPlayerSP player); 19 | 20 | /** 21 | * Type identifier used for (de)serialization 22 | * @return String 23 | */ 24 | String getCommandType(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/model/Layer.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.model; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | import java.util.UUID; 6 | 7 | public class Layer implements LayerInterface { 8 | 9 | private final UUID ulid; 10 | private String displayName; 11 | private Set macros; 12 | 13 | public Layer(UUID ulid, String displayName, Set macros) { 14 | this.ulid = ulid; 15 | this.displayName = displayName; 16 | this.macros = macros; 17 | } 18 | 19 | public Layer(UUID ulid, String displayName) { 20 | this(ulid, displayName, new HashSet<>()); 21 | } 22 | 23 | public Layer(String displayName) { 24 | this(UUID.randomUUID(), displayName, new HashSet<>()); 25 | } 26 | 27 | public Layer() { 28 | this(""); 29 | } 30 | 31 | public String getDisplayName() { 32 | return displayName; 33 | } 34 | 35 | public Layer setDisplayName(String displayName) { 36 | this.displayName = displayName; 37 | 38 | return this; 39 | } 40 | 41 | public Set getMacros() { 42 | return macros; 43 | } 44 | 45 | public Layer setMacros(Set macros) { 46 | this.macros = macros; 47 | 48 | return this; 49 | } 50 | 51 | public Layer addMacro(UUID macro) { 52 | this.macros.add(macro); 53 | 54 | return this; 55 | } 56 | 57 | public Layer addMacro(MacroInterface macro) { 58 | return this.addMacro(macro.getUMID()); 59 | } 60 | 61 | public Layer removeMacro(UUID macro) { 62 | this.macros.remove(macro); 63 | 64 | return this; 65 | } 66 | 67 | public Layer removeMacro(MacroInterface macro) { 68 | return this.removeMacro(macro.getUMID()); 69 | } 70 | 71 | public UUID getULID() { 72 | return ulid; 73 | } 74 | 75 | @Override 76 | public boolean equals(Object obj) { 77 | return 78 | obj instanceof LayerInterface && 79 | this.ulid.equals(((LayerInterface) obj).getULID()); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/model/LayerInterface.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.model; 2 | 3 | import java.util.Set; 4 | import java.util.UUID; 5 | 6 | public interface LayerInterface { 7 | 8 | /** 9 | * Get the displayName that should be rendered 10 | * 11 | * @return display name, user given name 12 | */ 13 | public String getDisplayName(); 14 | 15 | /** 16 | * Set the displayName that the macro should have 17 | * 18 | * @param displayName displayName to set 19 | * @return the current Layer instance 20 | */ 21 | public Layer setDisplayName(String displayName); 22 | 23 | /** 24 | * Get the macros bound to the layer 25 | * 26 | * @return Set of macros 27 | */ 28 | public Set getMacros(); 29 | 30 | /** 31 | * Set the macros the Layer should have 32 | * 33 | * @param macros the macros to have 34 | * @return the current Layer instance 35 | */ 36 | public Layer setMacros(Set macros); 37 | 38 | /** 39 | * Add a macro the Layer should have 40 | * 41 | * @param macro a macro to have 42 | * @return the current Layer instance 43 | */ 44 | public Layer addMacro(UUID macro); 45 | 46 | /** 47 | * Add a macro the Layer should have 48 | * 49 | * @param macro a macro to have 50 | * @return the current Layer instance 51 | */ 52 | public Layer addMacro(MacroInterface macro); 53 | 54 | /** 55 | * Remove a macro the Layer shouldn't have 56 | * 57 | * @param macro a macro to remove 58 | * @return the current Layer instance 59 | */ 60 | public Layer removeMacro(UUID macro); 61 | 62 | /** 63 | * Remove a macro the Layer shouldn't have 64 | * 65 | * @param macro a macro to remove 66 | * @return the current Layer instance 67 | */ 68 | public Layer removeMacro(MacroInterface macro); 69 | 70 | 71 | /** 72 | * Get the unique layer id 73 | * 74 | * @return unique layer id 75 | */ 76 | public UUID getULID(); 77 | 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/model/Macro.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.model; 2 | 3 | import java.util.UUID; 4 | 5 | /** 6 | * Model for Macro's (Bindings) 7 | */ 8 | public class Macro implements MacroInterface { 9 | 10 | /** 11 | * Unique Macro Identifier 12 | */ 13 | private UUID umid; 14 | 15 | /** 16 | * Keycode of the button that is bound 17 | */ 18 | private int keyCode; 19 | 20 | /** 21 | * Hold key to repeat command 22 | */ 23 | private boolean repeat; 24 | 25 | /** 26 | * Command in string form 27 | */ 28 | private CommandInterface command; 29 | 30 | /** 31 | * If the macro is active (default: true) 32 | */ 33 | private boolean active; 34 | 35 | public Macro(UUID umid, int keyCode, CommandInterface command, boolean active, boolean repeat) { 36 | this.umid = umid; 37 | this.keyCode = keyCode; 38 | this.command = command; 39 | this.active = active; 40 | this.repeat = repeat; 41 | } 42 | 43 | public Macro(int keyCode, CommandInterface command, boolean active, boolean repeat) { 44 | this(UUID.randomUUID(), keyCode, command, active, repeat); 45 | } 46 | 47 | public Macro(int keyCode, CommandInterface command, boolean active) { 48 | this(UUID.randomUUID(), keyCode, command, active, false); 49 | } 50 | 51 | public Macro(int keyCode, CommandInterface command) { 52 | this(keyCode, command, true); 53 | } 54 | 55 | public Macro(int keyCode, String command, boolean active) { 56 | this(keyCode, new StringCommand(command), active); 57 | } 58 | 59 | public Macro() { 60 | this.umid = UUID.randomUUID(); 61 | this.active = true; 62 | this.repeat = false; 63 | } 64 | 65 | public UUID getUMID() { 66 | return umid; 67 | } 68 | 69 | public int getKeyCode() { 70 | return keyCode; 71 | } 72 | 73 | public Macro setKeyCode(int keyCode) { 74 | this.keyCode = keyCode; 75 | 76 | return this; 77 | } 78 | 79 | public CommandInterface getCommand() { 80 | return command; 81 | } 82 | 83 | public Macro setCommand(CommandInterface command) { 84 | this.command = command; 85 | 86 | return this; 87 | } 88 | 89 | public boolean isActive() { 90 | return active; 91 | } 92 | 93 | public Macro setActive(boolean active) { 94 | this.active = active; 95 | 96 | return this; 97 | } 98 | 99 | public boolean willRepeat() { 100 | return repeat; 101 | } 102 | 103 | public Macro setRepeat(boolean repeat) { 104 | this.repeat = repeat; 105 | 106 | return this; 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/model/MacroInterface.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.model; 2 | 3 | import java.util.UUID; 4 | 5 | public interface MacroInterface { 6 | 7 | /** 8 | * Get the identifier of the macro (used internally) 9 | *

10 | * *Should* be immutable after setup. 11 | * 12 | * @return UUID unique macro identifier 13 | */ 14 | public UUID getUMID(); 15 | 16 | /** 17 | * Get the keyCode the Macro should be bound to 18 | * 19 | * @return int keyCode 20 | */ 21 | public int getKeyCode(); 22 | 23 | /** 24 | * Set the keyCode the Macro should be bound to 25 | * 26 | * @param keyCode the keyCode 27 | * @return the current Macro instance 28 | */ 29 | public Macro setKeyCode(int keyCode); 30 | 31 | /** 32 | * Get the actual command that will can run 33 | * 34 | * @return String command 35 | */ 36 | public CommandInterface getCommand(); 37 | 38 | /** 39 | * Set the actual command that will can run 40 | * 41 | * @param command the command 42 | * @return the current Macro instance 43 | */ 44 | public Macro setCommand(CommandInterface command); 45 | 46 | /** 47 | * Is the Macro active? 48 | * 49 | * @return boolean isActive 50 | */ 51 | public boolean isActive(); 52 | 53 | /** 54 | * Set the state of the Macro 55 | * 56 | * @param active isActive 57 | * @return the current Macro instance 58 | */ 59 | public Macro setActive(boolean active); 60 | 61 | /** 62 | * When holding button, should we repeat? 63 | * 64 | * @return repeat 65 | */ 66 | public boolean willRepeat(); 67 | 68 | /** 69 | * Set the 'repeat' flag on a macro. 70 | * 71 | * @param repeat willRepeat 72 | * @return the current Macro instance 73 | */ 74 | public Macro setRepeat(boolean repeat); 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/model/StringCommand.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.model; 2 | 3 | import com.mattsmeets.macrokey.MacroKey; 4 | import net.minecraft.client.entity.EntityPlayerSP; 5 | 6 | /** 7 | * Old vanilla macrokey command execution 8 | */ 9 | public class StringCommand extends AbstractCommand implements CommandInterface { 10 | 11 | /** 12 | * Command to execute 13 | */ 14 | private final String command; 15 | 16 | public StringCommand(String command) { 17 | super("string"); 18 | 19 | this.command = command; 20 | } 21 | 22 | @Override 23 | public void execute(EntityPlayerSP player) { 24 | // send command or text to server. For the time being it is 25 | // not possible to execute client-only commands. Tested and its 26 | // cool that the mod can bind its own GUI to different keys 27 | // from within the GUI, but this caused some weird issues 28 | player.sendChatMessage(command); 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return command; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/model/lambda/ExecuteOnTickInterface.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.model.lambda; 2 | 3 | import com.mattsmeets.macrokey.config.ModConfig; 4 | import net.minecraft.client.Minecraft; 5 | 6 | import static com.mattsmeets.macrokey.MacroKey.instance; 7 | 8 | public interface ExecuteOnTickInterface { 9 | public void execute(boolean delayed); 10 | 11 | public ExecuteOnTickInterface openMacroKeyGUI = 12 | (boolean delayed) -> 13 | Minecraft.getMinecraft().player.openGui( 14 | instance, 15 | ModConfig.guiMacroManagementId, 16 | Minecraft.getMinecraft().world, 17 | (int) Minecraft.getMinecraft().player.posX, 18 | (int) Minecraft.getMinecraft().player.posY, 19 | (int) Minecraft.getMinecraft().player.posZ 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/model/serializer/CommandSerializer.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.model.serializer; 2 | 3 | import com.google.gson.*; 4 | import com.mattsmeets.macrokey.model.AbstractCommand; 5 | import com.mattsmeets.macrokey.model.CommandInterface; 6 | import com.mattsmeets.macrokey.model.StringCommand; 7 | 8 | import java.lang.reflect.Type; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | public class CommandSerializer implements JsonSerializer, JsonDeserializer { 13 | 14 | private Map supportedTypes; 15 | 16 | public CommandSerializer() { 17 | this.supportedTypes = new HashMap<>(); 18 | this.supportedTypes.put("string", StringCommand.class); 19 | } 20 | 21 | @Override 22 | public CommandInterface deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 23 | JsonElement type = json.getAsJsonObject().get("type"); 24 | 25 | if(type == null || !this.supportedTypes.containsKey(type.getAsString())) { 26 | throw new JsonParseException("Could not parse command: " + json.toString()); 27 | } 28 | 29 | return context.deserialize(json, this.supportedTypes.get(type.getAsString())); 30 | } 31 | 32 | @Override 33 | public JsonElement serialize(CommandInterface src, Type typeOfSrc, JsonSerializationContext context) { 34 | return context.serialize(src.toString()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/proxy/ClientProxy.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.proxy; 2 | 3 | import com.mattsmeets.macrokey.command.CommandMacroKey; 4 | import com.mattsmeets.macrokey.handler.ChangeHandler; 5 | import com.mattsmeets.macrokey.handler.GameTickHandler; 6 | import com.mattsmeets.macrokey.handler.GuiHandler; 7 | import com.mattsmeets.macrokey.handler.hook.ClientTickHandler; 8 | import com.mattsmeets.macrokey.handler.hook.GuiEventHandler; 9 | import com.mattsmeets.macrokey.handler.hook.KeyInputHandler; 10 | import net.minecraft.client.settings.KeyBinding; 11 | import net.minecraftforge.client.ClientCommandHandler; 12 | import net.minecraftforge.common.MinecraftForge; 13 | import net.minecraftforge.fml.client.registry.ClientRegistry; 14 | import net.minecraftforge.fml.common.network.NetworkRegistry; 15 | import org.lwjgl.input.Keyboard; 16 | 17 | import static com.mattsmeets.macrokey.MacroKey.instance; 18 | 19 | public class ClientProxy extends CommonProxy { 20 | 21 | @Override 22 | public void init() { 23 | // hook into forge events 24 | this.registerHooks(); 25 | 26 | // register MacroKey event handlers 27 | MinecraftForge.EVENT_BUS.register(new GameTickHandler(null, null)); 28 | MinecraftForge.EVENT_BUS.register(new ChangeHandler.LayerChangeHandler()); 29 | MinecraftForge.EVENT_BUS.register(new ChangeHandler.MacroChangeHandler()); 30 | 31 | // register GUI registry 32 | NetworkRegistry.INSTANCE.registerGuiHandler(instance, new GuiHandler()); 33 | 34 | ClientCommandHandler.instance.registerCommand(new CommandMacroKey()); 35 | } 36 | 37 | private void registerHooks() { 38 | instance.forgeKeybindings = new KeyBinding[1]; 39 | instance.forgeKeybindings[0] = new KeyBinding("key.macrokey.management.desc", Keyboard.KEY_K, "key.macrokey.category"); 40 | 41 | for (int i = 0; i < instance.forgeKeybindings.length; ++i) { 42 | ClientRegistry.registerKeyBinding(instance.forgeKeybindings[i]); 43 | } 44 | 45 | MinecraftForge.EVENT_BUS.register(new KeyInputHandler()); 46 | MinecraftForge.EVENT_BUS.register(new ClientTickHandler()); 47 | MinecraftForge.EVENT_BUS.register(new GuiEventHandler()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/proxy/CommonProxy.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.proxy; 2 | 3 | public abstract class CommonProxy { 4 | 5 | public abstract void init(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/repository/BindingsRepository.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.repository; 2 | 3 | import com.google.gson.JsonObject; 4 | import com.mattsmeets.macrokey.model.*; 5 | import com.mattsmeets.macrokey.service.JsonConfig; 6 | 7 | import java.io.IOException; 8 | import java.util.Arrays; 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | import java.util.UUID; 12 | import java.util.stream.Collectors; 13 | 14 | /** 15 | * Repository class for the bindings.json file 16 | */ 17 | public class BindingsRepository { 18 | 19 | /** 20 | * JsonConfig helper class 21 | */ 22 | private final JsonConfig config; 23 | 24 | /** 25 | * File template used for serializing data into bindings.json 26 | */ 27 | private BindingsFileInterface bindingsFile; 28 | 29 | /** 30 | * Initialisation of the repository 31 | * Note: 32 | * The repository will automatically 33 | * sync when initialized 34 | * 35 | * @param jsonConfig the JsonConfig helper 36 | * @throws IOException when the file can not be found or modified 37 | */ 38 | public BindingsRepository(JsonConfig jsonConfig) throws IOException { 39 | this.config = jsonConfig; 40 | 41 | loadConfiguration(); 42 | } 43 | 44 | /** 45 | * Find all layers 46 | * 47 | * @param sync update from file before retrieving all layers 48 | * @return list of all layers 49 | * @throws IOException when file can not be found or read 50 | */ 51 | public Set findAllLayers(boolean sync) throws IOException { 52 | if (sync) 53 | // if specified to update memory with latest changes 54 | loadConfiguration(); 55 | 56 | return this.bindingsFile.getLayers(); 57 | } 58 | 59 | /** 60 | * Find layer by UUID 61 | * 62 | * @param ulid UUID 63 | * @param sync boolean update from file before retrieving 64 | * @return the layer found, may be null 65 | * @throws IOException when file can not be found or read 66 | */ 67 | public LayerInterface findLayerByUUID(UUID ulid, boolean sync) throws IOException { 68 | if (sync) 69 | // if specified to update memory with latest changes 70 | loadConfiguration(); 71 | 72 | return this.bindingsFile 73 | .getLayers() 74 | .stream() 75 | .filter( 76 | (layer) -> 77 | layer.getULID().equals(ulid) 78 | ) 79 | .reduce((u, v) -> { 80 | throw new IllegalStateException("More than one ID found"); 81 | }) 82 | .orElse(null); 83 | } 84 | 85 | /** 86 | * Add Layder 87 | * 88 | * @param layer affected layer 89 | * @param sync update file after adding layer 90 | * @throws IOException when file can not be found or read 91 | */ 92 | public void addLayer(LayerInterface layer, boolean sync) throws IOException { 93 | this.bindingsFile.addLayer(layer); 94 | 95 | if (sync) { 96 | // if specified to update configuration 97 | saveConfiguration(); 98 | } 99 | } 100 | 101 | /** 102 | * Edit Layer 103 | * 104 | * @param layer affected layer 105 | * @param sync update file after updating layer 106 | * @throws IOException when file can not be found or read 107 | */ 108 | public void updateLayer(LayerInterface layer, boolean sync) throws IOException { 109 | this.bindingsFile.setLayers( 110 | // get all layer's and go through all of them 111 | // when the ULID matches with the given layer 112 | // then return the given layer instead of the 113 | // layer that is currently being iterated over. 114 | // finally collect results into a Set 115 | this.bindingsFile 116 | .getLayers() 117 | .stream() 118 | .map((savedLayer) -> layer.getULID().equals(savedLayer.getULID()) ? layer : savedLayer) 119 | .collect(Collectors.toSet()) 120 | ); 121 | 122 | if (sync) { 123 | // if specified to update configuration 124 | saveConfiguration(); 125 | } 126 | } 127 | 128 | /** 129 | * Remove Layer by UUID 130 | * 131 | * @param ulid the unique layer identifier of the affected layer 132 | * @param sync update file after adding macro 133 | * @throws IOException when file can not be found or read 134 | */ 135 | public void deleteLayer(UUID ulid, boolean sync) throws IOException { 136 | this.bindingsFile.setLayers( 137 | // get all layer's and filter them 138 | // when the ulid of the layer matches 139 | // the given ulid, then we will filter 140 | // that out of the result set 141 | this.bindingsFile 142 | .getLayers() 143 | .stream() 144 | .filter(savedLayer -> ulid.compareTo(savedLayer.getULID()) != 0) 145 | .collect(Collectors.toSet()) 146 | ); 147 | 148 | if (this.isActiveLayer(ulid, false)) 149 | this.setActiveLayer((UUID) null, false); 150 | 151 | if (sync) { 152 | // if specified to update configuration 153 | saveConfiguration(); 154 | } 155 | } 156 | 157 | /** 158 | * Remove Layer by instance 159 | * 160 | * @param layer the affected layer 161 | * @param sync update file after removing layer 162 | * @throws IOException when file can not be found or read 163 | */ 164 | public void deleteLayer(LayerInterface layer, boolean sync) throws IOException { 165 | this.deleteLayer(layer.getULID(), sync); 166 | } 167 | 168 | /** 169 | * Find all active macro's 170 | * 171 | * @param sync update from file before retrieving all macros 172 | * @return list of all macros 173 | * @throws IOException when file can not be found or read 174 | */ 175 | public Set findAllMacros(boolean sync) throws IOException { 176 | if (sync) 177 | // if specified to update memory with latest changes 178 | loadConfiguration(); 179 | 180 | return this.bindingsFile.getMacros(); 181 | } 182 | 183 | public boolean isMacroInLayer(MacroInterface macro, LayerInterface layer) { 184 | return this.bindingsFile 185 | .getLayers() 186 | .stream() 187 | .filter(layerI -> layerI.getULID().equals(layer.getULID()) && layerI.getMacros().contains(macro.getUMID())).count() != 0; 188 | } 189 | 190 | /** 191 | * Find active macro by its ULID 192 | * 193 | * @param ulid the macro's ulid 194 | * @param sync update from file before retrieving all macros 195 | * @return list of active macro's with the given keyCode as trigger 196 | * @throws IOException when file can not be found or read 197 | */ 198 | public MacroInterface findMacroByUUID(UUID ulid, boolean sync) throws IOException { 199 | if (sync) 200 | // if specified to update memory with latest changes 201 | loadConfiguration(); 202 | 203 | // get all macros and filter through them 204 | // searching for entries that have the given 205 | // keyCode, and are active; finally collect 206 | // the results into a Set. 207 | return this.bindingsFile 208 | .getMacros() 209 | .stream() 210 | .filter( 211 | (macro) -> 212 | macro.getUMID().equals(ulid) 213 | 214 | ) 215 | .reduce((u, v) -> { 216 | throw new IllegalStateException("More than one ID found"); 217 | }) 218 | .orElse(null); 219 | } 220 | 221 | /** 222 | * Find active macro's by its keycode 223 | * 224 | * @param keyCode uses Keyboard keyCode 225 | * @param sync update from file before retrieving all macros 226 | * @return list of active macro's with the given keyCode as trigger 227 | * @throws IOException when file can not be found or read 228 | */ 229 | public Set findMacroByKeycode(int keyCode, LayerInterface layer, boolean sync) throws IOException { 230 | if (sync) 231 | // if specified to update memory with latest changes 232 | loadConfiguration(); 233 | 234 | // get all macros and filter through them 235 | // searching for entries that have the given 236 | // keyCode, and are active; it then checks 237 | // if the layer is null, or the macro exists 238 | // in the current layer. finally collect 239 | // the results into a Set. 240 | return this.bindingsFile 241 | .getMacros() 242 | .stream() 243 | .filter( 244 | (macro) -> 245 | macro.getKeyCode() == keyCode 246 | && macro.isActive() 247 | && (layer == null || isMacroInLayer(macro, layer)) 248 | ) 249 | .collect(Collectors.toSet()); 250 | } 251 | 252 | /** 253 | * Add Macro 254 | * 255 | * @param macro affected macro 256 | * @param sync update file after adding macro 257 | * @throws IOException when file can not be found or read 258 | */ 259 | public void addMacro(MacroInterface macro, boolean sync) throws IOException { 260 | this.bindingsFile.addMacro(macro); 261 | 262 | if (sync) { 263 | // if specified to update configuration 264 | saveConfiguration(); 265 | } 266 | } 267 | 268 | /** 269 | * Edit Macro 270 | * 271 | * @param macro affected macro 272 | * @param sync update file after adding macro 273 | * @throws IOException when file can not be found or read 274 | */ 275 | public void updateMacro(MacroInterface macro, boolean sync) throws IOException { 276 | this.bindingsFile.setMacros( 277 | // get all macro's and go through all of them 278 | // when the UMID matches with the given macro 279 | // then return the given macro instead of the 280 | // macro that is currently being iterated over. 281 | // finally collect results into a Set 282 | this.bindingsFile 283 | .getMacros() 284 | .stream() 285 | .map(savedMacro -> macro.getUMID().equals(savedMacro.getUMID()) ? macro : savedMacro) 286 | .collect(Collectors.toSet()) 287 | ); 288 | 289 | if (sync) { 290 | // if specified to update configuration 291 | saveConfiguration(); 292 | } 293 | } 294 | 295 | /** 296 | * Remove Macro by UUID 297 | * 298 | * @param umid the unique macro identifier of the affected macro 299 | * @param sync update file after adding macro 300 | * @param persist persist changes to the layer 301 | * @throws IOException when file can not be found or read 302 | */ 303 | public void deleteMacro(UUID umid, boolean sync, boolean persist) throws IOException { 304 | this.bindingsFile.setMacros( 305 | // get all macro's and filter them 306 | // when the umid of the macro matches 307 | // the given umid, then we will filter 308 | // that out of the result set 309 | this.bindingsFile 310 | .getMacros() 311 | .stream() 312 | .filter(savedMacro -> umid.compareTo(savedMacro.getUMID()) != 0) 313 | .collect(Collectors.toSet()) 314 | ); 315 | 316 | if (persist) { 317 | deleteMacroFromLayer(umid, sync); 318 | } 319 | 320 | if (sync && !persist) { 321 | // if specified to update configuration 322 | saveConfiguration(); 323 | } 324 | } 325 | 326 | /** 327 | * Remove macro from layer by UUID 328 | * 329 | * @param umid the unique macro identifier of the affected macro 330 | * @param sync update file after adding macro 331 | * @throws IOException when file can not be found or read 332 | */ 333 | public void deleteMacroFromLayer(UUID umid, boolean sync) throws IOException { 334 | // get all layers, and loop through them. 335 | // for each layer get all macro's and filter them 336 | // if they match the umid. Finally set the filtered 337 | // result as the new set of macros 338 | this.bindingsFile 339 | .getLayers() 340 | .forEach(layer -> 341 | layer.setMacros(layer.getMacros().stream() 342 | .filter(savedMacro -> umid.compareTo(savedMacro) != 0) 343 | .collect(Collectors.toSet()) 344 | )); 345 | 346 | if (sync) { 347 | // if specified to update configuration 348 | saveConfiguration(); 349 | } 350 | } 351 | 352 | /** 353 | * Remove Macro by instance 354 | * 355 | * @param macro the affected macro 356 | * @param sync update file after adding macro 357 | * @throws IOException when file can not be found or read 358 | */ 359 | public void deleteMacroFromLayer(MacroInterface macro, boolean sync) throws IOException { 360 | this.deleteMacroFromLayer(macro.getUMID(), sync); 361 | } 362 | 363 | /** 364 | * Remove Macro by instance 365 | * 366 | * @param macro the affected macro 367 | * @param sync update file after adding macro 368 | * @param persist persist changes to the layer 369 | * @throws IOException when file can not be found or read 370 | */ 371 | public void deleteMacro(MacroInterface macro, boolean sync, boolean persist) throws IOException { 372 | this.deleteMacro(macro.getUMID(), sync, persist); 373 | } 374 | 375 | /** 376 | * Find active layer in file 377 | * 378 | * @param sync boolean update from file before retrieving 379 | * @return the layer found, may be null 380 | * @throws IOException when file can not be found or read 381 | */ 382 | public LayerInterface findActiveLayer(boolean sync) throws IOException { 383 | return this.findLayerByUUID(this.bindingsFile.getActiveLayer(), sync); 384 | } 385 | 386 | /** 387 | * Set the active layer by ULID 388 | * 389 | * @param ulid unique layer id 390 | * @param sync update file after setting active layer 391 | * @throws IOException when file can not be found or read 392 | */ 393 | public void setActiveLayer(UUID ulid, boolean sync) throws IOException { 394 | this.bindingsFile.setActiveLayer(ulid); 395 | 396 | if (sync) { 397 | // if specified to update configuration 398 | saveConfiguration(); 399 | } 400 | } 401 | 402 | /** 403 | * Set the active layer by layer 404 | * 405 | * @param layer unique layer id 406 | * @param sync update file after setting active layer 407 | * @throws IOException when file can not be found or read 408 | */ 409 | public void setActiveLayer(LayerInterface layer, boolean sync) throws IOException { 410 | this.setActiveLayer(layer.getULID(), sync); 411 | } 412 | 413 | /** 414 | * Check if the given UUID is the active layer 415 | * 416 | * @param ulid UUID 417 | * @param sync boolean update from file before retrieving 418 | * @return true if the UUID given is the active layer 419 | * @throws IOException when file can not be found or read 420 | */ 421 | public boolean isActiveLayer(UUID ulid, boolean sync) throws IOException { 422 | if (sync) 423 | // if specified to update memory with latest changes 424 | loadConfiguration(); 425 | 426 | UUID activeULID = this.bindingsFile.getActiveLayer(); 427 | 428 | return ulid != null && activeULID != null && ulid.equals(activeULID); 429 | } 430 | 431 | /** 432 | * Check if the given UUID is the active layer 433 | * 434 | * @param layer Layer 435 | * @param sync boolean update from file before retrieving 436 | * @return true if the Layer given is the active layer 437 | * @throws IOException when file can not be found or read 438 | */ 439 | public boolean isActiveLayer(Layer layer, boolean sync) throws IOException { 440 | return this.isActiveLayer(layer.getULID(), sync); 441 | } 442 | 443 | /** 444 | * Get file configuration version 445 | * 446 | * @return will return the value of the "version" key 447 | */ 448 | public int findFileVersion() { 449 | return this.bindingsFile.getVersion(); 450 | } 451 | 452 | /** 453 | * Save the current BindingFile to json 454 | * 455 | * @throws IOException when file can not be found or read 456 | */ 457 | public void saveConfiguration() throws IOException { 458 | this.config.saveObjectToJson(this.bindingsFile); 459 | } 460 | 461 | /** 462 | * Loads the json file into memory 463 | * 464 | * @throws IOException when file can not be found or read 465 | */ 466 | public void loadConfiguration() throws IOException { 467 | JsonObject jsonObject = this.config.getJSONObject(); 468 | 469 | if (jsonObject != null) { 470 | // on initialization the bindingsFile will not be set. 471 | if (this.bindingsFile == null) { 472 | setBindingsFile(new BindingsFile(jsonObject.get("version").getAsInt())); 473 | } 474 | 475 | // retrieve all macro's from the bindings.json file 476 | // and add them inside our bindingsFile 477 | MacroInterface[] macroArray = this.config.bindJsonElementToObject(Macro[].class, jsonObject.get("macros")); 478 | this.bindingsFile 479 | .setMacros(Arrays 480 | .stream(macroArray) 481 | .collect(Collectors.toSet()) 482 | ); 483 | 484 | LayerInterface[] layerArray = this.config.bindJsonElementToObject(Layer[].class, jsonObject.get("layers")); 485 | this.bindingsFile 486 | .setLayers(Arrays 487 | .stream(layerArray) 488 | .collect(Collectors.toSet())); 489 | 490 | UUID activeLayer = this.config.bindJsonElementToObject(UUID.class, jsonObject.get("activeLayer")); 491 | this.bindingsFile 492 | .setActiveLayer(activeLayer); 493 | } else { 494 | // the bindings.json has just been created, or 495 | // has been corrupted. We will just create a fresh 496 | // installation to prevent errors. 497 | setBindingsFile(new BindingsFile(2, new HashSet<>())); 498 | 499 | saveConfiguration(); 500 | } 501 | } 502 | 503 | /** 504 | * Set the used bindings file. 505 | * 506 | * @param bindingsFile instance of BindingsFile 507 | */ 508 | public void setBindingsFile(BindingsFileInterface bindingsFile) { 509 | this.bindingsFile = bindingsFile; 510 | } 511 | 512 | } 513 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/service/JSONService.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.service; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.JsonParser; 7 | 8 | import java.io.*; 9 | 10 | public class JSONService { 11 | 12 | /** 13 | * JSON File Reader 14 | * 15 | * @param file A JSON file 16 | * @return The JSON contents of the give file 17 | * @throws IOException When the file is not found, or not readable/ 18 | */ 19 | public JsonElement loadJSONElementFromFile(File file) throws IOException { 20 | JsonParser parser = new JsonParser(); 21 | return parser.parse(new InputStreamReader(new FileInputStream(file), "UTF-8")); 22 | } 23 | 24 | public void saveJSONElementToFile(JsonElement element, File file) throws IOException { 25 | Writer writer = new FileWriter(file); 26 | 27 | Gson gson = new GsonBuilder().create(); 28 | gson.toJson(element, writer); 29 | writer.close(); 30 | } 31 | 32 | public void saveObjectsToFile(T element, File file) throws IOException { 33 | Writer writer = new FileWriter(file); 34 | 35 | Gson gson = new GsonBuilder().create(); 36 | gson.toJson(element, writer); 37 | writer.close(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/service/JsonConfig.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.service; 2 | 3 | import com.google.gson.GsonBuilder; 4 | import com.google.gson.JsonElement; 5 | import com.google.gson.JsonObject; 6 | import com.mattsmeets.macrokey.model.CommandInterface; 7 | import com.mattsmeets.macrokey.model.serializer.CommandSerializer; 8 | 9 | import java.io.File; 10 | import java.io.IOException; 11 | 12 | public class JsonConfig { 13 | 14 | private File file; 15 | private JSONService jsonService; 16 | 17 | public JsonConfig(String parentFolder, String fileName) { 18 | this.file = new File(parentFolder + "/macrokey/" + fileName); 19 | 20 | this.jsonService = new JSONService(); 21 | } 22 | 23 | public void initializeFile() throws IOException { 24 | File parentFolder = new File(this.file.getParent()); 25 | 26 | if (!parentFolder.exists()) { 27 | parentFolder.mkdirs(); 28 | } 29 | 30 | if (!this.file.exists()) { 31 | this.file.createNewFile(); 32 | } 33 | } 34 | 35 | private JsonElement getJSONElement() throws IOException { 36 | return this.jsonService.loadJSONElementFromFile(file); 37 | } 38 | 39 | public JsonObject getJSONObject() throws IOException { 40 | JsonElement jsonElement = getJSONElement(); 41 | 42 | if (jsonElement.isJsonObject()) { 43 | return jsonElement.getAsJsonObject(); 44 | } 45 | 46 | return null; 47 | } 48 | 49 | public T bindJsonToObject(Class classToBind) throws IOException { 50 | return bindJsonElementToObject(classToBind, getJSONElement()); 51 | } 52 | 53 | public T bindJsonElementToObject(Class classToBind, JsonElement element) { 54 | return new GsonBuilder() 55 | .registerTypeAdapter(CommandInterface.class, new CommandSerializer()) 56 | .create() 57 | .fromJson(element, classToBind); 58 | } 59 | 60 | public void saveObjectToJson(T object) throws IOException { 61 | this.jsonService.saveObjectsToFile(object, this.file); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/mattsmeets/macrokey/service/LogHelper.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.service; 2 | 3 | import org.apache.logging.log4j.Level; 4 | import org.apache.logging.log4j.LogManager; 5 | import org.apache.logging.log4j.Logger; 6 | 7 | public class LogHelper { 8 | 9 | private Logger logger; 10 | 11 | /** 12 | * Initializes the LogHelper with given parameters 13 | * 14 | * @param logger FMLPreInitializationEvent.getModLog() 15 | */ 16 | public LogHelper(Logger logger) { 17 | this.logger = logger; 18 | } 19 | 20 | public LogHelper(String modid) { 21 | this(LogManager.getLogger(modid)); 22 | } 23 | 24 | public void log(Level logLevel, Object object) { 25 | this.logger.log(logLevel, object); 26 | } 27 | 28 | public void info(Object object) { 29 | log(Level.INFO, object); 30 | } 31 | 32 | public void warn(Object object) { 33 | log(Level.WARN, object); 34 | } 35 | 36 | public void debug(Object object) { 37 | log(Level.DEBUG, object); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/resources/assets/macrokey/lang/en_US.lang: -------------------------------------------------------------------------------- 1 | ## Config Strings ## 2 | macrokey.config.title=MacroKey Keybinding Configuration 3 | #### 4 | 5 | ## Layer translations ## 6 | text.layer.display=Layer: %s 7 | text.layer.hover.right_click=Right-click to open the MacroKey GUI 8 | text.layer.master=Master 9 | #### 10 | 11 | ## GuiMacroManagement ## 12 | gui.manage.text.title=MacroKey Keybinding 13 | 14 | gui.manage.text.macro.add=Add Macro 15 | 16 | gui.manage.text.layer.edit=Layer Editor 17 | gui.manage.text.layer.switch=Layer Switch 18 | 19 | fragment.list.text.remove=X 20 | #### 21 | 22 | ## GuiModifyMacro ## 23 | gui.modify.text.title.new=Create Macro 24 | gui.modify.text.title.edit=Edit Macro 25 | 26 | gui.modify.text.command=Command 27 | gui.modify.text.key=Trigger 28 | 29 | gui.modify.text.repeat=Hold to repeat 30 | gui.modify.text.enable=Enable macro 31 | 32 | gui.modify.text.save=Save Macro 33 | #### 34 | 35 | ## GuiLayerManagement ## 36 | gui.manage.layer.text.title=Layer Management 37 | 38 | gui.manage.text.layer.add=Add Layer 39 | #### 40 | 41 | ## GuiModifyLayer ## 42 | gui.modify.layer.text.title.new=Create Layer 43 | gui.modify.layer.text.title.edit=Edit Layer 44 | 45 | gui.modify.layer.text.save=Save Layer 46 | 47 | ## CommandLayer ## 48 | command.layer.information=Layer %s - %s macro's active. 49 | 50 | ## Generic Translations ## 51 | enabled=Enabled 52 | disabled=Disabled 53 | edit=Edit 54 | #### 55 | 56 | ## Vanilla Controls ## 57 | key.macrokey.category=MacroKey Keybinding 58 | key.macrokey.management.desc=Open Macro Management GUI 59 | #### 60 | 61 | ## Missing Translations ## 62 | key.macrokey.category=MacroKey Keybinding 63 | key.macrokey.management.desc=Macro Management 64 | gui.manage.text.title=Manage Macros 65 | gui.manage.text.macro.add=Add Macro 66 | fragment.list.text.remove=X 67 | gui.modify.text.save=Save Macro 68 | gui.modify.text.command=Command 69 | gui.modify.text.key=Key 70 | gui.modify.text.repeat=Repeat 71 | gui.modify.text.enable=Enabled 72 | text.layer.display=Layer: %1$s 73 | text.layer.master=Master 74 | gui.manage.text.layer.edit=Edit Layers 75 | gui.manage.layer.text.title=Manage Layers 76 | gui.manage.text.layer.add=Add Layer 77 | gui.modify.layer.text.save=Save Layer 78 | #### 79 | -------------------------------------------------------------------------------- /src/main/resources/mcmod.info: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "modid": "macrokey", 4 | "name": "${mod_name}", 5 | "description": "This mod enables the use of commands that you can bind to keys. PSA to all admins: This is not a hacked client, nor does this mod add any change in functionality in the player's advantage.", 6 | "version": "${mod_version}", 7 | "mcversion": "${mc_version}", 8 | "url": "http://curse.com/project/243479", 9 | "updateUrl": "http://curse.com/project/243479", 10 | "authorList": ["Matt Smeets"], 11 | "credits": "Matthew Smeets (@Matt_Smeets)", 12 | "logoFile": "", 13 | "screenshots": [], 14 | "dependencies": [] 15 | } 16 | ] 17 | -------------------------------------------------------------------------------- /src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "macrokey resources", 4 | "pack_format": 3 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/test/java/com/mattsmeets/macrokey/handler/GameTickHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.handler; 2 | 3 | import com.mattsmeets.macrokey.event.ExecuteOnTickEvent; 4 | import com.mattsmeets.macrokey.event.InGameTickEvent; 5 | import com.mattsmeets.macrokey.event.MacroActivationEvent; 6 | import com.mattsmeets.macrokey.model.CommandInterface; 7 | import com.mattsmeets.macrokey.model.Macro; 8 | import com.mattsmeets.macrokey.model.MacroInterface; 9 | import com.mattsmeets.macrokey.model.lambda.ExecuteOnTickInterface; 10 | import net.minecraft.client.entity.EntityPlayerSP; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.mockito.junit.MockitoJUnitRunner; 14 | 15 | import java.util.Collections; 16 | import java.util.HashSet; 17 | import java.util.Set; 18 | 19 | import static org.mockito.Mockito.*; 20 | 21 | @RunWith(MockitoJUnitRunner.class) 22 | public class GameTickHandlerTest { 23 | 24 | @Test 25 | public void testOnKeyEventAddsMacroWhenKeyDown() { 26 | HashSet set = new HashSet(); 27 | HashSet spySet = spy(set); 28 | 29 | MacroActivationEvent event = mock(MacroActivationEvent.class); 30 | 31 | Macro macro = mock(Macro.class); 32 | 33 | when(event.getMacroState()).thenReturn(MacroActivationEvent.MacroState.KEY_DOWN); 34 | Set macros = Collections.singleton(macro); 35 | when(event.getMacros()).thenReturn(macros); 36 | 37 | GameTickHandler handler = new GameTickHandler(spySet, null); 38 | 39 | handler.onKeyEvent(event); 40 | 41 | verify(event).getMacros(); 42 | verify(event).getMacroState(); 43 | verify(spySet).addAll(macros); 44 | } 45 | 46 | @Test 47 | public void testOnKeyEventAddsMacroWhenKeyUp() { 48 | HashSet set = new HashSet(); 49 | HashSet spySet = spy(set); 50 | 51 | MacroActivationEvent event = mock(MacroActivationEvent.class); 52 | 53 | Macro macro = mock(Macro.class); 54 | 55 | when(event.getMacroState()).thenReturn(MacroActivationEvent.MacroState.KEY_UP); 56 | 57 | GameTickHandler handler = new GameTickHandler(spySet, null); 58 | 59 | handler.onKeyEvent(event); 60 | 61 | verify(event).getMacroState(); 62 | verify(spySet).removeIf(any()); 63 | } 64 | 65 | @Test 66 | public void testOnExecutorEventWillAddExecutor() { 67 | HashSet set = new HashSet(); 68 | HashSet spySet = spy(set); 69 | 70 | ExecuteOnTickEvent event = mock(ExecuteOnTickEvent.class); 71 | 72 | Macro macro = mock(Macro.class); 73 | 74 | GameTickHandler handler = new GameTickHandler(null, spySet); 75 | 76 | ExecuteOnTickInterface executor = (boolean delay) -> { 77 | }; 78 | 79 | when(event.getExecutor()).thenReturn(executor); 80 | 81 | handler.onExecutorEvent(event); 82 | 83 | verify(event).getExecutor(); 84 | verify(spySet).add(executor); 85 | } 86 | 87 | @Test 88 | public void testOnTickWillClearExecutors() { 89 | HashSet macroSet = new HashSet(); 90 | macroSet = spy(macroSet); 91 | 92 | HashSet executorSet = new HashSet(); 93 | executorSet = spy(executorSet); 94 | 95 | InGameTickEvent event = mock(InGameTickEvent.class); 96 | Macro macro = mock(Macro.class); 97 | ExecuteOnTickInterface executor = mock(ExecuteOnTickInterface.class); 98 | 99 | GameTickHandler handler = new GameTickHandler(macroSet, executorSet); 100 | 101 | handler.onTick(event); 102 | 103 | verify(executorSet).clear(); 104 | } 105 | 106 | @Test 107 | public void testOnTickWillRunAndClearExecutors() { 108 | HashSet macroSet = new HashSet(); 109 | macroSet = spy(macroSet); 110 | 111 | HashSet executorSet = new HashSet(); 112 | executorSet = spy(executorSet); 113 | 114 | InGameTickEvent event = mock(InGameTickEvent.class); 115 | Macro macro = mock(Macro.class); 116 | ExecuteOnTickInterface executor = mock(ExecuteOnTickInterface.class); 117 | 118 | GameTickHandler handler = new GameTickHandler(macroSet, executorSet); 119 | 120 | handler.onExecutorEvent(new ExecuteOnTickEvent(executor)); 121 | 122 | handler.onTick(event); 123 | 124 | verify(executor).execute(false); 125 | verify(executorSet).add(executor); 126 | verify(executorSet).forEach(any()); 127 | verify(executorSet).clear(); 128 | } 129 | 130 | @Test 131 | public void testOnTickWillRunAndClearExecutorsLimitedTick() { 132 | HashSet macroSet = new HashSet(); 133 | macroSet = spy(macroSet); 134 | 135 | HashSet executorSet = new HashSet(); 136 | executorSet = spy(executorSet); 137 | 138 | InGameTickEvent event = mock(InGameTickEvent.class); 139 | Macro macro = mock(Macro.class); 140 | ExecuteOnTickInterface executor = mock(ExecuteOnTickInterface.class); 141 | 142 | GameTickHandler handler = new GameTickHandler(macroSet, executorSet); 143 | 144 | when(event.isLimitedTick()).thenReturn(true); 145 | 146 | handler.onExecutorEvent(new ExecuteOnTickEvent(executor)); 147 | 148 | handler.onTick(event); 149 | 150 | verify(executor).execute(true); 151 | verify(executorSet).add(executor); 152 | verify(executorSet).forEach(any()); 153 | verify(executorSet).clear(); 154 | } 155 | 156 | @Test 157 | public void testOnTickWillRunNotRepeatingMacros() { 158 | HashSet macroSet = new HashSet(); 159 | macroSet = spy(macroSet); 160 | 161 | EntityPlayerSP player = mock(EntityPlayerSP.class); 162 | 163 | InGameTickEvent event = mock(InGameTickEvent.class); 164 | Macro macro = mock(Macro.class); 165 | Macro macro1 = mock(Macro.class); 166 | Macro macro2 = mock(Macro.class); 167 | 168 | when(macro.willRepeat()).thenReturn(false); 169 | when(macro1.willRepeat()).thenReturn(false); 170 | when(macro2.willRepeat()).thenReturn(true); 171 | 172 | CommandInterface command = mock(CommandInterface.class); 173 | 174 | when(macro.getCommand()).thenReturn(command); 175 | when(macro1.getCommand()).thenReturn(command); 176 | 177 | HashSet inputMacros = new HashSet(); 178 | inputMacros.add(macro); 179 | inputMacros.add(macro1); 180 | inputMacros.add(macro2); 181 | 182 | HashSet expectedMacros = new HashSet(); 183 | inputMacros.add(macro); 184 | inputMacros.add(macro1); 185 | 186 | MacroActivationEvent macroActivationEvent = mock(MacroActivationEvent.class); 187 | GameTickHandler handler = new GameTickHandler(macroSet, null); 188 | 189 | when(macroActivationEvent.getMacroState()).thenReturn(MacroActivationEvent.MacroState.KEY_DOWN); 190 | when(macroActivationEvent.getMacros()).thenReturn(inputMacros); 191 | when(event.getCurrentPlayer()).thenReturn(player); 192 | when(event.isLimitedTick()).thenReturn(false); 193 | 194 | handler.onKeyEvent(macroActivationEvent); 195 | 196 | handler.onTick(event); 197 | 198 | verify(command, times(2)).execute(player); 199 | verify(macroSet).addAll(inputMacros); 200 | verify(macroSet).removeIf(any()); 201 | } 202 | 203 | @Test 204 | public void testOnTickWillRunRepeatingMacrosOnLimitedTick() { 205 | HashSet macroSet = new HashSet(); 206 | macroSet = spy(macroSet); 207 | 208 | EntityPlayerSP player = mock(EntityPlayerSP.class); 209 | 210 | InGameTickEvent event = mock(InGameTickEvent.class); 211 | Macro macro = mock(Macro.class); 212 | Macro macro1 = mock(Macro.class); 213 | Macro macro2 = mock(Macro.class); 214 | 215 | when(macro.willRepeat()).thenReturn(false); 216 | when(macro1.willRepeat()).thenReturn(false); 217 | when(macro2.willRepeat()).thenReturn(true); 218 | 219 | CommandInterface command = mock(CommandInterface.class); 220 | 221 | when(macro.getCommand()).thenReturn(command); 222 | when(macro1.getCommand()).thenReturn(command); 223 | when(macro2.getCommand()).thenReturn(command); 224 | 225 | HashSet inputMacros = new HashSet(); 226 | inputMacros.add(macro); 227 | inputMacros.add(macro1); 228 | inputMacros.add(macro2); 229 | 230 | HashSet expectedMacros = new HashSet(); 231 | inputMacros.add(macro); 232 | inputMacros.add(macro1); 233 | 234 | MacroActivationEvent macroActivationEvent = mock(MacroActivationEvent.class); 235 | GameTickHandler handler = new GameTickHandler(macroSet, null); 236 | 237 | when(macroActivationEvent.getMacroState()).thenReturn(MacroActivationEvent.MacroState.KEY_DOWN); 238 | when(macroActivationEvent.getMacros()).thenReturn(inputMacros); 239 | when(event.getCurrentPlayer()).thenReturn(player); 240 | when(event.isLimitedTick()).thenReturn(true); 241 | 242 | handler.onKeyEvent(macroActivationEvent); 243 | 244 | handler.onTick(event); 245 | 246 | verify(command, times(3)).execute(player); 247 | verify(macroSet).addAll(inputMacros); 248 | verify(macroSet).removeIf(any()); 249 | } 250 | 251 | } 252 | -------------------------------------------------------------------------------- /src/test/java/com/mattsmeets/macrokey/model/serializer/CommandSerializerTest.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.model.serializer; 2 | 3 | import com.google.gson.*; 4 | import com.mattsmeets.macrokey.model.CommandInterface; 5 | import com.mattsmeets.macrokey.model.StringCommand; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.mockito.InjectMocks; 9 | import org.mockito.Mock; 10 | import org.mockito.junit.MockitoJUnitRunner; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | import static org.mockito.ArgumentMatchers.any; 14 | import static org.mockito.Mockito.*; 15 | 16 | @RunWith(MockitoJUnitRunner.class) 17 | public class CommandSerializerTest { 18 | 19 | @InjectMocks 20 | public CommandSerializer commandSerializer; 21 | 22 | @Mock 23 | public JsonSerializationContext serializationContext; 24 | 25 | @Mock 26 | public JsonDeserializationContext deserializationContext; 27 | 28 | @Test 29 | public void testSerializeWillConvertString() { 30 | StringCommand command = new StringCommand("Magic String"); 31 | StringCommand commandSpy = spy(command); 32 | 33 | JsonObject obj = new JsonObject(); 34 | obj.addProperty("test", "testValue"); 35 | 36 | when(serializationContext.serialize(any())).thenReturn(obj); 37 | 38 | JsonElement result = commandSerializer.serialize(commandSpy, CommandInterface.class, serializationContext); 39 | 40 | verify(serializationContext).serialize("Magic String"); 41 | 42 | assertEquals("{\"test\":\"testValue\"}", result.toString()); 43 | } 44 | 45 | @Test(expected = JsonParseException.class) 46 | public void testDeserializeWillThrowErrorWhenTypeNotFound() { 47 | JsonObject obj = new JsonObject(); 48 | obj.addProperty("type", "someRandomNotExistingValue"); 49 | 50 | commandSerializer.deserialize(obj, CommandInterface.class, deserializationContext); 51 | } 52 | 53 | @Test(expected = JsonParseException.class) 54 | public void testDeserializeWillThrowErrorWhenTypeNull() { 55 | JsonObject obj = new JsonObject(); 56 | 57 | commandSerializer.deserialize(obj, CommandInterface.class, deserializationContext); 58 | } 59 | 60 | @Test 61 | public void testDeserializeWillDeserializeStringType() { 62 | JsonObject obj = new JsonObject(); 63 | obj.addProperty("type", "string"); 64 | obj.addProperty("command", "SomeRandomCommand"); 65 | 66 | when(deserializationContext.deserialize(any(), any())).thenReturn(new StringCommand("SomeRandomCommand")); 67 | 68 | CommandInterface command = commandSerializer.deserialize(obj, CommandInterface.class, deserializationContext); 69 | 70 | assertEquals("string", command.getCommandType()); 71 | assertEquals("SomeRandomCommand", command.toString()); 72 | 73 | verify(deserializationContext).deserialize(obj, StringCommand.class); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/com/mattsmeets/macrokey/repository/BindingsRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.repository; 2 | 3 | import com.google.gson.JsonObject; 4 | import com.mattsmeets.macrokey.model.*; 5 | import com.mattsmeets.macrokey.service.JsonConfig; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.mockito.InjectMocks; 9 | import org.mockito.Mock; 10 | import org.mockito.junit.MockitoJUnitRunner; 11 | 12 | import java.io.IOException; 13 | import java.util.Collections; 14 | import java.util.HashSet; 15 | import java.util.Set; 16 | import java.util.UUID; 17 | 18 | import static org.junit.Assert.*; 19 | import static org.mockito.ArgumentMatchers.any; 20 | import static org.mockito.ArgumentMatchers.eq; 21 | import static org.mockito.Mockito.*; 22 | 23 | @RunWith(MockitoJUnitRunner.class) 24 | public class BindingsRepositoryTest { 25 | 26 | @Mock 27 | public JsonConfig jsonConfig; 28 | 29 | @InjectMocks 30 | public BindingsRepository bindingsRepository; 31 | 32 | @Test 33 | public void testFindLayerByUUIDWithSyncFalseGoodCase() throws IOException { 34 | BindingsFile file = mock(BindingsFile.class); 35 | Layer layer = new Layer("test"); 36 | 37 | Set input = new HashSet<>(); 38 | input.add(layer); 39 | 40 | this.bindingsRepository.setBindingsFile(file); 41 | 42 | when(file.getLayers()).thenReturn(input); 43 | 44 | LayerInterface result = this.bindingsRepository.findLayerByUUID(layer.getULID(), false); 45 | 46 | assertEquals(layer, result); 47 | 48 | verify(jsonConfig, times(0)).saveObjectToJson(file); 49 | } 50 | 51 | @Test(expected = IOException.class) 52 | public void testFindLayerByUUIDWithSyncTrueGoodCase() throws IOException { 53 | BindingsFile file = mock(BindingsFile.class); 54 | Layer layer = new Layer("test"); 55 | 56 | this.bindingsRepository.setBindingsFile(file); 57 | 58 | when(jsonConfig.getJSONObject()).thenThrow(new IOException()); 59 | 60 | LayerInterface result = this.bindingsRepository.findLayerByUUID(layer.getULID(), true); 61 | 62 | assertEquals(layer, result); 63 | } 64 | 65 | @Test 66 | public void testFindLayerByUUIDWithSyncFalseBadCase() throws IOException { 67 | BindingsFile file = mock(BindingsFile.class); 68 | Layer layer = new Layer("test"); 69 | Layer layer1 = new Layer("Hello World"); 70 | 71 | Set input = new HashSet<>(); 72 | input.add(layer); 73 | 74 | this.bindingsRepository.setBindingsFile(file); 75 | 76 | when(file.getLayers()).thenReturn(input); 77 | 78 | LayerInterface result = this.bindingsRepository.findLayerByUUID(layer1.getULID(), false); 79 | 80 | assertEquals(null, result); 81 | 82 | verify(jsonConfig, times(0)).saveObjectToJson(file); 83 | } 84 | 85 | @Test(expected = IllegalStateException.class) 86 | public void testFindLayerByUUIDWithSyncFalseMultiple() throws IOException { 87 | BindingsFile file = mock(BindingsFile.class); 88 | Layer layer = new Layer("test"); 89 | Layer layer1 = new Layer(layer.getULID(), "Hello World"); 90 | 91 | Set input = new HashSet<>(); 92 | input.add(layer); 93 | input.add(layer1); 94 | 95 | this.bindingsRepository.setBindingsFile(file); 96 | 97 | when(file.getLayers()).thenReturn(input); 98 | 99 | LayerInterface result = this.bindingsRepository.findLayerByUUID(layer.getULID(), false); 100 | 101 | assertEquals(null, result); 102 | 103 | verify(jsonConfig, times(0)).saveObjectToJson(file); 104 | } 105 | 106 | @Test 107 | public void testFindAllLayersWithSyncFalseGoodCase() throws IOException { 108 | BindingsFile file = mock(BindingsFile.class); 109 | Layer layer = mock(Layer.class); 110 | 111 | Set expectedResult = new HashSet<>(); 112 | expectedResult.add(layer); 113 | 114 | Set input = new HashSet<>(); 115 | input.add(layer); 116 | 117 | this.bindingsRepository.setBindingsFile(file); 118 | 119 | when(file.getLayers()).thenReturn(input); 120 | 121 | Set result = this.bindingsRepository.findAllLayers(false); 122 | 123 | assertEquals(expectedResult, result); 124 | } 125 | 126 | @Test 127 | public void testFindAllLayersWithSyncFalseBadCase() throws IOException { 128 | BindingsFile file = mock(BindingsFile.class); 129 | Layer layer = mock(Layer.class); 130 | 131 | Set expectedResult = new HashSet<>(); 132 | 133 | Set input = new HashSet<>(); 134 | input.add(layer); 135 | 136 | this.bindingsRepository.setBindingsFile(file); 137 | 138 | when(file.getLayers()).thenReturn(input); 139 | 140 | Set result = this.bindingsRepository.findAllLayers(false); 141 | 142 | assertNotEquals(expectedResult, result); 143 | } 144 | 145 | @Test(expected = IOException.class) 146 | public void testFindAllLayersWithSyncTrue() throws IOException { 147 | Layer layer = mock(Layer.class); 148 | 149 | Set expectedResult = new HashSet<>(); 150 | expectedResult.add(layer); 151 | 152 | when(jsonConfig.getJSONObject()).thenThrow(new IOException()); 153 | 154 | Set result = this.bindingsRepository.findAllLayers(true); 155 | 156 | // will never come here, if so it should go red 157 | assertEquals(expectedResult, result); 158 | } 159 | 160 | @Test 161 | public void testAddLayerWithSyncFalse() throws IOException { 162 | Macro macro = new Macro(10, "/gamemode 1", true); 163 | Layer layer = new Layer("Layer 1"); 164 | layer.addMacro(macro); 165 | 166 | BindingsFile file = new BindingsFile(2, new HashSet<>()); 167 | 168 | BindingsFile spyFile = spy(file); 169 | 170 | this.bindingsRepository.setBindingsFile(spyFile); 171 | 172 | doCallRealMethod().when(spyFile).addLayer(any()); 173 | 174 | this.bindingsRepository.addLayer(layer, false); 175 | 176 | Set expectedResult = new HashSet<>(); 177 | expectedResult.add(layer); 178 | 179 | assertEquals(expectedResult, file.getLayers()); 180 | 181 | verify(spyFile).addLayer(layer); 182 | 183 | verify(jsonConfig, times(0)).saveObjectToJson(spyFile); 184 | 185 | verifyNoMoreInteractions(spyFile); 186 | } 187 | 188 | @Test 189 | public void testAddLayerWithSyncTrue() throws IOException { 190 | Macro macro = new Macro(10, "/gamemode 1", true); 191 | Layer layer = new Layer("Layer 1"); 192 | layer.addMacro(macro); 193 | 194 | BindingsFile file = new BindingsFile(2, new HashSet<>()); 195 | 196 | BindingsFile spyFile = spy(file); 197 | 198 | this.bindingsRepository.setBindingsFile(spyFile); 199 | 200 | doCallRealMethod().when(spyFile).addLayer(any()); 201 | 202 | this.bindingsRepository.addLayer(layer, true); 203 | 204 | Set expectedResult = new HashSet<>(); 205 | expectedResult.add(layer); 206 | 207 | assertEquals(expectedResult, file.getLayers()); 208 | 209 | verify(spyFile).addLayer(layer); 210 | 211 | verify(jsonConfig).saveObjectToJson(spyFile); 212 | 213 | verifyNoMoreInteractions(spyFile); 214 | } 215 | 216 | @Test 217 | public void testUpdateLayerWithSyncFalse() throws IOException { 218 | BindingsFile file = new BindingsFile(2, new HashSet<>()); 219 | BindingsFile fileSpy = spy(file); 220 | 221 | this.bindingsRepository.setBindingsFile(fileSpy); 222 | 223 | Layer layer = new Layer("Hello World"); 224 | Layer layer1 = new Layer("Hello World1"); 225 | Layer layer2 = new Layer(layer1.getULID(), "Hello World2"); 226 | 227 | Layer layerSpy = spy(layer); 228 | Layer layer1Spy = spy(layer1); 229 | Layer layer2Spy = spy(layer2); 230 | 231 | assertEquals(0, this.bindingsRepository.findAllLayers(false).size()); 232 | 233 | this.bindingsRepository.addLayer(layerSpy, false); 234 | this.bindingsRepository.addLayer(layer1Spy, false); 235 | 236 | assertEquals(2, this.bindingsRepository.findAllLayers(false).size()); 237 | 238 | this.bindingsRepository.updateLayer(layer2Spy, false); 239 | 240 | assertEquals(2, this.bindingsRepository.findAllLayers(false).size()); 241 | assertEquals(layer2Spy, this.bindingsRepository.findLayerByUUID(layer1.getULID(), false)); 242 | 243 | verify(fileSpy).setLayers(any()); 244 | 245 | verify(layerSpy, times(2)).getULID(); 246 | verify(layer1Spy).getULID(); 247 | verify(layer2Spy, times(3)).getULID(); 248 | 249 | verify(jsonConfig, times(0)).saveObjectToJson(fileSpy); 250 | } 251 | 252 | @Test 253 | public void testUpdateLayerWithSyncTrue() throws IOException { 254 | BindingsFile file = new BindingsFile(2, new HashSet<>()); 255 | BindingsFile fileSpy = spy(file); 256 | 257 | this.bindingsRepository.setBindingsFile(fileSpy); 258 | 259 | Layer layer = new Layer("Hello World"); 260 | Layer layer1 = new Layer("Hello World1"); 261 | Layer layer2 = new Layer(layer1.getULID(), "Hello World2"); 262 | 263 | Layer layerSpy = spy(layer); 264 | Layer layer1Spy = spy(layer1); 265 | Layer layer2Spy = spy(layer2); 266 | 267 | assertEquals(0, this.bindingsRepository.findAllLayers(false).size()); 268 | 269 | this.bindingsRepository.addLayer(layerSpy, false); 270 | this.bindingsRepository.addLayer(layer1Spy, false); 271 | 272 | assertEquals(2, this.bindingsRepository.findAllLayers(false).size()); 273 | 274 | this.bindingsRepository.updateLayer(layer2Spy, true); 275 | 276 | assertEquals(2, this.bindingsRepository.findAllLayers(false).size()); 277 | 278 | assertEquals(layer2Spy, this.bindingsRepository.findLayerByUUID(layer1.getULID(), false)); 279 | 280 | verify(fileSpy).setLayers(any()); 281 | 282 | verify(layerSpy, times(2)).getULID(); 283 | verify(layer1Spy).getULID(); 284 | verify(layer2Spy, times(3)).getULID(); 285 | 286 | verify(jsonConfig, times(1)).saveObjectToJson(fileSpy); 287 | } 288 | 289 | @Test 290 | public void testDeleteLayerUUIDWithSyncFalse() throws IOException { 291 | Layer layer1 = new Layer("Hello World"); 292 | Layer layer2 = new Layer("Hello World1"); 293 | Layer layer3 = new Layer("Hello World2"); 294 | 295 | Layer layer1Spy = spy(layer1); 296 | Layer layer2Spy = spy(layer2); 297 | Layer layer3Spy = spy(layer3); 298 | 299 | Set layers = new HashSet<>(); 300 | layers.add(layer1Spy); 301 | layers.add(layer2Spy); 302 | layers.add(layer3Spy); 303 | 304 | Set expectedResult = new HashSet<>(); 305 | expectedResult.add(layer2Spy); 306 | expectedResult.add(layer3Spy); 307 | 308 | BindingsFile file = new BindingsFile(2, new HashSet<>(), layers); 309 | BindingsFile fileSpy = spy(file); 310 | 311 | this.bindingsRepository.setBindingsFile(fileSpy); 312 | 313 | assertEquals(3, this.bindingsRepository.findAllLayers(false).size()); 314 | 315 | this.bindingsRepository.deleteLayer(layer1.getULID(), false); 316 | 317 | assertEquals(2, this.bindingsRepository.findAllLayers(false).size()); 318 | assertEquals(expectedResult, this.bindingsRepository.findAllLayers(false)); 319 | 320 | verify(layer1Spy).getULID(); 321 | verify(layer2Spy).getULID(); 322 | verify(layer3Spy).getULID(); 323 | verify(fileSpy).setLayers(expectedResult); 324 | 325 | verify(jsonConfig, times(0)).saveObjectToJson(fileSpy); 326 | } 327 | 328 | @Test 329 | public void testDeleteLayerUUIDIsActiveLayerWithSyncFalse() throws IOException { 330 | Layer layer1 = new Layer("Hello World"); 331 | Layer layer2 = new Layer("Hello World1"); 332 | Layer layer3 = new Layer("Hello World2"); 333 | 334 | Layer layer1Spy = spy(layer1); 335 | Layer layer2Spy = spy(layer2); 336 | Layer layer3Spy = spy(layer3); 337 | 338 | Set layers = new HashSet<>(); 339 | layers.add(layer1Spy); 340 | layers.add(layer2Spy); 341 | layers.add(layer3Spy); 342 | 343 | Set expectedResult = new HashSet<>(); 344 | expectedResult.add(layer2Spy); 345 | expectedResult.add(layer3Spy); 346 | 347 | BindingsFile file = new BindingsFile(2, new HashSet<>(), layers); 348 | BindingsFile fileSpy = spy(file); 349 | 350 | this.bindingsRepository.setBindingsFile(fileSpy); 351 | 352 | this.bindingsRepository.setActiveLayer(layer1, false); 353 | 354 | assertEquals(3, this.bindingsRepository.findAllLayers(false).size()); 355 | assertTrue(this.bindingsRepository.isActiveLayer(layer1, false)); 356 | 357 | this.bindingsRepository.deleteLayer(layer1.getULID(), false); 358 | 359 | assertEquals(2, this.bindingsRepository.findAllLayers(false).size()); 360 | assertEquals(expectedResult, this.bindingsRepository.findAllLayers(false)); 361 | assertFalse(this.bindingsRepository.isActiveLayer(layer1, false)); 362 | assertNull(this.bindingsRepository.findActiveLayer(false)); 363 | 364 | verify(layer1Spy, times(1)).getULID(); 365 | verify(layer2Spy, times(2)).getULID(); 366 | verify(layer3Spy, times(2)).getULID(); 367 | verify(fileSpy).setLayers(expectedResult); 368 | 369 | verify(jsonConfig, times(0)).saveObjectToJson(fileSpy); 370 | } 371 | 372 | @Test 373 | public void testDeleteLayerUUIDWithSyncTrue() throws IOException { 374 | Layer layer1 = new Layer("Hello World"); 375 | Layer layer2 = new Layer("Hello World1"); 376 | Layer layer3 = new Layer("Hello World2"); 377 | 378 | Layer layer1Spy = spy(layer1); 379 | Layer layer2Spy = spy(layer2); 380 | Layer layer3Spy = spy(layer3); 381 | 382 | Set layers = new HashSet<>(); 383 | layers.add(layer1Spy); 384 | layers.add(layer2Spy); 385 | layers.add(layer3Spy); 386 | 387 | Set expectedResult = new HashSet<>(); 388 | expectedResult.add(layer2Spy); 389 | expectedResult.add(layer3Spy); 390 | 391 | BindingsFile file = new BindingsFile(2, new HashSet<>(), layers); 392 | BindingsFile fileSpy = spy(file); 393 | 394 | this.bindingsRepository.setBindingsFile(fileSpy); 395 | 396 | assertEquals(3, this.bindingsRepository.findAllLayers(false).size()); 397 | 398 | this.bindingsRepository.deleteLayer(layer1.getULID(), true); 399 | 400 | assertEquals(2, this.bindingsRepository.findAllLayers(false).size()); 401 | assertEquals(expectedResult, this.bindingsRepository.findAllLayers(false)); 402 | 403 | verify(layer1Spy).getULID(); 404 | verify(layer2Spy).getULID(); 405 | verify(layer3Spy).getULID(); 406 | verify(fileSpy).setLayers(expectedResult); 407 | 408 | verify(jsonConfig, times(1)).saveObjectToJson(fileSpy); 409 | } 410 | 411 | @Test 412 | public void testDeleteLayerWithSyncFalse() throws IOException { 413 | Layer layer1 = new Layer("Hello World"); 414 | Layer layer2 = new Layer("Hello World1"); 415 | Layer layer3 = new Layer("Hello World2"); 416 | 417 | Layer layer1Spy = spy(layer1); 418 | Layer layer2Spy = spy(layer2); 419 | Layer layer3Spy = spy(layer3); 420 | 421 | Set layers = new HashSet<>(); 422 | layers.add(layer1Spy); 423 | layers.add(layer2Spy); 424 | layers.add(layer3Spy); 425 | 426 | Set expectedResult = new HashSet<>(); 427 | expectedResult.add(layer2Spy); 428 | expectedResult.add(layer3Spy); 429 | 430 | BindingsFile file = new BindingsFile(2, new HashSet<>(), layers); 431 | BindingsFile fileSpy = spy(file); 432 | 433 | this.bindingsRepository.setBindingsFile(fileSpy); 434 | 435 | assertEquals(3, this.bindingsRepository.findAllLayers(false).size()); 436 | 437 | this.bindingsRepository.deleteLayer(layer1, false); 438 | 439 | assertEquals(2, this.bindingsRepository.findAllLayers(false).size()); 440 | assertEquals(expectedResult, this.bindingsRepository.findAllLayers(false)); 441 | 442 | verify(layer1Spy).getULID(); 443 | verify(layer2Spy).getULID(); 444 | verify(layer3Spy).getULID(); 445 | verify(fileSpy).setLayers(expectedResult); 446 | 447 | verify(jsonConfig, times(0)).saveObjectToJson(fileSpy); 448 | } 449 | 450 | @Test 451 | public void testDeleteLayerWithSyncTrue() throws IOException { 452 | Layer layer1 = new Layer("Hello World"); 453 | Layer layer2 = new Layer("Hello World1"); 454 | Layer layer3 = new Layer("Hello World2"); 455 | 456 | Layer layer1Spy = spy(layer1); 457 | Layer layer2Spy = spy(layer2); 458 | Layer layer3Spy = spy(layer3); 459 | 460 | Set layers = new HashSet<>(); 461 | layers.add(layer1Spy); 462 | layers.add(layer2Spy); 463 | layers.add(layer3Spy); 464 | 465 | Set expectedResult = new HashSet<>(); 466 | expectedResult.add(layer2Spy); 467 | expectedResult.add(layer3Spy); 468 | 469 | BindingsFile file = new BindingsFile(2, new HashSet<>(), layers); 470 | BindingsFile fileSpy = spy(file); 471 | 472 | this.bindingsRepository.setBindingsFile(fileSpy); 473 | 474 | assertEquals(3, this.bindingsRepository.findAllLayers(false).size()); 475 | 476 | this.bindingsRepository.deleteLayer(layer1, true); 477 | 478 | assertEquals(2, this.bindingsRepository.findAllLayers(false).size()); 479 | assertEquals(expectedResult, this.bindingsRepository.findAllLayers(false)); 480 | 481 | verify(layer1Spy).getULID(); 482 | verify(layer2Spy).getULID(); 483 | verify(layer3Spy).getULID(); 484 | verify(fileSpy).setLayers(expectedResult); 485 | 486 | verify(jsonConfig, times(1)).saveObjectToJson(fileSpy); 487 | } 488 | 489 | @Test 490 | public void testFindAllMacrosWithSyncFalseGoodCase() throws IOException { 491 | BindingsFile file = mock(BindingsFile.class); 492 | Macro macro = mock(Macro.class); 493 | 494 | Set expectedResult = new HashSet<>(); 495 | expectedResult.add(macro); 496 | 497 | Set input = new HashSet<>(); 498 | input.add(macro); 499 | 500 | this.bindingsRepository.setBindingsFile(file); 501 | 502 | when(file.getMacros()).thenReturn(input); 503 | 504 | Set result = this.bindingsRepository.findAllMacros(false); 505 | 506 | assertEquals(expectedResult, result); 507 | } 508 | 509 | @Test 510 | public void testFindAllMacrosWithSyncFalseBadCase() throws IOException { 511 | BindingsFile file = mock(BindingsFile.class); 512 | Macro macro = mock(Macro.class); 513 | 514 | Set expectedResult = new HashSet<>(); 515 | 516 | Set input = new HashSet<>(); 517 | input.add(macro); 518 | 519 | this.bindingsRepository.setBindingsFile(file); 520 | 521 | when(file.getMacros()).thenReturn(input); 522 | 523 | Set result = this.bindingsRepository.findAllMacros(false); 524 | 525 | assertNotEquals(expectedResult, result); 526 | } 527 | 528 | @Test(expected = IOException.class) 529 | public void testFindAllMacrosWithSyncTrue() throws IOException { 530 | Macro macro = mock(Macro.class); 531 | 532 | Set expectedResult = new HashSet<>(); 533 | expectedResult.add(macro); 534 | 535 | when(jsonConfig.getJSONObject()).thenThrow(new IOException()); 536 | 537 | Set result = this.bindingsRepository.findAllMacros(true); 538 | 539 | // will never come here, if so it should go red 540 | assertEquals(expectedResult, result); 541 | } 542 | 543 | @Test 544 | public void testFindMacroByKeycodeWithSyncFalseGoodCase() throws IOException { 545 | BindingsFile file = mock(BindingsFile.class); 546 | 547 | Macro macro1 = new Macro(1, "testing", true); 548 | Macro macro2 = new Macro(1, "testing", true); 549 | Macro macro3 = new Macro(1, "testing", false); 550 | Macro macro4 = new Macro(2, "testing", true); 551 | Macro macro5 = new Macro(3, "testing", false); 552 | 553 | Set expectedResult = new HashSet<>(); 554 | expectedResult.add(macro1); 555 | expectedResult.add(macro2); 556 | 557 | Set input = new HashSet<>(); 558 | input.add(macro1); 559 | input.add(macro2); 560 | input.add(macro3); 561 | input.add(macro4); 562 | input.add(macro5); 563 | 564 | this.bindingsRepository.setBindingsFile(file); 565 | 566 | when(file.getMacros()).thenReturn(input); 567 | 568 | Set result = this.bindingsRepository.findMacroByKeycode(1, null, false); 569 | 570 | assertEquals(expectedResult, result); 571 | } 572 | 573 | @Test 574 | public void testFindMacroByKeycodeWithSyncFalseMacroInLayer() throws IOException { 575 | BindingsFile file = mock(BindingsFile.class); 576 | 577 | Macro macro1 = new Macro(1, "testing", true); 578 | Macro macro2 = new Macro(1, "testing", true); 579 | Macro macro3 = new Macro(1, "testing", false); 580 | Macro macro4 = new Macro(2, "testing", true); 581 | Macro macro5 = new Macro(3, "testing", false); 582 | 583 | Set expectedResult = new HashSet<>(); 584 | expectedResult.add(macro4); 585 | 586 | Set input = new HashSet<>(); 587 | input.add(macro1); 588 | input.add(macro2); 589 | input.add(macro3); 590 | input.add(macro4); 591 | input.add(macro5); 592 | 593 | LayerInterface layer1 = new Layer(); 594 | layer1.addMacro(macro4); 595 | 596 | Set layers = new HashSet<>(); 597 | layers.add(layer1); 598 | 599 | this.bindingsRepository.setBindingsFile(file); 600 | 601 | when(file.getMacros()).thenReturn(input); 602 | when(file.getLayers()).thenReturn(layers); 603 | 604 | Set result = this.bindingsRepository.findMacroByKeycode(2, layer1, false); 605 | 606 | assertEquals(expectedResult, result); 607 | } 608 | 609 | @Test 610 | public void testFindMacroByKeycodeWithSyncFalseMacroNotInLayer() throws IOException { 611 | BindingsFile file = mock(BindingsFile.class); 612 | 613 | Macro macro1 = new Macro(1, "testing", true); 614 | Macro macro2 = new Macro(1, "testing", true); 615 | Macro macro3 = new Macro(1, "testing", false); 616 | Macro macro4 = new Macro(2, "testing", true); 617 | Macro macro5 = new Macro(3, "testing", false); 618 | 619 | Set expectedResult = new HashSet<>(); 620 | 621 | Set input = new HashSet<>(); 622 | input.add(macro1); 623 | input.add(macro2); 624 | input.add(macro3); 625 | input.add(macro4); 626 | input.add(macro5); 627 | 628 | LayerInterface layer1 = new Layer(); 629 | layer1.addMacro(macro2); 630 | 631 | Set layers = new HashSet<>(); 632 | layers.add(layer1); 633 | 634 | this.bindingsRepository.setBindingsFile(file); 635 | 636 | when(file.getMacros()).thenReturn(input); 637 | when(file.getLayers()).thenReturn(layers); 638 | 639 | Set result = this.bindingsRepository.findMacroByKeycode(2, layer1, false); 640 | 641 | assertEquals(expectedResult, result); 642 | } 643 | 644 | @Test(expected = IOException.class) 645 | public void testFindMacroByUUIDWithSyncTrue() throws IOException { 646 | BindingsFile file = mock(BindingsFile.class); 647 | MacroInterface macro = new Macro(); 648 | 649 | this.bindingsRepository.setBindingsFile(file); 650 | 651 | when(jsonConfig.getJSONObject()).thenThrow(new IOException()); 652 | 653 | MacroInterface result = this.bindingsRepository.findMacroByUUID(macro.getUMID(), true); 654 | 655 | assertEquals(macro, result); 656 | } 657 | 658 | @Test(expected = IllegalStateException.class) 659 | public void testFindMacroByUUIDWithSyncFalseMoreThanOne() throws IOException { 660 | BindingsFile file = mock(BindingsFile.class); 661 | MacroInterface macro = new Macro(); 662 | MacroInterface macro1 = new Macro(macro.getUMID(), macro.getKeyCode(), macro.getCommand(), macro.isActive(), macro.willRepeat()); 663 | 664 | Set macros = new HashSet<>(); 665 | macros.add(macro1); 666 | macros.add(macro); 667 | 668 | when(file.getMacros()).thenReturn(macros); 669 | 670 | this.bindingsRepository.setBindingsFile(file); 671 | 672 | MacroInterface result = this.bindingsRepository.findMacroByUUID(macro.getUMID(), false); 673 | 674 | assertEquals(null, result); 675 | } 676 | 677 | @Test 678 | public void testFindMacroByUUIDWithSyncFalseGoodCase() throws IOException { 679 | BindingsFile file = mock(BindingsFile.class); 680 | 681 | BindingsFile spyFile = spy(file); 682 | 683 | Macro macro1 = new Macro(1, "testing", true); 684 | Macro macro2 = new Macro(1, "testing", true); 685 | Macro macro3 = new Macro(1, "testing", false); 686 | Macro macro4 = new Macro(2, "testing", true); 687 | Macro macro5 = new Macro(3, "testing", false); 688 | 689 | Set input = new HashSet<>(); 690 | input.add(macro1); 691 | input.add(macro2); 692 | input.add(macro3); 693 | input.add(macro4); 694 | input.add(macro5); 695 | 696 | this.bindingsRepository.setBindingsFile(spyFile); 697 | 698 | when(spyFile.getMacros()).thenReturn(input); 699 | 700 | MacroInterface result = this.bindingsRepository.findMacroByUUID(macro1.getUMID(), false); 701 | 702 | assertEquals(macro1, result); 703 | } 704 | 705 | @Test 706 | public void testFindMacroByKeycodeWithSyncFalseAndLayerDependent() throws IOException { 707 | BindingsFile file = mock(BindingsFile.class); 708 | 709 | Layer layer = new Layer("Hello World!"); 710 | 711 | Macro macro1 = new Macro(1, "testing", true); 712 | Macro macro2 = new Macro(1, "testing", true); 713 | Macro macro3 = new Macro(1, "testing", false); 714 | Macro macro4 = new Macro(1, "testing", true); 715 | Macro macro5 = new Macro(3, "testing", false); 716 | 717 | layer.addMacro(macro1); 718 | layer.addMacro(macro2); 719 | layer.addMacro(macro3); 720 | layer.addMacro(macro4); 721 | 722 | when(file.getLayers()).thenReturn(Collections.singleton(layer)); 723 | 724 | Set expectedResult = new HashSet<>(); 725 | expectedResult.add(macro1); 726 | expectedResult.add(macro2); 727 | expectedResult.add(macro4); 728 | 729 | Set input = new HashSet<>(); 730 | input.add(macro1); 731 | input.add(macro2); 732 | input.add(macro3); 733 | input.add(macro4); 734 | input.add(macro5); 735 | 736 | this.bindingsRepository.setBindingsFile(file); 737 | 738 | when(file.getMacros()).thenReturn(input); 739 | 740 | Set result = this.bindingsRepository.findMacroByKeycode(1, layer, false); 741 | 742 | assertEquals(expectedResult, result); 743 | } 744 | 745 | @Test 746 | public void testFindMacroByKeycodeWithSyncFalseBadCase() throws IOException { 747 | BindingsFile file = mock(BindingsFile.class); 748 | 749 | Macro macro1 = new Macro(1, "testing", true); 750 | Macro macro2 = new Macro(1, "testing", true); 751 | Macro macro3 = new Macro(1, "testing", false); 752 | Macro macro4 = new Macro(2, "testing", true); 753 | Macro macro5 = new Macro(3, "testing", false); 754 | 755 | Macro macro1Spy = spy(macro1); 756 | Macro macro2Spy = spy(macro2); 757 | Macro macro3Spy = spy(macro3); 758 | Macro macro4Spy = spy(macro4); 759 | Macro macro5Spy = spy(macro5); 760 | 761 | Set expectedResult = new HashSet<>(); 762 | expectedResult.add(macro1Spy); 763 | // expect to return macro2 764 | 765 | Set input = new HashSet<>(); 766 | input.add(macro1Spy); 767 | input.add(macro2Spy); 768 | input.add(macro3Spy); 769 | input.add(macro4Spy); 770 | input.add(macro5Spy); 771 | 772 | this.bindingsRepository.setBindingsFile(file); 773 | 774 | when(file.getMacros()).thenReturn(input); 775 | 776 | Set result = this.bindingsRepository.findMacroByKeycode(1, null, false); 777 | 778 | verify(macro1Spy, times(1)).getKeyCode(); 779 | verify(macro1Spy, times(1)).isActive(); 780 | 781 | verify(macro2Spy, times(1)).getKeyCode(); 782 | verify(macro2Spy, times(1)).isActive(); 783 | 784 | verify(macro3Spy, times(1)).getKeyCode(); 785 | verify(macro3Spy, times(1)).isActive(); 786 | 787 | verify(macro4Spy, times(1)).getKeyCode(); 788 | verify(macro4Spy, times(0)).isActive(); 789 | 790 | verify(macro5Spy, times(1)).getKeyCode(); 791 | verify(macro5Spy, times(0)).isActive(); 792 | 793 | verifyNoMoreInteractions(macro1Spy, macro2Spy, macro3Spy, macro4Spy, macro5Spy); 794 | 795 | assertNotEquals(expectedResult, result); 796 | } 797 | 798 | @Test(expected = IOException.class) 799 | public void testFindMacroByKeycodeWithSyncTrue() throws IOException { 800 | Macro macro = mock(Macro.class); 801 | 802 | Set expectedResult = new HashSet<>(); 803 | expectedResult.add(macro); 804 | 805 | when(jsonConfig.getJSONObject()).thenThrow(new IOException()); 806 | 807 | Set result = this.bindingsRepository.findMacroByKeycode(1, null, true); 808 | 809 | // will never come here, if so it should go red 810 | assertEquals(expectedResult, result); 811 | } 812 | 813 | @Test 814 | public void testAddMacroWithSyncFalse() throws IOException { 815 | Macro macro = new Macro(10, "/gamemode 1", true); 816 | BindingsFile file = new BindingsFile(2, new HashSet<>()); 817 | 818 | BindingsFile spyFile = spy(file); 819 | 820 | this.bindingsRepository.setBindingsFile(spyFile); 821 | 822 | doCallRealMethod().when(spyFile).addMacro(any()); 823 | 824 | this.bindingsRepository.addMacro(macro, false); 825 | 826 | Set expectedResult = new HashSet<>(); 827 | expectedResult.add(macro); 828 | 829 | assertEquals(expectedResult, file.getMacros()); 830 | 831 | verify(spyFile).addMacro(macro); 832 | 833 | verify(jsonConfig, times(0)).saveObjectToJson(spyFile); 834 | 835 | verifyNoMoreInteractions(spyFile); 836 | } 837 | 838 | @Test 839 | public void testAddMacroWithSyncTrue() throws IOException { 840 | Macro macro = new Macro(10, "/gamemode 1", true); 841 | BindingsFile file = new BindingsFile(2, new HashSet<>()); 842 | 843 | BindingsFile spyFile = spy(file); 844 | 845 | this.bindingsRepository.setBindingsFile(spyFile); 846 | 847 | doCallRealMethod().when(spyFile).addMacro(any()); 848 | 849 | this.bindingsRepository.addMacro(macro, true); 850 | 851 | Set expectedResult = new HashSet<>(); 852 | expectedResult.add(macro); 853 | 854 | assertEquals(expectedResult, file.getMacros()); 855 | 856 | verify(spyFile).addMacro(macro); 857 | 858 | verify(jsonConfig).saveObjectToJson(spyFile); 859 | 860 | verifyNoMoreInteractions(spyFile); 861 | } 862 | 863 | @Test 864 | public void testFindVersion() { 865 | int version = 1000; 866 | 867 | BindingsFile bindingsFile = new BindingsFile(version); 868 | BindingsFile fileSpy = spy(bindingsFile); 869 | 870 | doCallRealMethod().when(fileSpy).getVersion(); 871 | 872 | this.bindingsRepository.setBindingsFile(fileSpy); 873 | 874 | assertEquals(version, this.bindingsRepository.findFileVersion()); 875 | 876 | verify(fileSpy).getVersion(); 877 | } 878 | 879 | @Test 880 | public void testSaveConfiguration() throws IOException { 881 | BindingsFile bindingsFile = new BindingsFile(2, new HashSet<>()); 882 | 883 | this.bindingsRepository.setBindingsFile(bindingsFile); 884 | 885 | this.bindingsRepository.saveConfiguration(); 886 | 887 | verify(this.jsonConfig).saveObjectToJson(bindingsFile); 888 | } 889 | 890 | @Test 891 | public void testUpdateMacroWithSyncFalse() throws IOException { 892 | BindingsFile file = new BindingsFile(2, new HashSet<>()); 893 | BindingsFile fileSpy = spy(file); 894 | 895 | this.bindingsRepository.setBindingsFile(fileSpy); 896 | 897 | Macro macro = new Macro(10, "test", false); 898 | Macro macro1 = new Macro(50, "testing", true); 899 | Macro newMacro = new Macro(macro.getUMID(), 20, new StringCommand("test2"), true, false); 900 | 901 | Macro macroSpy = spy(macro); 902 | Macro macro1Spy = spy(macro1); 903 | Macro newMacroSpy = spy(newMacro); 904 | 905 | assertEquals(0, this.bindingsRepository.findAllMacros(false).size()); 906 | 907 | this.bindingsRepository.addMacro(macroSpy, false); 908 | this.bindingsRepository.addMacro(macro1Spy, false); 909 | 910 | assertEquals(2, this.bindingsRepository.findAllMacros(false).size()); 911 | 912 | this.bindingsRepository.updateMacro(newMacroSpy, false); 913 | 914 | assertEquals(2, this.bindingsRepository.findAllMacros(false).size()); 915 | 916 | Set newMacroSet = new HashSet<>(); 917 | newMacroSet.add(newMacroSpy); 918 | 919 | assertEquals(newMacroSet, this.bindingsRepository.findMacroByKeycode(20, null, false)); 920 | 921 | verify(fileSpy).setMacros(any()); 922 | 923 | verify(macroSpy).getUMID(); 924 | verify(macro1Spy).getUMID(); 925 | verify(newMacroSpy, times(2)).getUMID(); 926 | 927 | verify(jsonConfig, times(0)).saveObjectToJson(fileSpy); 928 | } 929 | 930 | @Test 931 | public void testUpdateMacroWithSyncTrue() throws IOException { 932 | BindingsFile file = new BindingsFile(2, new HashSet<>()); 933 | BindingsFile fileSpy = spy(file); 934 | 935 | this.bindingsRepository.setBindingsFile(fileSpy); 936 | 937 | Macro macro = new Macro(10, "test", false); 938 | Macro macro1 = new Macro(50, "testing", true); 939 | Macro newMacro = new Macro(macro.getUMID(), 20, new StringCommand("test2"), true, false); 940 | 941 | Macro macroSpy = spy(macro); 942 | Macro macro1Spy = spy(macro1); 943 | Macro newMacroSpy = spy(newMacro); 944 | 945 | assertEquals(0, this.bindingsRepository.findAllMacros(false).size()); 946 | 947 | this.bindingsRepository.addMacro(macroSpy, false); 948 | this.bindingsRepository.addMacro(macro1Spy, false); 949 | 950 | assertEquals(2, this.bindingsRepository.findAllMacros(false).size()); 951 | 952 | this.bindingsRepository.updateMacro(newMacroSpy, true); 953 | 954 | assertEquals(2, this.bindingsRepository.findAllMacros(false).size()); 955 | 956 | Set newMacroSet = new HashSet<>(); 957 | newMacroSet.add(newMacroSpy); 958 | 959 | assertEquals(newMacroSet, this.bindingsRepository.findMacroByKeycode(20, null, false)); 960 | 961 | verify(fileSpy).setMacros(any()); 962 | 963 | verify(macroSpy).getUMID(); 964 | verify(macro1Spy).getUMID(); 965 | verify(newMacroSpy, times(2)).getUMID(); 966 | 967 | verify(jsonConfig, times(1)).saveObjectToJson(fileSpy); 968 | } 969 | 970 | @Test 971 | public void testDeleteMacroUUIDWithSyncFalse() throws IOException { 972 | Macro macro1 = new Macro(10, "test", false); 973 | Macro macro2 = new Macro(10, "test", false); 974 | Macro macro3 = new Macro(10, "test", false); 975 | 976 | Macro macro1Spy = spy(macro1); 977 | Macro macro2Spy = spy(macro2); 978 | Macro macro3Spy = spy(macro3); 979 | 980 | Set macros = new HashSet<>(); 981 | macros.add(macro1Spy); 982 | macros.add(macro2Spy); 983 | macros.add(macro3Spy); 984 | 985 | Set expectedResult = new HashSet<>(); 986 | expectedResult.add(macro2Spy); 987 | expectedResult.add(macro3Spy); 988 | 989 | BindingsFile file = new BindingsFile(2, macros); 990 | BindingsFile fileSpy = spy(file); 991 | 992 | this.bindingsRepository.setBindingsFile(fileSpy); 993 | 994 | assertEquals(3, this.bindingsRepository.findAllMacros(false).size()); 995 | 996 | this.bindingsRepository.deleteMacro(macro1.getUMID(), false, false); 997 | 998 | assertEquals(2, this.bindingsRepository.findAllMacros(false).size()); 999 | assertEquals(expectedResult, this.bindingsRepository.findAllMacros(false)); 1000 | 1001 | verify(macro1Spy).getUMID(); 1002 | verify(macro2Spy).getUMID(); 1003 | verify(macro3Spy).getUMID(); 1004 | verify(fileSpy).setMacros(expectedResult); 1005 | 1006 | verify(jsonConfig, times(0)).saveObjectToJson(fileSpy); 1007 | } 1008 | 1009 | @Test 1010 | public void testDeleteMacroUUIDWithSyncTrue() throws IOException { 1011 | Macro macro1 = new Macro(10, "test", false); 1012 | Macro macro2 = new Macro(10, "test", false); 1013 | Macro macro3 = new Macro(10, "test", false); 1014 | 1015 | Macro macro1Spy = spy(macro1); 1016 | Macro macro2Spy = spy(macro2); 1017 | Macro macro3Spy = spy(macro3); 1018 | 1019 | Set macros = new HashSet<>(); 1020 | macros.add(macro1Spy); 1021 | macros.add(macro2Spy); 1022 | macros.add(macro3Spy); 1023 | 1024 | Set expectedResult = new HashSet<>(); 1025 | expectedResult.add(macro2Spy); 1026 | expectedResult.add(macro3Spy); 1027 | 1028 | BindingsFile file = new BindingsFile(2, macros); 1029 | BindingsFile fileSpy = spy(file); 1030 | 1031 | this.bindingsRepository.setBindingsFile(fileSpy); 1032 | 1033 | assertEquals(3, this.bindingsRepository.findAllMacros(false).size()); 1034 | 1035 | this.bindingsRepository.deleteMacro(macro1.getUMID(), true, false); 1036 | 1037 | assertEquals(2, this.bindingsRepository.findAllMacros(false).size()); 1038 | assertEquals(expectedResult, this.bindingsRepository.findAllMacros(false)); 1039 | 1040 | verify(macro1Spy).getUMID(); 1041 | verify(macro2Spy).getUMID(); 1042 | verify(macro3Spy).getUMID(); 1043 | verify(fileSpy).setMacros(expectedResult); 1044 | 1045 | verify(jsonConfig, times(1)).saveObjectToJson(fileSpy); 1046 | } 1047 | 1048 | @Test 1049 | public void testDeleteMacroFromLayerWithSyncTrue() throws IOException { 1050 | Macro macro1 = new Macro(10, "test", false); 1051 | Macro macro2 = new Macro(10, "test", false); 1052 | Macro macro3 = new Macro(10, "test", false); 1053 | 1054 | Layer layer1 = new Layer("testing layer"); 1055 | 1056 | Macro macro1Spy = spy(macro1); 1057 | Macro macro2Spy = spy(macro2); 1058 | Macro macro3Spy = spy(macro3); 1059 | 1060 | Layer layer1Spy = spy(layer1); 1061 | 1062 | Set macros = new HashSet<>(); 1063 | macros.add(macro1Spy); 1064 | macros.add(macro2Spy); 1065 | macros.add(macro3Spy); 1066 | 1067 | layer1Spy.addMacro(macro1Spy); 1068 | layer1Spy.addMacro(macro3Spy); 1069 | 1070 | Set expectedResult = new HashSet<>(); 1071 | expectedResult.add(macro1Spy); 1072 | expectedResult.add(macro2Spy); 1073 | expectedResult.add(macro3Spy); 1074 | 1075 | BindingsFile file = new BindingsFile(2, macros); 1076 | BindingsFile fileSpy = spy(file); 1077 | 1078 | when(fileSpy.getLayers()).thenReturn((Set) new HashSet() {{ 1079 | add(layer1Spy); 1080 | }}); 1081 | 1082 | this.bindingsRepository.setBindingsFile(fileSpy); 1083 | 1084 | when(layer1Spy.getMacros()).thenCallRealMethod(); 1085 | 1086 | assertEquals(3, this.bindingsRepository.findAllMacros(false).size()); 1087 | assertEquals(true, this.bindingsRepository.isMacroInLayer(macro1Spy, layer1Spy)); 1088 | assertEquals(false, this.bindingsRepository.isMacroInLayer(macro2Spy, layer1Spy)); 1089 | assertEquals(true, this.bindingsRepository.isMacroInLayer(macro3Spy, layer1Spy)); 1090 | 1091 | this.bindingsRepository.deleteMacroFromLayer(macro1Spy.getUMID(), true); 1092 | 1093 | assertEquals(false, this.bindingsRepository.isMacroInLayer(macro1Spy, layer1Spy)); 1094 | assertEquals(false, this.bindingsRepository.isMacroInLayer(macro2Spy, layer1Spy)); 1095 | assertEquals(true, this.bindingsRepository.isMacroInLayer(macro3Spy, layer1Spy)); 1096 | assertEquals(expectedResult, this.bindingsRepository.findAllMacros(false)); 1097 | 1098 | verify(macro1Spy, times(4)).getUMID(); 1099 | verify(macro2Spy, times(2)).getUMID(); 1100 | verify(macro3Spy, times(3)).getUMID(); 1101 | 1102 | verify(jsonConfig, times(1)).saveObjectToJson(fileSpy); 1103 | } 1104 | 1105 | @Test 1106 | public void testDeleteMacroFromLayerWithSyncFalse() throws IOException { 1107 | Macro macro1 = new Macro(10, "test", false); 1108 | Macro macro2 = new Macro(10, "test", false); 1109 | Macro macro3 = new Macro(10, "test", false); 1110 | 1111 | Layer layer1 = new Layer("testing layer"); 1112 | 1113 | Macro macro1Spy = spy(macro1); 1114 | Macro macro2Spy = spy(macro2); 1115 | Macro macro3Spy = spy(macro3); 1116 | 1117 | Layer layer1Spy = spy(layer1); 1118 | 1119 | Set macros = new HashSet<>(); 1120 | macros.add(macro1Spy); 1121 | macros.add(macro2Spy); 1122 | macros.add(macro3Spy); 1123 | 1124 | layer1Spy.addMacro(macro1Spy); 1125 | layer1Spy.addMacro(macro3Spy); 1126 | 1127 | Set expectedResult = new HashSet<>(); 1128 | expectedResult.add(macro1Spy); 1129 | expectedResult.add(macro2Spy); 1130 | expectedResult.add(macro3Spy); 1131 | 1132 | BindingsFile file = new BindingsFile(2, macros); 1133 | BindingsFile fileSpy = spy(file); 1134 | 1135 | when(fileSpy.getLayers()).thenReturn((Set) new HashSet() {{ 1136 | add(layer1Spy); 1137 | }}); 1138 | 1139 | this.bindingsRepository.setBindingsFile(fileSpy); 1140 | 1141 | when(layer1Spy.getMacros()).thenCallRealMethod(); 1142 | 1143 | assertEquals(3, this.bindingsRepository.findAllMacros(false).size()); 1144 | assertEquals(true, this.bindingsRepository.isMacroInLayer(macro1Spy, layer1Spy)); 1145 | assertEquals(false, this.bindingsRepository.isMacroInLayer(macro2Spy, layer1Spy)); 1146 | assertEquals(true, this.bindingsRepository.isMacroInLayer(macro3Spy, layer1Spy)); 1147 | 1148 | this.bindingsRepository.deleteMacroFromLayer(macro1Spy.getUMID(), false); 1149 | 1150 | assertEquals(false, this.bindingsRepository.isMacroInLayer(macro1Spy, layer1Spy)); 1151 | assertEquals(false, this.bindingsRepository.isMacroInLayer(macro2Spy, layer1Spy)); 1152 | assertEquals(true, this.bindingsRepository.isMacroInLayer(macro3Spy, layer1Spy)); 1153 | assertEquals(expectedResult, this.bindingsRepository.findAllMacros(false)); 1154 | 1155 | verify(macro1Spy, times(4)).getUMID(); 1156 | verify(macro2Spy, times(2)).getUMID(); 1157 | verify(macro3Spy, times(3)).getUMID(); 1158 | 1159 | verify(jsonConfig, times(0)).saveObjectToJson(fileSpy); 1160 | } 1161 | 1162 | @Test 1163 | public void testDeleteMacroFromLayerObjectWithSyncTrue() throws IOException { 1164 | Macro macro1 = new Macro(10, "test", false); 1165 | Macro macro2 = new Macro(10, "test", false); 1166 | Macro macro3 = new Macro(10, "test", false); 1167 | 1168 | Layer layer1 = new Layer("testing layer"); 1169 | 1170 | Macro macro1Spy = spy(macro1); 1171 | Macro macro2Spy = spy(macro2); 1172 | Macro macro3Spy = spy(macro3); 1173 | 1174 | Layer layer1Spy = spy(layer1); 1175 | 1176 | Set macros = new HashSet<>(); 1177 | macros.add(macro1Spy); 1178 | macros.add(macro2Spy); 1179 | macros.add(macro3Spy); 1180 | 1181 | layer1Spy.addMacro(macro1Spy); 1182 | layer1Spy.addMacro(macro3Spy); 1183 | 1184 | Set expectedResult = new HashSet<>(); 1185 | expectedResult.add(macro1Spy); 1186 | expectedResult.add(macro2Spy); 1187 | expectedResult.add(macro3Spy); 1188 | 1189 | BindingsFile file = new BindingsFile(2, macros); 1190 | BindingsFile fileSpy = spy(file); 1191 | 1192 | when(fileSpy.getLayers()).thenReturn((Set) new HashSet() {{ 1193 | add(layer1Spy); 1194 | }}); 1195 | 1196 | this.bindingsRepository.setBindingsFile(fileSpy); 1197 | 1198 | when(layer1Spy.getMacros()).thenCallRealMethod(); 1199 | 1200 | assertEquals(3, this.bindingsRepository.findAllMacros(false).size()); 1201 | assertEquals(true, this.bindingsRepository.isMacroInLayer(macro1Spy, layer1Spy)); 1202 | assertEquals(false, this.bindingsRepository.isMacroInLayer(macro2Spy, layer1Spy)); 1203 | assertEquals(true, this.bindingsRepository.isMacroInLayer(macro3Spy, layer1Spy)); 1204 | 1205 | this.bindingsRepository.deleteMacroFromLayer(macro1Spy, true); 1206 | 1207 | assertEquals(false, this.bindingsRepository.isMacroInLayer(macro1Spy, layer1Spy)); 1208 | assertEquals(false, this.bindingsRepository.isMacroInLayer(macro2Spy, layer1Spy)); 1209 | assertEquals(true, this.bindingsRepository.isMacroInLayer(macro3Spy, layer1Spy)); 1210 | assertEquals(expectedResult, this.bindingsRepository.findAllMacros(false)); 1211 | 1212 | verify(macro1Spy, times(4)).getUMID(); 1213 | verify(macro2Spy, times(2)).getUMID(); 1214 | verify(macro3Spy, times(3)).getUMID(); 1215 | 1216 | verify(jsonConfig, times(1)).saveObjectToJson(fileSpy); 1217 | } 1218 | 1219 | @Test 1220 | public void testDeleteMacroWithSyncFalse() throws IOException { 1221 | Macro macro1 = new Macro(10, "test", false); 1222 | Macro macro2 = new Macro(10, "test", false); 1223 | Macro macro3 = new Macro(10, "test", false); 1224 | 1225 | Macro macro1Spy = spy(macro1); 1226 | Macro macro2Spy = spy(macro2); 1227 | Macro macro3Spy = spy(macro3); 1228 | 1229 | Set macros = new HashSet<>(); 1230 | macros.add(macro1Spy); 1231 | macros.add(macro2Spy); 1232 | macros.add(macro3Spy); 1233 | 1234 | Set expectedResult = new HashSet<>(); 1235 | expectedResult.add(macro2Spy); 1236 | expectedResult.add(macro3Spy); 1237 | 1238 | BindingsFile file = new BindingsFile(2, macros); 1239 | BindingsFile fileSpy = spy(file); 1240 | 1241 | this.bindingsRepository.setBindingsFile(fileSpy); 1242 | 1243 | assertEquals(3, this.bindingsRepository.findAllMacros(false).size()); 1244 | 1245 | this.bindingsRepository.deleteMacro(macro1, false, false); 1246 | 1247 | assertEquals(2, this.bindingsRepository.findAllMacros(false).size()); 1248 | assertEquals(expectedResult, this.bindingsRepository.findAllMacros(false)); 1249 | 1250 | verify(macro1Spy).getUMID(); 1251 | verify(macro2Spy).getUMID(); 1252 | verify(macro3Spy).getUMID(); 1253 | verify(fileSpy).setMacros(expectedResult); 1254 | 1255 | verify(jsonConfig, times(0)).saveObjectToJson(fileSpy); 1256 | } 1257 | 1258 | @Test 1259 | public void testDeleteMacroWithSyncTruePersistTrue() throws IOException { 1260 | Macro macro1 = new Macro(10, "test", false); 1261 | Macro macro2 = new Macro(10, "test", false); 1262 | Macro macro3 = new Macro(10, "test", false); 1263 | 1264 | Layer layer1 = new Layer("testing layer"); 1265 | 1266 | Macro macro1Spy = spy(macro1); 1267 | Macro macro2Spy = spy(macro2); 1268 | Macro macro3Spy = spy(macro3); 1269 | 1270 | Layer layer1Spy = spy(layer1); 1271 | 1272 | Set macros = new HashSet<>(); 1273 | macros.add(macro1Spy); 1274 | macros.add(macro2Spy); 1275 | macros.add(macro3Spy); 1276 | 1277 | layer1Spy.addMacro(macro1Spy); 1278 | layer1Spy.addMacro(macro3Spy); 1279 | 1280 | Set expectedResult = new HashSet<>(); 1281 | expectedResult.add(macro2Spy); 1282 | expectedResult.add(macro3Spy); 1283 | 1284 | BindingsFile file = new BindingsFile(2, macros); 1285 | BindingsFile fileSpy = spy(file); 1286 | 1287 | when(fileSpy.getLayers()).thenReturn((Set) new HashSet() {{ 1288 | add(layer1Spy); 1289 | }}); 1290 | 1291 | this.bindingsRepository.setBindingsFile(fileSpy); 1292 | 1293 | when(layer1Spy.getMacros()).thenCallRealMethod(); 1294 | 1295 | assertEquals(3, this.bindingsRepository.findAllMacros(false).size()); 1296 | assertEquals(true, this.bindingsRepository.isMacroInLayer(macro1Spy, layer1Spy)); 1297 | assertEquals(false, this.bindingsRepository.isMacroInLayer(macro2Spy, layer1Spy)); 1298 | assertEquals(true, this.bindingsRepository.isMacroInLayer(macro3Spy, layer1Spy)); 1299 | 1300 | this.bindingsRepository.deleteMacro(macro1Spy.getUMID(), true, true); 1301 | 1302 | assertEquals(false, this.bindingsRepository.isMacroInLayer(macro1Spy, layer1Spy)); 1303 | assertEquals(false, this.bindingsRepository.isMacroInLayer(macro2Spy, layer1Spy)); 1304 | assertEquals(true, this.bindingsRepository.isMacroInLayer(macro3Spy, layer1Spy)); 1305 | assertEquals(expectedResult, this.bindingsRepository.findAllMacros(false)); 1306 | 1307 | verify(macro1Spy, times(5)).getUMID(); 1308 | verify(macro2Spy, times(3)).getUMID(); 1309 | verify(macro3Spy, times(4)).getUMID(); 1310 | 1311 | verify(jsonConfig, times(1)).saveObjectToJson(fileSpy); 1312 | } 1313 | 1314 | @Test 1315 | public void testDeleteMacroWithSyncTrue() throws IOException { 1316 | Macro macro1 = new Macro(10, "test", false); 1317 | Macro macro2 = new Macro(10, "test", false); 1318 | Macro macro3 = new Macro(10, "test", false); 1319 | 1320 | Macro macro1Spy = spy(macro1); 1321 | Macro macro2Spy = spy(macro2); 1322 | Macro macro3Spy = spy(macro3); 1323 | 1324 | Set macros = new HashSet<>(); 1325 | macros.add(macro1Spy); 1326 | macros.add(macro2Spy); 1327 | macros.add(macro3Spy); 1328 | 1329 | Set expectedResult = new HashSet<>(); 1330 | expectedResult.add(macro2Spy); 1331 | expectedResult.add(macro3Spy); 1332 | 1333 | BindingsFile file = new BindingsFile(2, macros); 1334 | BindingsFile fileSpy = spy(file); 1335 | 1336 | this.bindingsRepository.setBindingsFile(fileSpy); 1337 | 1338 | assertEquals(3, this.bindingsRepository.findAllMacros(false).size()); 1339 | 1340 | this.bindingsRepository.deleteMacro(macro1, true, false); 1341 | 1342 | assertEquals(2, this.bindingsRepository.findAllMacros(false).size()); 1343 | assertEquals(expectedResult, this.bindingsRepository.findAllMacros(false)); 1344 | 1345 | verify(macro1Spy).getUMID(); 1346 | verify(macro2Spy).getUMID(); 1347 | verify(macro3Spy).getUMID(); 1348 | verify(fileSpy).setMacros(expectedResult); 1349 | 1350 | verify(jsonConfig, times(1)).saveObjectToJson(fileSpy); 1351 | } 1352 | 1353 | @Test 1354 | public void testSetActiveLayerSyncFalse() throws IOException { 1355 | Layer layer1 = new Layer("layer1"); 1356 | Layer layer2 = new Layer("layer2"); 1357 | Layer layer3 = new Layer("layer3"); 1358 | 1359 | Layer layer1Spy = spy(layer1); 1360 | Layer layer2Spy = spy(layer2); 1361 | Layer layer3Spy = spy(layer3); 1362 | 1363 | Set layers = new HashSet<>(); 1364 | layers.add(layer1Spy); 1365 | layers.add(layer2Spy); 1366 | layers.add(layer3Spy); 1367 | 1368 | BindingsFile file = new BindingsFile(2, null, layers); 1369 | BindingsFile fileSpy = spy(file); 1370 | 1371 | this.bindingsRepository.setBindingsFile(fileSpy); 1372 | 1373 | assertFalse(this.bindingsRepository.isActiveLayer(layer1Spy.getULID(), false)); 1374 | 1375 | this.bindingsRepository.setActiveLayer(layer1Spy.getULID(), false); 1376 | 1377 | assertTrue(this.bindingsRepository.isActiveLayer(layer1Spy, false)); 1378 | } 1379 | 1380 | @Test 1381 | public void testSetActiveLayerObjectSyncFalse() throws IOException { 1382 | Layer layer1 = new Layer("layer1"); 1383 | Layer layer2 = new Layer("layer2"); 1384 | Layer layer3 = new Layer("layer3"); 1385 | 1386 | Layer layer1Spy = spy(layer1); 1387 | Layer layer2Spy = spy(layer2); 1388 | Layer layer3Spy = spy(layer3); 1389 | 1390 | Set layers = new HashSet<>(); 1391 | layers.add(layer1Spy); 1392 | layers.add(layer2Spy); 1393 | layers.add(layer3Spy); 1394 | 1395 | BindingsFile file = new BindingsFile(2, null, layers); 1396 | BindingsFile fileSpy = spy(file); 1397 | 1398 | this.bindingsRepository.setBindingsFile(fileSpy); 1399 | 1400 | assertFalse(this.bindingsRepository.isActiveLayer(layer1Spy.getULID(), false)); 1401 | 1402 | this.bindingsRepository.setActiveLayer(layer1Spy, false); 1403 | 1404 | assertTrue(this.bindingsRepository.isActiveLayer(layer1Spy, false)); 1405 | } 1406 | 1407 | @Test 1408 | public void testSetActiveLayerSyncTrue() throws IOException { 1409 | BindingsFile file = mock(BindingsFile.class); 1410 | 1411 | Layer layer1 = new Layer(); 1412 | 1413 | this.bindingsRepository.setBindingsFile(file); 1414 | 1415 | this.bindingsRepository.setActiveLayer(layer1.getULID(), true); 1416 | 1417 | verify(jsonConfig).saveObjectToJson(file); 1418 | } 1419 | 1420 | @Test 1421 | public void testFindActiveLayerLayerNull() throws IOException { 1422 | Layer layer1 = new Layer("layer1"); 1423 | Layer layer2 = new Layer("layer2"); 1424 | Layer layer3 = new Layer("layer3"); 1425 | 1426 | Layer layer1Spy = spy(layer1); 1427 | Layer layer2Spy = spy(layer2); 1428 | Layer layer3Spy = spy(layer3); 1429 | 1430 | Set layers = new HashSet<>(); 1431 | layers.add(layer1Spy); 1432 | layers.add(layer2Spy); 1433 | layers.add(layer3Spy); 1434 | 1435 | BindingsFile file = new BindingsFile(2, null, layers); 1436 | 1437 | this.bindingsRepository.setBindingsFile(file); 1438 | 1439 | assertNull(this.bindingsRepository.findActiveLayer(false)); 1440 | 1441 | verify(layer1Spy).getULID(); 1442 | verify(layer2Spy).getULID(); 1443 | verify(layer3Spy).getULID(); 1444 | 1445 | verifyNoMoreInteractions(layer1Spy, layer2Spy, layer3Spy); 1446 | } 1447 | 1448 | @Test 1449 | public void testIsActiveLayerLayerNull() throws IOException { 1450 | Layer layer1 = new Layer("layer1"); 1451 | Layer layer2 = new Layer("layer2"); 1452 | Layer layer3 = new Layer("layer3"); 1453 | 1454 | Layer layer1Spy = spy(layer1); 1455 | Layer layer2Spy = spy(layer2); 1456 | Layer layer3Spy = spy(layer3); 1457 | 1458 | Set layers = new HashSet<>(); 1459 | layers.add(layer1Spy); 1460 | layers.add(layer2Spy); 1461 | layers.add(layer3Spy); 1462 | 1463 | BindingsFile file = new BindingsFile(2, null, layers); 1464 | 1465 | this.bindingsRepository.setBindingsFile(file); 1466 | 1467 | assertFalse(this.bindingsRepository.isActiveLayer(layer1Spy, false)); 1468 | assertFalse(this.bindingsRepository.isActiveLayer(layer2Spy, false)); 1469 | assertFalse(this.bindingsRepository.isActiveLayer(layer3Spy, false)); 1470 | 1471 | verify(layer1Spy).getULID(); 1472 | verify(layer2Spy).getULID(); 1473 | verify(layer3Spy).getULID(); 1474 | 1475 | verifyNoMoreInteractions(layer1Spy, layer2Spy, layer3Spy); 1476 | } 1477 | 1478 | @Test 1479 | public void testIsActiveLayerPassNull() throws IOException { 1480 | assertFalse(this.bindingsRepository.isActiveLayer((UUID) null, false)); 1481 | } 1482 | 1483 | @Test 1484 | public void testIsActiveLayerNotNull() throws IOException { 1485 | Layer layer1 = new Layer("layer1"); 1486 | Layer layer2 = new Layer("layer2"); 1487 | Layer layer3 = new Layer("layer3"); 1488 | 1489 | Layer layer1Spy = spy(layer1); 1490 | Layer layer2Spy = spy(layer2); 1491 | Layer layer3Spy = spy(layer3); 1492 | 1493 | Set layers = new HashSet<>(); 1494 | layers.add(layer1Spy); 1495 | layers.add(layer2Spy); 1496 | layers.add(layer3Spy); 1497 | 1498 | BindingsFile file = new BindingsFile(2, null, layers); 1499 | 1500 | this.bindingsRepository.setBindingsFile(file); 1501 | 1502 | assertFalse(this.bindingsRepository.isActiveLayer(layer1Spy, false)); 1503 | assertFalse(this.bindingsRepository.isActiveLayer(layer2Spy, false)); 1504 | assertFalse(this.bindingsRepository.isActiveLayer(layer3Spy, false)); 1505 | 1506 | this.bindingsRepository.setActiveLayer(layer1Spy, false); 1507 | 1508 | assertTrue(this.bindingsRepository.isActiveLayer(layer1Spy, false)); 1509 | assertFalse(this.bindingsRepository.isActiveLayer(layer2Spy, false)); 1510 | assertFalse(this.bindingsRepository.isActiveLayer(layer3Spy, false)); 1511 | 1512 | this.bindingsRepository.setActiveLayer(layer2Spy, false); 1513 | 1514 | assertFalse(this.bindingsRepository.isActiveLayer(layer1Spy, false)); 1515 | assertTrue(this.bindingsRepository.isActiveLayer(layer2Spy, false)); 1516 | assertFalse(this.bindingsRepository.isActiveLayer(layer3Spy, false)); 1517 | 1518 | this.bindingsRepository.setActiveLayer(layer3Spy, false); 1519 | 1520 | assertFalse(this.bindingsRepository.isActiveLayer(layer1Spy, false)); 1521 | assertFalse(this.bindingsRepository.isActiveLayer(layer2Spy, false)); 1522 | assertTrue(this.bindingsRepository.isActiveLayer(layer3Spy, false)); 1523 | 1524 | verify(layer1Spy, times(5)).getULID(); 1525 | verify(layer2Spy, times(5)).getULID(); 1526 | verify(layer3Spy, times(5)).getULID(); 1527 | 1528 | verifyNoMoreInteractions(layer1Spy, layer2Spy, layer3Spy); 1529 | } 1530 | 1531 | @Test(expected = IOException.class) 1532 | public void testIsActiveLayerWithSyncTrue() throws IOException { 1533 | BindingsFile file = mock(BindingsFile.class); 1534 | Layer layer = new Layer("test"); 1535 | 1536 | this.bindingsRepository.setBindingsFile(file); 1537 | 1538 | when(jsonConfig.getJSONObject()).thenThrow(new IOException()); 1539 | 1540 | boolean result = this.bindingsRepository.isActiveLayer(layer.getULID(), true); 1541 | 1542 | assertFalse(result); 1543 | } 1544 | 1545 | @Test 1546 | public void testFindActiveLayerLayerNotNull() throws IOException { 1547 | Layer layer1 = new Layer("layer1"); 1548 | Layer layer2 = new Layer("layer2"); 1549 | Layer layer3 = new Layer("layer3"); 1550 | 1551 | Layer layer1Spy = spy(layer1); 1552 | Layer layer2Spy = spy(layer2); 1553 | Layer layer3Spy = spy(layer3); 1554 | 1555 | Set layers = new HashSet<>(); 1556 | layers.add(layer1Spy); 1557 | layers.add(layer2Spy); 1558 | layers.add(layer3Spy); 1559 | 1560 | BindingsFile file = new BindingsFile(2, null, layers); 1561 | 1562 | this.bindingsRepository.setBindingsFile(file); 1563 | 1564 | this.bindingsRepository.setActiveLayer(layer1Spy.getULID(), false); 1565 | 1566 | assertEquals(layer1Spy, this.bindingsRepository.findActiveLayer(false)); 1567 | 1568 | verify(layer1Spy, times(2)).getULID(); 1569 | verify(layer2Spy).getULID(); 1570 | verify(layer3Spy).getULID(); 1571 | 1572 | verifyNoMoreInteractions(layer1Spy, layer2Spy, layer3Spy); 1573 | } 1574 | 1575 | @Test 1576 | public void testLoadConfigurationWithNullJsonObject() throws IOException { 1577 | when(jsonConfig.getJSONObject()).thenReturn(null); 1578 | 1579 | BindingsRepository bindingSpy = spy(bindingsRepository); 1580 | 1581 | bindingSpy.loadConfiguration(); 1582 | 1583 | verify(bindingSpy).setBindingsFile(any()); 1584 | verify(bindingSpy).saveConfiguration(); 1585 | } 1586 | 1587 | @Test 1588 | public void testLoadConfigurationWithJsonObjectButBindingNull() throws IOException { 1589 | this.bindingsRepository.setBindingsFile(null); 1590 | 1591 | JsonObject object = new JsonObject(); 1592 | object.addProperty("version", 20); 1593 | 1594 | assertEquals(20, object.get("version").getAsInt()); 1595 | 1596 | Macro[] macros = new Macro[]{mock(Macro.class)}; 1597 | Layer[] layers = new Layer[]{mock(Layer.class)}; 1598 | UUID activeLayer = UUID.randomUUID(); 1599 | 1600 | when(jsonConfig.getJSONObject()).thenReturn(object); 1601 | when(jsonConfig.bindJsonElementToObject(eq(Macro[].class), any())).thenReturn(macros); 1602 | when(jsonConfig.bindJsonElementToObject(eq(Layer[].class), any())).thenReturn(layers); 1603 | when(jsonConfig.bindJsonElementToObject(eq(UUID.class), any())).thenReturn(activeLayer); 1604 | 1605 | BindingsRepository bindingSpy = spy(bindingsRepository); 1606 | 1607 | bindingSpy.loadConfiguration(); 1608 | 1609 | verify(bindingSpy).setBindingsFile(any()); 1610 | } 1611 | 1612 | @Test 1613 | public void testLoadConfigurationWithJsonObject() throws IOException { 1614 | this.bindingsRepository.setBindingsFile(mock(BindingsFile.class)); 1615 | 1616 | JsonObject object = new JsonObject(); 1617 | object.addProperty("version", 20); 1618 | 1619 | assertEquals(20, object.get("version").getAsInt()); 1620 | 1621 | Macro[] macros = new Macro[]{mock(Macro.class)}; 1622 | Layer[] layers = new Layer[]{mock(Layer.class)}; 1623 | UUID activeLayer = UUID.randomUUID(); 1624 | 1625 | when(jsonConfig.getJSONObject()).thenReturn(object); 1626 | when(jsonConfig.bindJsonElementToObject(eq(Macro[].class), any())).thenReturn(macros); 1627 | when(jsonConfig.bindJsonElementToObject(eq(Layer[].class), any())).thenReturn(layers); 1628 | when(jsonConfig.bindJsonElementToObject(eq(UUID.class), any())).thenReturn(activeLayer); 1629 | 1630 | BindingsRepository bindingSpy = spy(bindingsRepository); 1631 | 1632 | bindingSpy.loadConfiguration(); 1633 | 1634 | verify(bindingSpy, times(0)).setBindingsFile(any()); 1635 | } 1636 | 1637 | } 1638 | -------------------------------------------------------------------------------- /src/test/java/com/mattsmeets/macrokey/service/JSONServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.service; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.mockito.Mock; 6 | import org.mockito.junit.MockitoJUnitRunner; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | 11 | import static org.junit.Assert.assertNull; 12 | 13 | @RunWith(MockitoJUnitRunner.class) 14 | public class JSONServiceTest { 15 | 16 | @Mock 17 | private JSONService jsonService; 18 | 19 | @Test 20 | public void loadJSONElementFromFileReturnsNullWhenFileDoesNotExist() throws IOException { 21 | File file = new File("bindings.json"); 22 | 23 | assertNull(jsonService.loadJSONElementFromFile(file)); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/mattsmeets/macrokey/service/LogHelperTest.java: -------------------------------------------------------------------------------- 1 | package com.mattsmeets.macrokey.service; 2 | 3 | import org.apache.logging.log4j.Level; 4 | import org.apache.logging.log4j.Logger; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.mockito.InjectMocks; 8 | import org.mockito.Mock; 9 | import org.mockito.junit.MockitoJUnitRunner; 10 | 11 | import static org.mockito.Mockito.verify; 12 | import static org.mockito.Mockito.verifyNoMoreInteractions; 13 | 14 | @RunWith(MockitoJUnitRunner.class) 15 | public class LogHelperTest { 16 | 17 | @Mock 18 | private Logger logger; 19 | 20 | @InjectMocks 21 | private LogHelper logHelper; 22 | 23 | @Test 24 | public void testIfDebugCallsLoggerDebug() { 25 | Object message = "message"; 26 | 27 | logHelper.debug(message); 28 | 29 | verify(logger).log(Level.DEBUG, message); 30 | 31 | verifyNoMoreInteractions(logger); 32 | } 33 | 34 | @Test 35 | public void testIfInfoCallsLoggerInfo() { 36 | Object message = "message"; 37 | 38 | logHelper.info(message); 39 | 40 | verify(logger).log(Level.INFO, message); 41 | 42 | verifyNoMoreInteractions(logger); 43 | } 44 | 45 | @Test 46 | public void testIfWarnCallsLoggerWarn() { 47 | Object message = "message"; 48 | 49 | logHelper.warn(message); 50 | 51 | verify(logger).log(Level.WARN, message); 52 | 53 | verifyNoMoreInteractions(logger); 54 | } 55 | 56 | @Test 57 | public void testIfLogCallsGivenLevel() { 58 | Object message = "message"; 59 | 60 | logHelper.log(Level.ALL, message); 61 | 62 | verify(logger).log(Level.ALL, message); 63 | 64 | verifyNoMoreInteractions(logger); 65 | } 66 | 67 | } 68 | --------------------------------------------------------------------------------