From f921d658ae6f204c90636141cd4620b43c5f495c Mon Sep 17 00:00:00 2001 From: Caviar-X Date: Sat, 24 Feb 2024 22:03:48 +0800 Subject: [PATCH] add proper keymap support --- docs/lindbergh.conf | 15 ++++ src/lindbergh/config.c | 67 +++++++++++++++ src/lindbergh/config.h | 26 ++++++ src/lindbergh/input.c | 182 +++++++++++++++-------------------------- 4 files changed, 173 insertions(+), 117 deletions(-) diff --git a/docs/lindbergh.conf b/docs/lindbergh.conf index 8f577cc..58d0e9f 100644 --- a/docs/lindbergh.conf +++ b/docs/lindbergh.conf @@ -67,3 +67,18 @@ FREEPLAY 1 # Set if you want to see degug messages in the console DEBUG_MSGS 0 + +# Keymap settings +# Configure the keymap using `xev` +TEST_KEY 28 +PLAYER_1_START_KEY 10 +PLAYER_1_SERVICE_KEY 39 +PLAYER_1_COIN_KEY 14 +PLAYER_1_UP_KEY 111 +PLAYER_1_DOWN_KEY 116 +PLAYER_1_LEFT_KEY 113 +PLAYER_1_RIGHT_KEY 114 +PLAYER_1_BUTTON_1_KEY 24 +PLAYER_1_BUTTON_2_KEY 25 +PLAYER_1_BUTTON_3_KEY 26 +PLAYER_1_BUTTON_4_KEY 27 \ No newline at end of file diff --git a/src/lindbergh/config.c b/src/lindbergh/config.c index 634e37e..2c1d142 100644 --- a/src/lindbergh/config.c +++ b/src/lindbergh/config.c @@ -397,6 +397,42 @@ int readConfig(FILE *configFile, EmulatorConfig *config) else if (strcmp(command, "DEBUG_MSGS") == 0) config->showDebugMessages = atoi(getNextToken(NULL, " ", &saveptr)); + else if (strcmp(command,"TEST_KEY") == 0) + config->keymap.test = atoi(getNextToken(NULL, " ", &saveptr)); + //TODO: add config when supporting player2 + else if (strcmp(command,"PLAYER_1_START_KEY") == 0) + config->keymap.player1.start = atoi(getNextToken(NULL, " ", &saveptr)); + + else if (strcmp(command,"PLAYER_1_SERVICE_KEY") == 0) + config->keymap.player1.service = atoi(getNextToken(NULL, " ", &saveptr)); + + else if (strcmp(command,"PLAYER_1_COIN_KEY") == 0) + config->keymap.player1.coin = atoi(getNextToken(NULL, " ", &saveptr)); + + else if (strcmp(command,"PLAYER_1_UP_KEY") == 0) + config->keymap.player1.up = atoi(getNextToken(NULL, " ", &saveptr)); + + else if (strcmp(command,"PLAYER_1_DOWN_KEY") == 0) + config->keymap.player1.down = atoi(getNextToken(NULL, " ", &saveptr)); + + else if (strcmp(command,"PLAYER_1_LEFT_KEY") == 0) + config->keymap.player1.left = atoi(getNextToken(NULL, " ", &saveptr)); + + else if (strcmp(command,"PLAYER_1_RIGHT_KEY") == 0) + config->keymap.player1.right = atoi(getNextToken(NULL, " ", &saveptr)); + + else if (strcmp(command,"PLAYER_1_BUTTON_1_KEY") == 0) + config->keymap.player1.button1 = atoi(getNextToken(NULL, " ", &saveptr)); + + else if (strcmp(command,"PLAYER_1_BUTTON_2_KEY") == 0) + config->keymap.player1.button2 = atoi(getNextToken(NULL, " ", &saveptr)); + + else if (strcmp(command,"PLAYER_1_BUTTON_3_KEY") == 0) + config->keymap.player1.button3 = atoi(getNextToken(NULL, " ", &saveptr)); + + else if (strcmp(command,"PLAYER_1_BUTTON_4_KEY") == 0) + config->keymap.player1.button4 = atoi(getNextToken(NULL, " ", &saveptr)); + else printf("Error: Unknown settings command %s\n", command); } @@ -404,6 +440,36 @@ int readConfig(FILE *configFile, EmulatorConfig *config) return 0; } +KeyMapping getDefualtKeymap() +{ + KeyMapping a; + a.test = 28; + a.player1.start = 10; + a.player1.service = 39; + a.player1.coin = 14; + a.player1.up = 111; + a.player1.down = 116; + a.player1.left = 113; + a.player1.right = 114; + a.player1.button1 = 24; + a.player1.button2 = 25; + a.player1.button3 = 26; + a.player1.button4 = 27; + //TODO: Add keys when supporting player2 + a.player2.start = -1; + a.player2.service = -1; + a.player2.coin = -1; + a.player2.up = -1; + a.player2.down = -1; + a.player2.left = -1; + a.player2.right = -1; + a.player2.button1 = -1; + a.player2.button2 = -1; + a.player2.button3 = -1; + a.player2.button4 = -1; + return a; +} + int initConfig() { config.emulateRideboard = 0; @@ -427,6 +493,7 @@ int initConfig() config.gameID = "XXXX"; config.gameDVP = "DVP-XXXX"; config.gameType = SHOOTING; + config.keymap = getDefualtKeymap(); if (detectGame(config.crc32) != 0) { printf("Warning: Unsure what game with CRC 0x%X is. Please submit this new game to the GitHub repository: https://github.com/bobbydilley/lindbergh-loader/issues/new?title=Please+add+new+game+0x%X&body=I+tried+to+launch+the+following+game:\n", config.crc32, config.crc32); diff --git a/src/lindbergh/config.h b/src/lindbergh/config.h index ea32659..c8f16e9 100644 --- a/src/lindbergh/config.h +++ b/src/lindbergh/config.h @@ -83,6 +83,30 @@ typedef enum FIGHTING } GameType; +typedef struct +{ + unsigned int service; + unsigned int start; + unsigned int coin; + unsigned int up; + unsigned int down; + unsigned int left; + unsigned int right; + unsigned int button1; + unsigned int button2; + unsigned int button3; + unsigned int button4; +} PlayerKeyMapping; + +// All keycode can be found using `xev` binary's debug output +// NOTE: Maybe using tagged union for driving and shooting games +typedef struct +{ + unsigned int test; + PlayerKeyMapping player1; + PlayerKeyMapping player2; +} KeyMapping; + typedef struct { int emulateRideboard; @@ -100,6 +124,7 @@ typedef struct Colour lindberghColour; GameStatus gameStatus; GameType gameType; + KeyMapping keymap; uint32_t crc32; GameRegion region; int freeplay; @@ -109,6 +134,7 @@ typedef struct char* gameDVP; } EmulatorConfig; +KeyMapping getDefualtKeymap(); int initConfig(); EmulatorConfig *getConfig(); char *getGameName(); diff --git a/src/lindbergh/input.c b/src/lindbergh/input.c index 39dbba0..e468abd 100644 --- a/src/lindbergh/input.c +++ b/src/lindbergh/input.c @@ -28,161 +28,109 @@ int initInput() */ int XNextEventDriving(Display *display, XEvent *event_return, int returnValue) { - switch (event_return->type) + KeyMapping keymap = getConfig()->keymap; + if (event_return->type == KeyPress || event_return->type == KeyRelease) { - - case KeyRelease: - case KeyPress: - { - switch (event_return->xkey.keycode) - { - case 28: + if (event_return->xkey.keycode == keymap.test) setSwitch(SYSTEM, BUTTON_TEST, event_return->type == KeyPress); - break; - case 39: + else if (event_return->xkey.keycode == keymap.player1.service) setSwitch(PLAYER_1, BUTTON_SERVICE, event_return->type == KeyPress); - break; - case 14: + else if (event_return->xkey.keycode == keymap.player1.coin) incrementCoin(PLAYER_1, event_return->type == KeyPress); - break; - case 15: + else if (event_return->xkey.keycode == keymap.player2.coin) incrementCoin(PLAYER_2, event_return->type == KeyPress); - break; - case 111: // Up - setAnalogue(ANALOGUE_2, event_return->type == KeyPress ? pow(2, 10) - 1 : 0); - break; - case 116: // Down - setAnalogue(ANALOGUE_3, event_return->type == KeyPress ? pow(2, 10) - 1 : 0); - break; - case 113: // Left - setAnalogue(ANALOGUE_1, event_return->type == KeyPress ? pow(2, 10) * 0.2 : pow(2, 10) * 0.5); - break; - case 114: // Right - setAnalogue(ANALOGUE_1, event_return->type == KeyPress ? pow(2, 10) * 0.8 : pow(2, 10) * 0.5); - break; - case 10: + else if (event_return->xkey.keycode == keymap.player1.up) + setAnalogue(ANALOGUE_2, + event_return->type == KeyPress ? pow(2, 10) - 1 : 0); + else if (event_return->xkey.keycode == keymap.player1.down) + setAnalogue(ANALOGUE_3, + event_return->type == KeyPress ? pow(2, 10) - 1 : 0); + else if (event_return->xkey.keycode == keymap.player1.left) + setAnalogue(ANALOGUE_1, event_return->type == KeyPress + ? pow(2, 10) * 0.2 + : pow(2, 10) * 0.5); + else if (event_return->xkey.keycode == keymap.player1.right) + setAnalogue(ANALOGUE_1, event_return->type == KeyPress + ? pow(2, 10) * 0.8 + : pow(2, 10) * 0.5); + else if (event_return->xkey.keycode == keymap.player1.start) setSwitch(PLAYER_1, BUTTON_START, event_return->type == KeyPress); - break; - case 24: + else if (event_return->xkey.keycode == keymap.player1.button1) setSwitch(PLAYER_1, BUTTON_1, event_return->type == KeyPress); - break; - case 25: + else if (event_return->xkey.keycode == keymap.player1.button2) setSwitch(PLAYER_1, BUTTON_2, event_return->type == KeyPress); - break; - case 26: + else if (event_return->xkey.keycode == keymap.player1.button3) setSwitch(PLAYER_1, BUTTON_3, event_return->type == KeyPress); - break; - case 27: + else if (event_return->xkey.keycode == keymap.player1.button4) setSwitch(PLAYER_1, BUTTON_4, event_return->type == KeyPress); - break; - case 29: + else if (event_return->xkey.keycode == keymap.player1.up) setSwitch(PLAYER_1, BUTTON_UP, event_return->type == KeyPress); - break; - case 30: + else if (event_return->xkey.keycode == keymap.player1.down) setSwitch(PLAYER_1, BUTTON_DOWN, event_return->type == KeyPress); - break; - case 31: + else if (event_return->xkey.keycode == keymap.player1.left) setSwitch(PLAYER_1, BUTTON_LEFT, event_return->type == KeyPress); - break; - case 32: + else if (event_return->xkey.keycode == keymap.player1.right) setSwitch(PLAYER_1, BUTTON_RIGHT, event_return->type == KeyPress); - break; - default: - break; - } } - break; - } - return returnValue; } /** * Button mapping used for shooting games */ -int XNextEventShooting(Display *display, XEvent *event_return, int returnValue) +int XNextEventShooting(Display *display, XEvent *event_return, int returnValue) { - switch (event_return->type) + KeyMapping keymap = getConfig()->keymap; + if (event_return->type == KeyPress || event_return->type == KeyRelease) { - - case KeyRelease: - case KeyPress: - { - switch (event_return->xkey.keycode) - { - case 28: + if (event_return->xkey.keycode == keymap.test) setSwitch(SYSTEM, BUTTON_TEST, event_return->type == KeyPress); - break; - case 39: + else if (event_return->xkey.keycode == keymap.player1.service) setSwitch(PLAYER_1, BUTTON_SERVICE, event_return->type == KeyPress); - break; - case 14: + else if (event_return->xkey.keycode == keymap.player1.coin) incrementCoin(PLAYER_1, event_return->type == KeyPress); - break; - case 15: + else if (event_return->xkey.keycode == keymap.player2.coin) incrementCoin(PLAYER_2, event_return->type == KeyPress); - break; - case 111: - setSwitch(PLAYER_1, BUTTON_UP, event_return->type == KeyPress); - break; - case 116: - setSwitch(PLAYER_1, BUTTON_DOWN, event_return->type == KeyPress); - break; - case 113: - setSwitch(PLAYER_1, BUTTON_LEFT, event_return->type == KeyPress); - break; - case 114: - setSwitch(PLAYER_1, BUTTON_RIGHT, event_return->type == KeyPress); - break; - case 10: + else if (event_return->xkey.keycode == keymap.player1.start) setSwitch(PLAYER_1, BUTTON_START, event_return->type == KeyPress); - break; - case 24: + else if (event_return->xkey.keycode == keymap.player1.button1) setSwitch(PLAYER_1, BUTTON_1, event_return->type == KeyPress); - break; - case 25: + else if (event_return->xkey.keycode == keymap.player1.button2) setSwitch(PLAYER_1, BUTTON_2, event_return->type == KeyPress); - break; - case 26: + else if (event_return->xkey.keycode == keymap.player1.button3) setSwitch(PLAYER_1, BUTTON_3, event_return->type == KeyPress); - break; - case 27: + else if (event_return->xkey.keycode == keymap.player1.button4) setSwitch(PLAYER_1, BUTTON_4, event_return->type == KeyPress); - break; - default: - break; - } - } - break; - - case MotionNotify: + else if (event_return->xkey.keycode == keymap.player1.up) + setSwitch(PLAYER_1, BUTTON_UP, event_return->type == KeyPress); + else if (event_return->xkey.keycode == keymap.player1.down) + setSwitch(PLAYER_1, BUTTON_DOWN, event_return->type == KeyPress); + else if (event_return->xkey.keycode == keymap.player1.left) + setSwitch(PLAYER_1, BUTTON_LEFT, event_return->type == KeyPress); + else if (event_return->xkey.keycode == keymap.player1.right) + setSwitch(PLAYER_1, BUTTON_RIGHT, event_return->type == KeyPress); + } + else if (event_return->type == MotionNotify) { - setAnalogue(ANALOGUE_1, ((double)event_return->xmotion.x / (double)getConfig()->width) * pow(2, 10)); - setAnalogue(ANALOGUE_2, ((double)event_return->xmotion.y / (double)getConfig()->height) * pow(2, 10)); - } - break; - - case ButtonPress: - case ButtonRelease: + setAnalogue(ANALOGUE_1, + ((double)event_return->xmotion.x / (double)getConfig()->width) * + pow(2, 10)); + setAnalogue(ANALOGUE_2, ((double)event_return->xmotion.y / + (double)getConfig()->height) * + pow(2, 10)); + } + else if (event_return->type == ButtonPress || event_return->type == ButtonRelease) { - switch (event_return->xbutton.button) - { - case 1: // Trigger + // Trigger + if (event_return->xbutton.button == 1) setSwitch(PLAYER_1, BUTTON_1, event_return->type == ButtonPress); - break; - case 3: // Reload + // Reload + else if (event_return->xbutton.button == 3) setSwitch(PLAYER_1, BUTTON_2, event_return->type == ButtonPress); - break; - case 9: // Gun Button + // Gun button + else if (event_return->xbutton.button == 2) setSwitch(PLAYER_1, BUTTON_3, event_return->type == ButtonPress); - break; - default: - break; - } } - break; - } - return returnValue; }