shithub: m8c

Download patch

ref: 61fa136412fcc4504e198cd6d457a7cb57ed17d1
parent: 9bfe4ddb18ee77192c57b91c4ef305082588d77e
author: Jonne Kokkonen <jonne.kokkonen@gmail.com>
date: Wed Nov 24 07:28:06 EST 2021

analog joy support, update readme with faq section

--- a/README.md
+++ b/README.md
@@ -49,7 +49,7 @@
 
 ```
 cd m8c
-make && sudo make install
+make
  ```
 
 ### Start the program
@@ -57,7 +57,7 @@
 Connect the Teensy to your computer and start the program. It should automatically detect your device.
 
 ```
-m8c
+./m8c
 ```
 
 If the stars are aligned correctly, you should see the M8 screen.
@@ -101,16 +101,22 @@
 
 -----------
 
-### Bonus: improve performance on the Raspberry Pi
-Enabling the experimental GL Driver with Full KMS can boost the program's performance a bit.
+## FAQ
 
-The driver can be enabled with ```sudo raspi-config``` and selecting "Advanced options" -> "GL Driver" -> "GL (Full KMS)" and rebooting.
+* When starting the program, something like the following appears and the program does not start:
+```
+$ ./m8c
+INFO: Looking for USB serial devices.
+INFO: Found M8 in /dev/ttyACM1.
+INFO: Opening port.
+Aborted (core dumped)
+```
 
-Please note that with some configurations (for example, composite video) this can lead to not getting video output at all. If that happens, you can delete the row ```dtoverlay=vc4-kms-v3d``` in bottom of /boot/config.txt.
+This is likely an issue with the version of libserialport included in your Linux distribution and you need to build the library yourself. Please see [this issue for a workaround](https://github.com/laamaa/m8c/issues/20).
 
-Further performance improvement can be achieved by not using X11 and running the program directly in framebuffer console, but this might require doing a custom build of SDL.
+-----------
 
-### Bonus: quickly install m8c locally with nix
+### Bonus content: quickly install m8c locally with nix
 
 ``` sh
 nix-env -iA m8c-stable -f https://github.com/laamaa/m8c/archive/refs/heads/main.tar.gz
--- a/config.c
+++ b/config.c
@@ -25,14 +25,15 @@
   c.key_delete      = SDL_SCANCODE_DELETE;
   c.key_reset       = SDL_SCANCODE_R;
 
-  c.gamepad_up      = SDL_CONTROLLER_BUTTON_DPAD_UP;
-  c.gamepad_left    = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
-  c.gamepad_down    = SDL_CONTROLLER_BUTTON_DPAD_DOWN;
-  c.gamepad_right   = SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
-  c.gamepad_select  = SDL_CONTROLLER_BUTTON_BACK;
-  c.gamepad_start   = SDL_CONTROLLER_BUTTON_START;
-  c.gamepad_opt     = SDL_CONTROLLER_BUTTON_B;
-  c.gamepad_edit    = SDL_CONTROLLER_BUTTON_A;
+  c.gamepad_up                = SDL_CONTROLLER_BUTTON_DPAD_UP;
+  c.gamepad_left              = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
+  c.gamepad_down              = SDL_CONTROLLER_BUTTON_DPAD_DOWN;
+  c.gamepad_right             = SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
+  c.gamepad_select            = SDL_CONTROLLER_BUTTON_BACK;
+  c.gamepad_start             = SDL_CONTROLLER_BUTTON_START;
+  c.gamepad_opt               = SDL_CONTROLLER_BUTTON_B;
+  c.gamepad_edit              = SDL_CONTROLLER_BUTTON_A;
+  c.gamepad_analog_threshold  = 32000;
   return c;
 }
 
@@ -98,21 +99,23 @@
 void read_gamepad_config(ini_t *ini, config_params_s *conf) {
   // TODO: Some form of validation
 
-  const char *gamepad_up      = ini_get(ini, "gamepad", "gamepad_up");
-  const char *gamepad_left    = ini_get(ini, "gamepad", "gamepad_left");
-  const char *gamepad_down    = ini_get(ini, "gamepad", "gamepad_down");
-  const char *gamepad_right   = ini_get(ini, "gamepad", "gamepad_right");
-  const char *gamepad_select  = ini_get(ini, "gamepad", "gamepad_select");
-  const char *gamepad_start   = ini_get(ini, "gamepad", "gamepad_start");
-  const char *gamepad_opt     = ini_get(ini, "gamepad", "gamepad_opt");
-  const char *gamepad_edit    = ini_get(ini, "gamepad", "gamepad_edit");
+  const char *gamepad_up                = ini_get(ini, "gamepad", "gamepad_up");
+  const char *gamepad_left              = ini_get(ini, "gamepad", "gamepad_left");
+  const char *gamepad_down              = ini_get(ini, "gamepad", "gamepad_down");
+  const char *gamepad_right             = ini_get(ini, "gamepad", "gamepad_right");
+  const char *gamepad_select            = ini_get(ini, "gamepad", "gamepad_select");
+  const char *gamepad_start             = ini_get(ini, "gamepad", "gamepad_start");
+  const char *gamepad_opt               = ini_get(ini, "gamepad", "gamepad_opt");
+  const char *gamepad_edit              = ini_get(ini, "gamepad", "gamepad_edit");
+  const char *gamepad_analog_threshold  = ini_get(ini, "gamepad", "gamepad_analog_threshold");
 
-  conf->gamepad_up      = atoi(gamepad_up);
-  conf->gamepad_left    = atoi(gamepad_left);
-  conf->gamepad_down    = atoi(gamepad_down);
-  conf->gamepad_right   = atoi(gamepad_right);
-  conf->gamepad_select  = atoi(gamepad_select);
-  conf->gamepad_start   = atoi(gamepad_start);
-  conf->gamepad_opt     = atoi(gamepad_opt);
-  conf->gamepad_edit    = atoi(gamepad_edit);
+  conf->gamepad_up                = atoi(gamepad_up);
+  conf->gamepad_left              = atoi(gamepad_left);
+  conf->gamepad_down              = atoi(gamepad_down);
+  conf->gamepad_right             = atoi(gamepad_right);
+  conf->gamepad_select            = atoi(gamepad_select);
+  conf->gamepad_start             = atoi(gamepad_start);
+  conf->gamepad_opt               = atoi(gamepad_opt);
+  conf->gamepad_edit              = atoi(gamepad_edit);
+  conf->gamepad_analog_threshold  = atoi(gamepad_analog_threshold);
 }
\ No newline at end of file
--- a/config.h
+++ b/config.h
@@ -33,6 +33,8 @@
   int gamepad_start;
   int gamepad_opt;
   int gamepad_edit;
+
+  int gamepad_analog_threshold;
 } config_params_s;
 
 
--- a/config.ini
+++ b/config.ini
@@ -30,4 +30,5 @@
 gamepad_select=4
 gamepad_start=6
 gamepad_opt=1
-gamepad_edit=0
\ No newline at end of file
+gamepad_edit=0
+gamepad_analog_threshold=32767 ;the threshold for analog sticks to trigger cursor movement (range: 1-32767)
\ No newline at end of file
--- a/input.c
+++ b/input.c
@@ -2,6 +2,9 @@
 // Released under the MIT licence, https://opensource.org/licenses/MIT
 
 #include <SDL2/SDL.h>
+#include <SDL2/SDL_events.h>
+#include <SDL2/SDL_gamecontroller.h>
+#include <SDL2/SDL_log.h>
 #include <stdio.h>
 
 #include "config.h"
@@ -28,7 +31,8 @@
 uint8_t keyjazz_enabled = 0;
 uint8_t keyjazz_base_octave = 2;
 
-uint8_t keycode = 0; // value of the pressed key
+uint8_t keycode = 0;          // value of the pressed key
+static int controller_axis_released = 1; // is analog axis released
 input_msg_s key = {normal, 0};
 
 uint8_t toggle_input_keyjazz() {
@@ -184,7 +188,8 @@
   return key;
 }
 
-static input_msg_s handle_normal_keys(SDL_Event *event, config_params_s *conf, uint8_t keyvalue) {
+static input_msg_s handle_normal_keys(SDL_Event *event, config_params_s *conf,
+                                      uint8_t keyvalue) {
   input_msg_s key = {normal, keyvalue};
 
   if (event->key.keysym.scancode == conf->key_up) {
@@ -195,13 +200,17 @@
     key.value = key_down;
   } else if (event->key.keysym.scancode == conf->key_right) {
     key.value = key_right;
-  } else if (event->key.keysym.scancode == conf->key_select || event->key.keysym.scancode == conf->key_select_alt ) {
+  } else if (event->key.keysym.scancode == conf->key_select ||
+             event->key.keysym.scancode == conf->key_select_alt) {
     key.value = key_select;
-  } else if (event->key.keysym.scancode == conf->key_start || event->key.keysym.scancode == conf->key_start_alt) {
+  } else if (event->key.keysym.scancode == conf->key_start ||
+             event->key.keysym.scancode == conf->key_start_alt) {
     key.value = key_start;
-  } else if (event->key.keysym.scancode == conf->key_opt || event->key.keysym.scancode == conf->key_opt_alt) {
+  } else if (event->key.keysym.scancode == conf->key_opt ||
+             event->key.keysym.scancode == conf->key_opt_alt) {
     key.value = key_opt;
-  } else if (event->key.keysym.scancode == conf->key_edit || event->key.keysym.scancode == conf->key_edit_alt) {
+  } else if (event->key.keysym.scancode == conf->key_edit ||
+             event->key.keysym.scancode == conf->key_edit_alt) {
     key.value = key_edit;
   } else if (event->key.keysym.scancode == conf->key_delete) {
     key.value = key_opt | key_edit;
@@ -213,7 +222,9 @@
   return key;
 }
 
-static input_msg_s handle_game_controller_buttons(SDL_Event *event, config_params_s *conf, uint8_t keyvalue) {
+static input_msg_s handle_game_controller_buttons(SDL_Event *event,
+                                                  config_params_s *conf,
+                                                  uint8_t keyvalue) {
   input_msg_s key = {normal, keyvalue};
 
   if (event->cbutton.button == conf->gamepad_up) {
@@ -238,6 +249,71 @@
   return key;
 }
 
+static input_msg_s handle_game_controller_axis(SDL_Event *event,
+                                               config_params_s *conf,
+                                               uint8_t keyvalue) {
+
+  input_msg_s key = {normal, keyvalue};
+
+  // Handle up-down movement
+  if (event->caxis.axis == SDL_CONTROLLER_AXIS_LEFTY ||
+      event->caxis.axis == SDL_CONTROLLER_AXIS_RIGHTY) {
+
+    if (event->caxis.value > 0) {
+      key.value = key_down;
+      if (event->caxis.value < conf->gamepad_analog_threshold) {
+        if (controller_axis_released == 0) {
+          controller_axis_released = 1;
+          SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Axis released");
+        }
+      } else {
+        controller_axis_released = 0;
+        SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Axis down");
+      }
+    } else {
+      key.value = key_up;
+      if (event->caxis.value > 0 - conf->gamepad_analog_threshold) {
+        if (controller_axis_released == 0) {
+          controller_axis_released = 1;
+          SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Axis released");
+        }
+      } else {
+        controller_axis_released = 0;
+        SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Axis up");
+      }
+    }
+  }
+  // Handle left-right movement
+  else if (event->caxis.axis == SDL_CONTROLLER_AXIS_LEFTX ||
+           event->caxis.axis == SDL_CONTROLLER_AXIS_RIGHTX) {
+    if (event->caxis.value > 0) {
+      key.value = key_right;
+      if (event->caxis.value < conf->gamepad_analog_threshold) {
+        if (controller_axis_released == 0) {
+          controller_axis_released = 1;
+          SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Axis released");
+        }
+      } else {
+        controller_axis_released = 0;
+        SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Axis down");
+      }
+    } else {
+      key.value = key_left;
+      if (event->caxis.value > 0 - conf->gamepad_analog_threshold) {
+        if (controller_axis_released == 0) {
+          controller_axis_released = 1;
+          SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Axis released");
+        }
+      } else {
+        controller_axis_released = 0;
+        SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Axis up");
+      }
+    }
+  }
+
+  return key;
+}
+
 // Handles SDL input events
 void handle_sdl_events(config_params_s *conf) {
 
@@ -293,6 +369,10 @@
     key = handle_game_controller_buttons(&event, conf, 0);
     break;
 
+  case SDL_CONTROLLERAXISMOTION:
+    key = handle_game_controller_axis(&event, conf, 0);
+    break;
+
   default:
     break;
   }
@@ -299,10 +379,14 @@
 
   // Do not allow pressing multiple keys with keyjazz
   if (key.type == normal) {
-    if (event.type == SDL_KEYDOWN || event.type == SDL_CONTROLLERBUTTONDOWN)
+
+    if (event.type == SDL_KEYDOWN || event.type == SDL_CONTROLLERBUTTONDOWN ||
+        controller_axis_released == 0) {
       keycode |= key.value;
-    else
+    } else {
       keycode &= ~key.value;
+    }
+
   } else {
     if (event.type == SDL_KEYDOWN)
       keycode = key.value;
@@ -319,8 +403,8 @@
   // Query for SDL events
   handle_sdl_events(conf);
 
-  if (keycode == (key_start|key_select|key_opt|key_edit)){
-    key = (input_msg_s){special,msg_reset_display};
+  if (keycode == (key_start | key_select | key_opt | key_edit)) {
+    key = (input_msg_s){special, msg_reset_display};
   }
 
   if (key.type == normal) {
--