ref: 5fcbbc9bee7c8705db1812c3b15ce11298f1b5d6
parent: 328b1c845f21f5b47ba8156399245f2c3b1a4159
author: laamaa <jonne.kokkonen@gmail.com>
date: Tue Apr 15 10:56:58 EDT 2025
start work on event callback
--- /dev/null
+++ b/src/common.h
@@ -1,0 +1,15 @@
+#ifndef COMMON_H_
+#define COMMON_H_
+#include "config.h"
+
+enum app_state { QUIT, WAIT_FOR_DEVICE, RUN };+
+struct app_context {+ config_params_s conf;
+ enum app_state app_state;
+ char *preferred_device;
+ unsigned char device_connected;
+ unsigned char app_suspended;
+ };
+
+#endif
\ No newline at end of file
--- /dev/null
+++ b/src/events.c
@@ -1,0 +1,357 @@
+#include "events.h"
+#include "backends/audio.h"
+#include "backends/m8.h"
+#include "common.h"
+#include "config.h"
+#include "gamecontrollers.h"
+#include "render.h"
+#include <SDL3/SDL.h>
+#include <SDL3/SDL_events.h>
+
+uint8_t keyjazz_enabled = 0;
+uint8_t keyjazz_base_octave = 2;
+uint8_t keyjazz_velocity = 0x64;
+
+static uint8_t keycode = 0; // value of the pressed key
+
+static input_msg_s key = {normal, 0, 0, 0};+
+static unsigned char toggle_input_keyjazz() {+ keyjazz_enabled = !keyjazz_enabled;
+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, keyjazz_enabled ? "Keyjazz enabled" : "Keyjazz disabled");
+ return keyjazz_enabled;
+}
+
+// Get note value for a scancode, or -1 if not found
+static int get_note_for_scancode(SDL_Scancode scancode) {+
+ // Map from SDL scancodes to note offsets
+ const struct keyjazz_scancodes_t {+ SDL_Scancode scancode;
+ uint8_t note_offset;
+ } NOTE_MAP[] = {+ {SDL_SCANCODE_Z, 0}, {SDL_SCANCODE_S, 1}, {SDL_SCANCODE_X, 2}, {SDL_SCANCODE_D, 3},+ {SDL_SCANCODE_C, 4}, {SDL_SCANCODE_V, 5}, {SDL_SCANCODE_G, 6}, {SDL_SCANCODE_B, 7},+ {SDL_SCANCODE_H, 8}, {SDL_SCANCODE_N, 9}, {SDL_SCANCODE_J, 10}, {SDL_SCANCODE_M, 11},+ {SDL_SCANCODE_Q, 12}, {SDL_SCANCODE_2, 13}, {SDL_SCANCODE_W, 14}, {SDL_SCANCODE_3, 15},+ {SDL_SCANCODE_E, 16}, {SDL_SCANCODE_R, 17}, {SDL_SCANCODE_5, 18}, {SDL_SCANCODE_T, 19},+ {SDL_SCANCODE_6, 20}, {SDL_SCANCODE_Y, 21}, {SDL_SCANCODE_7, 22}, {SDL_SCANCODE_U, 23},+ {SDL_SCANCODE_I, 24}, {SDL_SCANCODE_9, 25}, {SDL_SCANCODE_O, 26}, {SDL_SCANCODE_0, 27},+ {SDL_SCANCODE_P, 28},+ };
+
+ const size_t NOTE_MAP_SIZE = (sizeof(NOTE_MAP) / sizeof(NOTE_MAP[0]));
+
+ for (size_t i = 0; i < NOTE_MAP_SIZE; i++) {+ if (NOTE_MAP[i].scancode == scancode) {+ return NOTE_MAP[i].note_offset + keyjazz_base_octave * 12;
+ }
+ }
+ return -1; // Not a note key
+}
+
+// Handle octave and velocity changes
+static void handle_keyjazz_settings(const SDL_Event *event, const config_params_s *conf) {+
+ // Constants for keyjazz limits and adjustments
+ const unsigned char KEYJAZZ_MIN_OCTAVE = 0;
+ const unsigned char KEYJAZZ_MAX_OCTAVE = 8;
+ const unsigned char KEYJAZZ_MIN_VELOCITY = 0;
+ const unsigned char KEYJAZZ_MAX_VELOCITY = 0x7F;
+ const unsigned char KEYJAZZ_FINE_VELOCITY_STEP = 1;
+ const unsigned char KEYJAZZ_COARSE_VELOCITY_STEP = 0x10;
+
+ if (event->key.repeat > 0 || event->key.type == SDL_EVENT_KEY_UP) {+ return;
+ }
+
+ const SDL_Scancode scancode = event->key.scancode;
+ const bool is_fine_adjustment = (event->key.mod & SDL_KMOD_ALT) > 0;
+
+ if (scancode == conf->key_jazz_dec_octave && keyjazz_base_octave > KEYJAZZ_MIN_OCTAVE) {+ keyjazz_base_octave--;
+ display_keyjazz_overlay(1, keyjazz_base_octave, keyjazz_velocity);
+ } else if (scancode == conf->key_jazz_inc_octave && keyjazz_base_octave < KEYJAZZ_MAX_OCTAVE) {+ keyjazz_base_octave++;
+ display_keyjazz_overlay(1, keyjazz_base_octave, keyjazz_velocity);
+ } else if (scancode == conf->key_jazz_dec_velocity) {+ const int step = is_fine_adjustment ? KEYJAZZ_FINE_VELOCITY_STEP : KEYJAZZ_COARSE_VELOCITY_STEP;
+ if (keyjazz_velocity > (is_fine_adjustment ? KEYJAZZ_MIN_VELOCITY + step : step)) {+ keyjazz_velocity -= step;
+ display_keyjazz_overlay(1, keyjazz_base_octave, keyjazz_velocity);
+ }
+ } else if (scancode == conf->key_jazz_inc_velocity) {+ const int step = is_fine_adjustment ? KEYJAZZ_FINE_VELOCITY_STEP : KEYJAZZ_COARSE_VELOCITY_STEP;
+ const int max = is_fine_adjustment ? KEYJAZZ_MAX_VELOCITY : (KEYJAZZ_MAX_VELOCITY - step);
+ if (keyjazz_velocity < max) {+ keyjazz_velocity += step;
+ display_keyjazz_overlay(1, keyjazz_base_octave, keyjazz_velocity);
+ }
+ }
+}
+
+static input_msg_s handle_keyjazz(SDL_Event *event, uint8_t keyvalue, config_params_s *conf) {+ input_msg_s key = {keyjazz, keyvalue, keyjazz_velocity, event->type};+
+ // Check if this is a note key
+ const int note_value = get_note_for_scancode(event->key.scancode);
+ if (note_value >= 0) {+ key.value = note_value;
+ return key;
+ }
+
+ // Not a note key, handle other settings
+ key.type = normal;
+ handle_keyjazz_settings(event, conf);
+
+ return key;
+}
+
+static input_msg_s handle_m8_buttons(const SDL_Event *event, const config_params_s *conf) {+ // Default message with normal type and no value
+ input_msg_s key = {normal, 0, 0, 0};+
+ // Get the current scancode
+ const SDL_Scancode scancode = event->key.scancode;
+
+ // Handle standard keycodes (single key mapping)
+ const struct {+ SDL_Scancode scancode;
+ uint8_t value;
+ } normal_key_map[] = {+ {conf->key_up, key_up},+ {conf->key_left, key_left},+ {conf->key_down, key_down},+ {conf->key_right, key_right},+ {conf->key_select, key_select},+ {conf->key_select_alt, key_select},+ {conf->key_start, key_start},+ {conf->key_start_alt, key_start},+ {conf->key_opt, key_opt},+ {conf->key_opt_alt, key_opt},+ {conf->key_edit, key_edit},+ {conf->key_edit_alt, key_edit},+ {conf->key_delete, key_opt | key_edit},+ };
+
+ // Handle special messages (different message type)
+ const struct {+ SDL_Scancode scancode;
+ special_messages_t message;
+ } special_key_map[] = {+ {conf->key_reset, msg_reset_display},+ {conf->key_toggle_audio, msg_toggle_audio},+ };
+
+ // Check normal key mappings
+ for (size_t i = 0; i < sizeof(normal_key_map) / sizeof(normal_key_map[0]); i++) {+ if (scancode == normal_key_map[i].scancode) {+ key.value = normal_key_map[i].value;
+ return key;
+ }
+ }
+
+ // Check special key mappings
+ for (size_t i = 0; i < sizeof(special_key_map) / sizeof(special_key_map[0]); i++) {+ if (scancode == special_key_map[i].scancode) {+ key.type = special;
+ key.value = special_key_map[i].message;
+ return key;
+ }
+ }
+
+ // No matching key found, return default key message
+ return key;
+}
+
+SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {+ struct app_context *ctx = appstate;
+ SDL_AppResult ret_val = SDL_APP_CONTINUE;
+ static int prev_key_analog = 0;
+
+ switch (event->type) {+
+ // --- System events ---
+ case SDL_EVENT_QUIT:
+ case SDL_EVENT_TERMINATING:
+ ret_val = SDL_APP_SUCCESS;
+ break;
+ case SDL_EVENT_DID_ENTER_BACKGROUND:
+ // iOS: Application entered into background on iOS. About 5 seconds to stop things.
+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_DID_ENTER_BACKGROUND");
+ ctx->app_suspended = 1;
+ if (ctx->device_connected)
+ m8_pause_processing();
+ break;
+ case SDL_EVENT_WILL_ENTER_BACKGROUND:
+ // iOS: App about to enter into background
+ break;
+ case SDL_EVENT_WILL_ENTER_FOREGROUND:
+ // iOS: App returning to foreground
+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_WILL_ENTER_FOREGROUND");
+ break;
+ case SDL_EVENT_DID_ENTER_FOREGROUND:
+ // iOS: App becomes interactive again
+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_DID_ENTER_FOREGROUND");
+ ctx->app_suspended = 0;
+ if (ctx->device_connected) {+ m8_resume_processing();
+ }
+ case SDL_EVENT_WINDOW_RESIZED:
+ case SDL_EVENT_WINDOW_MOVED:
+ // If window size is changed, some operating systems might need a little nudge to fix scaling
+ renderer_fix_texture_scaling_after_window_resize();
+ break;
+
+ // --- Input events ---
+ case SDL_EVENT_GAMEPAD_ADDED:
+ case SDL_EVENT_GAMEPAD_REMOVED:
+ // Reinitialize game controllers on controller add/remove/remap
+ gamecontrollers_initialize();
+ break;
+
+ case SDL_EVENT_KEY_DOWN:
+ if (event->key.repeat > 0) {+ break;
+ }
+
+ // ALT+ENTER toggles fullscreen
+ if (event->key.key == SDLK_RETURN && (event->key.mod & SDL_KMOD_ALT) > 0) {+ toggle_fullscreen();
+ break;
+ }
+
+ // ALT+F4 quits program
+ if (event->key.key == SDLK_F4 && (event->key.mod & SDL_KMOD_ALT) > 0) {+ key = (input_msg_s){special, msg_quit, 0, 0};+ break;
+ }
+
+ // ESC = toggle keyjazz
+ if (event->key.key == SDLK_ESCAPE) {+ display_keyjazz_overlay(toggle_input_keyjazz(), keyjazz_base_octave, keyjazz_velocity);
+ break;
+ }
+
+ key = handle_m8_buttons(event, &ctx->conf);
+ SDL_Log("key %d",key.value);+ if (keyjazz_enabled) {+ key = handle_keyjazz(event, key.value, &ctx->conf);
+ }
+ if (key.type == normal) {+ keycode |= key.value;
+ } else {+ keycode = key.value;
+ }
+ break;
+
+ case SDL_EVENT_KEY_UP:
+
+ key = handle_m8_buttons(event, &ctx->conf);
+ if (keyjazz_enabled) {+ key = handle_keyjazz(event, key.value, &ctx->conf);
+ }
+
+ if (key.type == normal)
+ keycode &= ~key.value;
+ else
+ keycode = 0;
+
+ break;
+
+ default:
+ break;
+ }
+ return ret_val;
+}
+
+// Handles SDL input events
+static void handle_sdl_events(config_params_s *conf) {+
+ static int prev_key_analog = 0;
+
+ SDL_Event event;
+
+ // Read joysticks
+ const int key_analog = gamecontrollers_handle_buttons(conf);
+ if (prev_key_analog != key_analog) {+ keycode = key_analog;
+ prev_key_analog = key_analog;
+ }
+
+ const input_msg_s gamepad_msg = gamecontrollers_handle_special_messages(conf);
+ if (gamepad_msg.type == special) {+ key = gamepad_msg;
+ }
+}
+
+int input_process(config_params_s *conf, enum app_state *app_state) {+ static uint8_t prev_input = 0;
+ static uint8_t prev_note = 0;
+
+ // get current inputs
+ const input_msg_s input = input_get_msg(conf);
+
+ switch (input.type) {+ case normal:
+ if (input.value != prev_input) {+ prev_input = input.value;
+ m8_send_msg_controller(input.value);
+ }
+ break;
+ case keyjazz:
+ if (input.value != 0) {+ if (input.eventType == SDL_EVENT_KEY_DOWN && input.value != prev_input) {+ m8_send_msg_keyjazz(input.value, input.value2);
+ prev_note = input.value;
+ } else if (input.eventType == SDL_EVENT_KEY_UP && input.value == prev_note) {+ m8_send_msg_keyjazz(0xFF, 0);
+ }
+ }
+ prev_input = input.value;
+ break;
+ case special:
+ if (input.value != prev_input) {+ prev_input = input.value;
+ switch (input.value) {+ case msg_quit:
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Received msg_quit from input device.");
+ *app_state = 0;
+ break;
+ case msg_reset_display:
+ m8_reset_display();
+ break;
+ case msg_toggle_audio:
+ conf->audio_enabled = !conf->audio_enabled;
+ audio_toggle(conf->audio_device_name, conf->audio_buffer_size);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+ return 1;
+}
+
+// Returns the currently pressed keys to main
+input_msg_s input_get_msg(config_params_s *conf) {+
+ key = (input_msg_s){normal, 0, 0, 0};+
+ // Query for SDL events
+ handle_sdl_events(conf);
+
+ if (!keyjazz_enabled && keycode == (key_start | key_select | key_opt | key_edit)) {+ key = (input_msg_s){special, msg_reset_display, 0, 0};+ }
+
+ if (key.type == normal) {+ /* Normal input keys go through some event-based manipulation in
+ handle_sdl_events(), the value is stored in keycode variable */
+ const input_msg_s input = (input_msg_s){key.type, keycode, 0, 0};+ return input;
+ }
+ // Special event keys already have the correct keycode baked in
+ return key;
+}
--- /dev/null
+++ b/src/events.h
@@ -1,0 +1,53 @@
+// Copyright 2021 Jonne Kokkonen
+// Released under the MIT licence, https://opensource.org/licenses/MIT
+
+#ifndef INPUT_H_
+#define INPUT_H_
+
+#include "config.h"
+#include "common.h"
+#include <stdint.h>
+
+typedef enum input_buttons_t {+ INPUT_UP,
+ INPUT_DOWN,
+ INPUT_LEFT,
+ INPUT_RIGHT,
+ INPUT_OPT,
+ INPUT_EDIT,
+ INPUT_SELECT,
+ INPUT_START,
+ INPUT_MAX
+} input_buttons_t;
+
+// Bits for M8 input messages
+typedef enum keycodes_t {+ key_left = 1 << 7,
+ key_up = 1 << 6,
+ key_down = 1 << 5,
+ key_select = 1 << 4,
+ key_start = 1 << 3,
+ key_right = 1 << 2,
+ key_opt = 1 << 1,
+ key_edit = 1
+} keycodes_t;
+
+typedef enum input_type_t { normal, keyjazz, special } input_type_t;+
+typedef enum special_messages_t {+ msg_quit = 1,
+ msg_reset_display = 2,
+ msg_toggle_audio = 3
+} special_messages_t;
+
+typedef struct input_msg_s {+ input_type_t type;
+ uint8_t value;
+ uint8_t value2;
+ uint32_t eventType;
+} input_msg_s;
+
+input_msg_s input_get_msg(config_params_s *conf);
+int input_process(config_params_s *conf, enum app_state *app_state);
+
+#endif
--- a/src/gamecontrollers.c
+++ b/src/gamecontrollers.c
@@ -4,7 +4,7 @@
#include "gamecontrollers.h"
#include "config.h"
-#include "input.h"
+#include "events.h"
#include <SDL3/SDL.h>
#include <stdio.h>
--- a/src/gamecontrollers.h
+++ b/src/gamecontrollers.h
@@ -6,7 +6,7 @@
#define GAMECONTROLLERS_H_
#include "config.h"
-#include "input.h"
+#include "events.h"
#define MAX_CONTROLLERS 4
--- a/src/input.c
+++ /dev/null
@@ -1,335 +1,0 @@
-#include "input.h"
-#include "backends/audio.h"
-#include "backends/m8.h"
-#include "config.h"
-#include "gamecontrollers.h"
-#include "render.h"
-#include <SDL3/SDL.h>
-
-uint8_t keyjazz_enabled = 0;
-uint8_t keyjazz_base_octave = 2;
-uint8_t keyjazz_velocity = 0x64;
-
-static uint8_t keycode = 0; // value of the pressed key
-
-static input_msg_s key = {normal, 0, 0, 0};-
-static unsigned char toggle_input_keyjazz() {- keyjazz_enabled = !keyjazz_enabled;
- SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, keyjazz_enabled ? "Keyjazz enabled" : "Keyjazz disabled");
- return keyjazz_enabled;
-}
-
-// Get note value for a scancode, or -1 if not found
-static int get_note_for_scancode(SDL_Scancode scancode) {-
- // Map from SDL scancodes to note offsets
- const struct keyjazz_scancodes_t {- SDL_Scancode scancode;
- uint8_t note_offset;
- } NOTE_MAP[] = {- {SDL_SCANCODE_Z, 0}, {SDL_SCANCODE_S, 1}, {SDL_SCANCODE_X, 2}, {SDL_SCANCODE_D, 3},- {SDL_SCANCODE_C, 4}, {SDL_SCANCODE_V, 5}, {SDL_SCANCODE_G, 6}, {SDL_SCANCODE_B, 7},- {SDL_SCANCODE_H, 8}, {SDL_SCANCODE_N, 9}, {SDL_SCANCODE_J, 10}, {SDL_SCANCODE_M, 11},- {SDL_SCANCODE_Q, 12}, {SDL_SCANCODE_2, 13}, {SDL_SCANCODE_W, 14}, {SDL_SCANCODE_3, 15},- {SDL_SCANCODE_E, 16}, {SDL_SCANCODE_R, 17}, {SDL_SCANCODE_5, 18}, {SDL_SCANCODE_T, 19},- {SDL_SCANCODE_6, 20}, {SDL_SCANCODE_Y, 21}, {SDL_SCANCODE_7, 22}, {SDL_SCANCODE_U, 23},- {SDL_SCANCODE_I, 24}, {SDL_SCANCODE_9, 25}, {SDL_SCANCODE_O, 26}, {SDL_SCANCODE_0, 27},- {SDL_SCANCODE_P, 28},- };
-
- const size_t NOTE_MAP_SIZE = (sizeof(NOTE_MAP) / sizeof(NOTE_MAP[0]));
-
- for (size_t i = 0; i < NOTE_MAP_SIZE; i++) {- if (NOTE_MAP[i].scancode == scancode) {- return NOTE_MAP[i].note_offset + keyjazz_base_octave * 12;
- }
- }
- return -1; // Not a note key
-}
-
-// Handle octave and velocity changes
-static void handle_keyjazz_settings(const SDL_Event *event, const config_params_s *conf) {-
- // Constants for keyjazz limits and adjustments
- const unsigned char KEYJAZZ_MIN_OCTAVE = 0;
- const unsigned char KEYJAZZ_MAX_OCTAVE = 8;
- const unsigned char KEYJAZZ_MIN_VELOCITY = 0;
- const unsigned char KEYJAZZ_MAX_VELOCITY = 0x7F;
- const unsigned char KEYJAZZ_FINE_VELOCITY_STEP = 1;
- const unsigned char KEYJAZZ_COARSE_VELOCITY_STEP = 0x10;
-
- if (event->key.repeat > 0 || event->key.type == SDL_EVENT_KEY_UP) {- return;
- }
-
- const SDL_Scancode scancode = event->key.scancode;
- const bool is_fine_adjustment = (event->key.mod & SDL_KMOD_ALT) > 0;
-
- if (scancode == conf->key_jazz_dec_octave && keyjazz_base_octave > KEYJAZZ_MIN_OCTAVE) {- keyjazz_base_octave--;
- display_keyjazz_overlay(1, keyjazz_base_octave, keyjazz_velocity);
- } else if (scancode == conf->key_jazz_inc_octave && keyjazz_base_octave < KEYJAZZ_MAX_OCTAVE) {- keyjazz_base_octave++;
- display_keyjazz_overlay(1, keyjazz_base_octave, keyjazz_velocity);
- } else if (scancode == conf->key_jazz_dec_velocity) {- const int step = is_fine_adjustment ? KEYJAZZ_FINE_VELOCITY_STEP : KEYJAZZ_COARSE_VELOCITY_STEP;
- if (keyjazz_velocity > (is_fine_adjustment ? KEYJAZZ_MIN_VELOCITY + step : step)) {- keyjazz_velocity -= step;
- display_keyjazz_overlay(1, keyjazz_base_octave, keyjazz_velocity);
- }
- } else if (scancode == conf->key_jazz_inc_velocity) {- const int step = is_fine_adjustment ? KEYJAZZ_FINE_VELOCITY_STEP : KEYJAZZ_COARSE_VELOCITY_STEP;
- const int max = is_fine_adjustment ? KEYJAZZ_MAX_VELOCITY : (KEYJAZZ_MAX_VELOCITY - step);
- if (keyjazz_velocity < max) {- keyjazz_velocity += step;
- display_keyjazz_overlay(1, keyjazz_base_octave, keyjazz_velocity);
- }
- }
-}
-
-static input_msg_s handle_keyjazz(SDL_Event *event, uint8_t keyvalue, config_params_s *conf) {- input_msg_s key = {keyjazz, keyvalue, keyjazz_velocity, event->type};-
- // Check if this is a note key
- const int note_value = get_note_for_scancode(event->key.scancode);
- if (note_value >= 0) {- key.value = note_value;
- return key;
- }
-
- // Not a note key, handle other settings
- key.type = normal;
- handle_keyjazz_settings(event, conf);
-
- return key;
-}
-
-static input_msg_s handle_normal_keys(const SDL_Event *event, const config_params_s *conf) {- // Default message with normal type and no value
- input_msg_s key = {normal, 0, 0, 0};-
- // Get the current scancode
- const SDL_Scancode scancode = event->key.scancode;
-
- // Handle standard keycodes (single key mapping)
- const struct {- SDL_Scancode scancode;
- uint8_t value;
- } normal_key_map[] = {- {conf->key_up, key_up},- {conf->key_left, key_left},- {conf->key_down, key_down},- {conf->key_right, key_right},- {conf->key_select, key_select},- {conf->key_select_alt, key_select},- {conf->key_start, key_start},- {conf->key_start_alt, key_start},- {conf->key_opt, key_opt},- {conf->key_opt_alt, key_opt},- {conf->key_edit, key_edit},- {conf->key_edit_alt, key_edit},- {conf->key_delete, key_opt | key_edit},- };
-
- // Handle special messages (different message type)
- const struct {- SDL_Scancode scancode;
- special_messages_t message;
- } special_key_map[] = {- {conf->key_reset, msg_reset_display},- {conf->key_toggle_audio, msg_toggle_audio},- };
-
- // Check normal key mappings
- for (size_t i = 0; i < sizeof(normal_key_map) / sizeof(normal_key_map[0]); i++) {- if (scancode == normal_key_map[i].scancode) {- key.value = normal_key_map[i].value;
- return key;
- }
- }
-
- // Check special key mappings
- for (size_t i = 0; i < sizeof(special_key_map) / sizeof(special_key_map[0]); i++) {- if (scancode == special_key_map[i].scancode) {- key.type = special;
- key.value = special_key_map[i].message;
- return key;
- }
- }
-
- // No matching key found, return default key message
- return key;
-}
-
-// Handles SDL input events
-static void handle_sdl_events(config_params_s *conf) {-
- static int prev_key_analog = 0;
-
- SDL_Event event;
-
- // Read joysticks
- const int key_analog = gamecontrollers_handle_buttons(conf);
- if (prev_key_analog != key_analog) {- keycode = key_analog;
- prev_key_analog = key_analog;
- }
-
- const input_msg_s gamepad_msg = gamecontrollers_handle_special_messages(conf);
- if (gamepad_msg.type == special) {- key = gamepad_msg;
- }
-
- while (SDL_PollEvent(&event)) {-
- switch (event.type) {-
- // Reinitialize game controllers on controller add/remove/remap
- case SDL_EVENT_GAMEPAD_ADDED:
- case SDL_EVENT_GAMEPAD_REMOVED:
- gamecontrollers_initialize();
- break;
-
- // Handle SDL quit events (for example, window close)
- case SDL_EVENT_QUIT:
- key = (input_msg_s){special, msg_quit, 0, 0};- break;
-
- case SDL_EVENT_WINDOW_RESIZED:
- case SDL_EVENT_WINDOW_MOVED:
- renderer_fix_texture_scaling_after_window_resize();
- break;
-
- case SDL_EVENT_KEY_DOWN:
-
- if (event.key.repeat > 0) {- break;
- }
-
- // ALT+ENTER toggles fullscreen
- if (event.key.key == SDLK_RETURN && (event.key.mod & SDL_KMOD_ALT) > 0) {- toggle_fullscreen();
- break;
- }
-
- // ALT+F4 quits program
- if (event.key.key == SDLK_F4 && (event.key.mod & SDL_KMOD_ALT) > 0) {- key = (input_msg_s){special, msg_quit, 0, 0};- break;
- }
-
- // ESC = toggle keyjazz
- if (event.key.key == SDLK_ESCAPE) {- display_keyjazz_overlay(toggle_input_keyjazz(), keyjazz_base_octave, keyjazz_velocity);
- break;
- }
-
- // Intentional fallthrough
- case SDL_EVENT_KEY_UP:
-
- // Normal keyboard inputs
- key = handle_normal_keys(&event, conf);
-
- if (keyjazz_enabled) {- key = handle_keyjazz(&event, key.value, conf);
- }
- break;
-
- default:
- break;
- }
-
- switch (key.type) {- case normal:
- if (event.type == SDL_EVENT_KEY_DOWN) {- keycode |= key.value;
- } else if (event.type == SDL_EVENT_KEY_UP) {- keycode &= ~key.value;
- }
- break;
- case keyjazz:
- // Do not allow pressing multiple keys with keyjazz
- case special:
- if (event.type == SDL_EVENT_KEY_DOWN) {- keycode = key.value;
- } else if (event.type == SDL_EVENT_KEY_UP) {- keycode = 0;
- }
- break;
- default:
- break;
- }
- }
-}
-
-int input_process(config_params_s *conf, enum app_state *app_state) {- static uint8_t prev_input = 0;
- static uint8_t prev_note = 0;
-
- // get current inputs
- const input_msg_s input = input_get_msg(conf);
-
- switch (input.type) {- case normal:
- if (input.value != prev_input) {- prev_input = input.value;
- m8_send_msg_controller(input.value);
- }
- break;
- case keyjazz:
- if (input.value != 0) {- if (input.eventType == SDL_EVENT_KEY_DOWN && input.value != prev_input) {- m8_send_msg_keyjazz(input.value, input.value2);
- prev_note = input.value;
- } else if (input.eventType == SDL_EVENT_KEY_UP && input.value == prev_note) {- m8_send_msg_keyjazz(0xFF, 0);
- }
- }
- prev_input = input.value;
- break;
- case special:
- if (input.value != prev_input) {- prev_input = input.value;
- switch (input.value) {- case msg_quit:
- SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Received msg_quit from input device.");
- *app_state = 0;
- break;
- case msg_reset_display:
- m8_reset_display();
- break;
- case msg_toggle_audio:
- conf->audio_enabled = !conf->audio_enabled;
- audio_toggle(conf->audio_device_name, conf->audio_buffer_size);
- break;
- default:
- break;
- }
- break;
- }
- }
- return 1;
-}
-
-// Returns the currently pressed keys to main
-input_msg_s input_get_msg(config_params_s *conf) {-
- key = (input_msg_s){normal, 0, 0, 0};-
- // Query for SDL events
- handle_sdl_events(conf);
-
- if (!keyjazz_enabled && keycode == (key_start | key_select | key_opt | key_edit)) {- key = (input_msg_s){special, msg_reset_display, 0, 0};- }
-
- if (key.type == normal) {- /* Normal input keys go through some event-based manipulation in
- handle_sdl_events(), the value is stored in keycode variable */
- const input_msg_s input = (input_msg_s){key.type, keycode, 0, 0};- return input;
- }
- // Special event keys already have the correct keycode baked in
- return key;
-}
--- a/src/input.h
+++ /dev/null
@@ -1,54 +1,0 @@
-// Copyright 2021 Jonne Kokkonen
-// Released under the MIT licence, https://opensource.org/licenses/MIT
-
-#ifndef INPUT_H_
-#define INPUT_H_
-
-#include "config.h"
-#include <stdint.h>
-
-enum app_state { QUIT, WAIT_FOR_DEVICE, RUN };-
-typedef enum input_buttons_t {- INPUT_UP,
- INPUT_DOWN,
- INPUT_LEFT,
- INPUT_RIGHT,
- INPUT_OPT,
- INPUT_EDIT,
- INPUT_SELECT,
- INPUT_START,
- INPUT_MAX
-} input_buttons_t;
-
-// Bits for M8 input messages
-typedef enum keycodes_t {- key_left = 1 << 7,
- key_up = 1 << 6,
- key_down = 1 << 5,
- key_select = 1 << 4,
- key_start = 1 << 3,
- key_right = 1 << 2,
- key_opt = 1 << 1,
- key_edit = 1
-} keycodes_t;
-
-typedef enum input_type_t { normal, keyjazz, special } input_type_t;-
-typedef enum special_messages_t {- msg_quit = 1,
- msg_reset_display = 2,
- msg_toggle_audio = 3
-} special_messages_t;
-
-typedef struct input_msg_s {- input_type_t type;
- uint8_t value;
- uint8_t value2;
- uint32_t eventType;
-} input_msg_s;
-
-input_msg_s input_get_msg(config_params_s *conf);
-int input_process(config_params_s *conf, enum app_state *app_state);
-
-#endif
--- a/src/main.c
+++ b/src/main.c
@@ -14,19 +14,12 @@
#include "SDL2_inprint.h"
#include "backends/audio.h"
#include "backends/m8.h"
+#include "common.h"
#include "config.h"
#include "gamecontrollers.h"
-#include "input.h"
+#include "events.h"
#include "render.h"
-struct app_context {- config_params_s conf;
- enum app_state app_state;
- char *preferred_device;
- unsigned char device_connected;
- unsigned char app_suspended;
-};
-
static void do_wait_for_device(struct app_context *ctx) {static Uint64 ticks_poll_device = 0;
static int screensaver_initialized = 0;
@@ -112,6 +105,43 @@
return device_connected;
}
+// Main callback loop - read inputs, process data from device, render screen
+SDL_AppResult SDL_AppIterate(void *appstate) {+ struct app_context *ctx = appstate;
+ SDL_AppResult app_result = SDL_APP_CONTINUE;
+
+ switch (ctx->app_state) {+
+ case WAIT_FOR_DEVICE: {+ if (ctx->conf.wait_for_device) {+ do_wait_for_device(ctx);
+ }
+ break;
+ }
+
+ case RUN: {+ const int result = m8_process_data(&ctx->conf);
+ if (result == DEVICE_DISCONNECTED) {+ ctx->device_connected = 0;
+ ctx->app_state = WAIT_FOR_DEVICE;
+ audio_close();
+ } else if (result == DEVICE_FATAL_ERROR) {+ return SDL_APP_FAILURE;
+ }
+ render_screen();
+ break;
+ }
+
+ case QUIT: {+ app_result = SDL_APP_SUCCESS;
+ break;
+ }
+ }
+
+ return app_result;
+}
+
+// Initialize the app: initialize context, configs, renderer controllers and attempt to find M8
SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) {char *config_filename = NULL;
@@ -132,11 +162,16 @@
}
#ifndef NDEBUG
+ // Show debug messages in the application log
SDL_SetLogPriorities(SDL_LOG_PRIORITY_DEBUG);
SDL_LogDebug(SDL_LOG_CATEGORY_TEST, "Running a Debug build");
#endif
gamecontrollers_initialize();
+
+ // Process the application's main callback roughly at 120hz
+ SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "120");
+
*appstate = ctx;
if (ctx->app_state == WAIT_FOR_DEVICE) {@@ -155,54 +190,14 @@
ctx->device_connected = 0;
ctx->app_state = ctx->conf.wait_for_device ? WAIT_FOR_DEVICE : QUIT;
}
- }
-
- return SDL_APP_CONTINUE;
-}
-
-SDL_AppResult SDL_AppIterate(void *appstate) {- struct app_context *ctx = appstate;
- SDL_AppResult app_result = SDL_APP_CONTINUE;
-
- switch (ctx->app_state) {- case WAIT_FOR_DEVICE: {- if (ctx->conf.wait_for_device) {- do_wait_for_device(ctx);
- }
- break;
- }
-
- case RUN:
- break;
- case QUIT:
- break;
}
- return app_result;
-
- if (ctx->conf.wait_for_device && ctx->app_state == WAIT_FOR_DEVICE) {- do_wait_for_device(ctx);
- } else if (!ctx->device_connected && ctx->app_state != WAIT_FOR_DEVICE) {- return SDL_APP_FAILURE;
- }
-
- // Handle input, process data, and render screen while running.
- if (ctx->app_state == RUN) {- const int result = m8_process_data(&ctx->conf);
- if (result == DEVICE_DISCONNECTED) {- ctx->device_connected = 0;
- ctx->app_state = WAIT_FOR_DEVICE;
- audio_close();
- } else if (result == DEVICE_FATAL_ERROR) {- return SDL_APP_FAILURE;
- }
- render_screen();
- }
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void *appstate, SDL_AppResult result) {struct app_context *app = appstate;
+
if (app) { if (app->app_state == WAIT_FOR_DEVICE) {screensaver_destroy();
@@ -216,61 +211,9 @@
if (app->device_connected) {m8_close();
}
- SDL_Quit();
- SDL_Log("Shutting down.");-
SDL_free(app);
- }
-}
-SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {- struct app_context *ctx = appstate;
- SDL_AppResult ret_val = SDL_APP_CONTINUE;
-
- switch (event->type) {- case SDL_EVENT_QUIT:
- case SDL_EVENT_TERMINATING:
- ret_val = SDL_APP_SUCCESS;
- break;
- case SDL_EVENT_DID_ENTER_BACKGROUND:
- /* This will get called if the user accepted whatever sent your app to the background.
- If the user got a phone call and canceled it, you'll instead get an
- SDL_EVENT_DID_ENTER_FOREGROUND event and restart your loops. When you get this, you have 5
- seconds to save all your state or the app will be terminated. Your app is NOT active at this
- point.
- */
- SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_DID_ENTER_BACKGROUND");
- ctx->app_suspended = 1;
- if (ctx->device_connected)
- m8_pause_processing();
- break;
- case SDL_EVENT_LOW_MEMORY:
- /* You will get this when your app is paused and iOS wants more memory.
- Release as much memory as possible.
- */
- break;
- case SDL_EVENT_WILL_ENTER_BACKGROUND:
- /* Prepare your app to go into the background. Stop loops, etc.
- This gets called when the user hits the home button, or gets a call.
- */
- break;
- case SDL_EVENT_WILL_ENTER_FOREGROUND:
- /* This call happens when your app is coming back to the foreground.
- Restore all your state here.
- */
- SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_WILL_ENTER_FOREGROUND");
- break;
- case SDL_EVENT_DID_ENTER_FOREGROUND:
- /* Restart your loops here.
- Your app is interactive and getting CPU again.
- */
- SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_DID_ENTER_FOREGROUND");
- ctx->app_suspended = 0;
- if (ctx->device_connected) {- m8_resume_processing();
- }
- default:
- break;
- }
- return ret_val;
+ SDL_Log("Shutting down.");+ SDL_Quit();
+ }
}
\ No newline at end of file
--- a/src/render.c
+++ b/src/render.c
@@ -77,6 +77,8 @@
return false;
}
+ SDL_SetRenderVSync(rend, 1);
+
if (!SDL_SetRenderLogicalPresentation(rend, texture_width, texture_height, window_scaling_mode)) {SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set renderer logical presentation: %s",
SDL_GetError());
--
⑨