Browse Source

Add additional hooks for Community modules (#25050)

Drashna Jaelre 1 year ago
parent
commit
12caf0be4e

+ 55 - 0
data/constants/module_hooks/1.1.0.hjson

@@ -0,0 +1,55 @@
+{
+    pointing_device_init: {
+        ret_type: void
+        args: void
+        guard: defined(POINTING_DEVICE_ENABLE)
+    }
+    pointing_device_task: {
+        ret_type: report_mouse_t
+        args: report_mouse_t mouse_report
+        call_params: mouse_report
+        guard: defined(POINTING_DEVICE_ENABLE)
+        header: report.h
+    }
+    rgb_matrix_indicators: {
+        ret_type: bool
+        args: void
+        guard: defined(RGB_MATRIX_ENABLE)
+        header: rgb_matrix.h
+    }
+    rgb_matrix_indicators_advanced: {
+        ret_type: bool
+        args: uint8_t led_min, uint8_t led_max
+        call_params: led_min, led_max
+        guard: defined(RGB_MATRIX_ENABLE)
+        header: rgb_matrix.h
+    }
+    led_matrix_indicators: {
+        ret_type: bool
+        args: void
+        guard: defined(LED_MATRIX_ENABLE)
+        header: led_matrix.h
+    }
+    led_matrix_indicators_advanced: {
+        ret_type: bool
+        args: uint8_t led_min, uint8_t led_max
+        call_params: led_min, led_max
+        guard: defined(LED_MATRIX_ENABLE)
+        header: led_matrix.h
+    }
+    default_layer_state_set: {
+        ret_type: layer_state_t
+        args: layer_state_t state
+        call_params: state
+        guard: !defined(NO_ACTION_LAYER)
+        header: action_layer.h
+    }
+    layer_state_set: {
+        ret_type: layer_state_t
+        args: layer_state_t state
+        call_params: state
+        guard: !defined(NO_ACTION_LAYER)
+        header: action_layer.h
+    }
+
+}

+ 21 - 12
docs/features/community_modules.md

@@ -127,18 +127,27 @@ Introspection is a relatively advanced topic within QMK, and existing patterns s
 
 Community Modules may provide specializations for the following APIs:
 
-| Base API                   | API Format                          | Example (`hello_world` module)         | API Version |
-|----------------------------|-------------------------------------|----------------------------------------|-------------|
-| `keyboard_pre_init`        | `keyboard_pre_init_<module>`        | `keyboard_pre_init_hello_world`        | `0.1.0`     |
-| `keyboard_post_init`       | `keyboard_post_init_<module>`       | `keyboard_post_init_hello_world`       | `0.1.0`     |
-| `pre_process_record`       | `pre_process_record_<module>`       | `pre_process_record_hello_world`       | `0.1.0`     |
-| `process_record`           | `process_record_<module>`           | `process_record_hello_world`           | `0.1.0`     |
-| `post_process_record`      | `post_process_record_<module>`      | `post_process_record_hello_world`      | `0.1.0`     |
-| `housekeeping_task`        | `housekeeping_task_<module>`        | `housekeeping_task_hello_world`        | `1.0.0`     |
-| `suspend_power_down`       | `suspend_power_down_<module>`       | `suspend_power_down_hello_world`       | `1.0.0`     |
-| `suspend_wakeup_init`      | `suspend_wakeup_init_<module>`      | `suspend_wakeup_init_hello_world`      | `1.0.0`     |
-| `shutdown`                 | `shutdown_<module>`                 | `shutdown_hello_world`                 | `1.0.0`     |
-| `process_detected_host_os` | `process_detected_host_os_<module>` | `process_detected_host_os_hello_world` | `1.0.0`     |
+| Base API                         | API Format                                | Example (`hello_world` module)              | API Version |
+|----------------------------------|-------------------------------------------|---------------------------------------------|-------------|
+| `keyboard_pre_init`              | `keyboard_pre_init_<module>`              | `keyboard_pre_init_hello_world`             | `0.1.0`     |
+| `keyboard_post_init`             | `keyboard_post_init_<module>`             | `keyboard_post_init_hello_world`            | `0.1.0`     |
+| `pre_process_record`             | `pre_process_record_<module>`             | `pre_process_record_hello_world`            | `0.1.0`     |
+| `process_record`                 | `process_record_<module>`                 | `process_record_hello_world`                | `0.1.0`     |
+| `post_process_record`            | `post_process_record_<module>`            | `post_process_record_hello_world`           | `0.1.0`     |
+| `housekeeping_task`              | `housekeeping_task_<module>`              | `housekeeping_task_hello_world`             | `1.0.0`     |
+| `suspend_power_down`             | `suspend_power_down_<module>`             | `suspend_power_down_hello_world`            | `1.0.0`     |
+| `suspend_wakeup_init`            | `suspend_wakeup_init_<module>`            | `suspend_wakeup_init_hello_world`           | `1.0.0`     |
+| `shutdown`                       | `shutdown_<module>`                       | `shutdown_hello_world`                      | `1.0.0`     |
+| `process_detected_host_os`       | `process_detected_host_os_<module>`       | `process_detected_host_os_hello_world`      | `1.0.0`     |
+| `default_layer_state_set`        | `default_layer_state_set_<module>`        | `default_layer_state_set_hello_world`       | `1.1.0`     |
+| `layer_state_set`                | `layer_state_set_<module>`                | `layer_state_set_hello_world`               | `1.1.0`     |
+| `led_matrix_indicators`          | `led_matrix_indicators_<module>`          | `led_matrix_indicators_hello_word`          | `1.1.0`     |
+| `led_matrix_indicators_advanced` | `led_matrix_indicators_advanced_<module>` | `led_matrix_indicators_advanced_hello_word` | `1.1.0`     |
+| `rgb_matrix_indicators`          | `rgb_matrix_indicators_<module>`          | `rgb_matrix_indicators_hello_word`          | `1.1.0`     |
+| `rgb_matrix_indicators_advanced` | `rgb_matrix_indicators_advanced_<module>` | `rgb_matrix_indicators_advanced_hello_word` | `1.1.0`     |
+| `pointing_device_init`           | `pointing_device_init_<module>`           | `pointing_device_init_hello_word`           | `1.1.0`     |
+| `pointing_device_task`           | `pointing_device_task_<module>`           | `pointing_device_task_hello_word`           | `1.1.0`     |
+
 
 ::: info
 An unspecified API is disregarded if a Community Module does not provide a specialization for it.

+ 10 - 0
lib/python/qmk/cli/generate/community_modules.py

@@ -76,6 +76,8 @@ def _render_api_implementations(api, module):
         lines.append(f'__attribute__((weak)) {api.ret_type} {api.name}_{module_name}_user({api.args}) {{')
         if api.ret_type == 'bool':
             lines.append('    return true;')
+        elif api.ret_type in ['layer_state_t', 'report_mouse_t']:
+            lines.append(f'    return {api.call_params};')
         else:
             pass
         lines.append('}')
@@ -86,6 +88,8 @@ def _render_api_implementations(api, module):
         if api.ret_type == 'bool':
             lines.append(f'    if(!{api.name}_{module_name}_user({api.call_params})) {{ return false; }}')
             lines.append('    return true;')
+        elif api.ret_type in ['layer_state_t', 'report_mouse_t']:
+            lines.append(f'    return {api.name}_{module_name}_user({api.call_params});')
         else:
             lines.append(f'    {api.name}_{module_name}_user({api.call_params});')
         lines.append('}')
@@ -96,6 +100,8 @@ def _render_api_implementations(api, module):
         if api.ret_type == 'bool':
             lines.append(f'    if(!{api.name}_{module_name}_kb({api.call_params})) {{ return false; }}')
             lines.append('    return true;')
+        elif api.ret_type in ['layer_state_t', 'report_mouse_t']:
+            lines.append(f'    return {api.name}_{module_name}_kb({api.call_params});')
         else:
             lines.append(f'    {api.name}_{module_name}_kb({api.call_params});')
         lines.append('}')
@@ -113,10 +119,14 @@ def _render_core_implementation(api, modules):
             module_name = Path(module).name
             if api.ret_type == 'bool':
                 lines.append(f'        && {api.name}_{module_name}({api.call_params})')
+            elif api.ret_type in ['layer_state_t', 'report_mouse_t']:
+                lines.append(f'    {api.call_params} = {api.name}_{module_name}({api.call_params});')
             else:
                 lines.append(f'    {api.name}_{module_name}({api.call_params});')
         if api.ret_type == 'bool':
             lines.append('    ;')
+        elif api.ret_type in ['layer_state_t', 'report_mouse_t']:
+            lines.append(f'    return {api.call_params};')
         lines.append('}')
     return lines
 

+ 19 - 0
quantum/action_layer.c

@@ -27,11 +27,20 @@ __attribute__((weak)) layer_state_t default_layer_state_set_kb(layer_state_t sta
     return default_layer_state_set_user(state);
 }
 
+/** \brief Default Layer State Set At Module Level
+ *
+ * Run module code on default layer state change
+ */
+__attribute__((weak)) layer_state_t default_layer_state_set_modules(layer_state_t state) {
+    return state;
+}
+
 /** \brief Default Layer State Set
  *
  * Static function to set the default layer state, prints debug info and clears keys
  */
 static void default_layer_state_set(layer_state_t state) {
+    state = default_layer_state_set_modules(state);
     state = default_layer_state_set_kb(state);
     ac_dprintf("default_layer_state: ");
     default_layer_debug();
@@ -107,11 +116,21 @@ __attribute__((weak)) layer_state_t layer_state_set_kb(layer_state_t state) {
     return layer_state_set_user(state);
 }
 
+/** \brief Layer state set modules
+ *
+ * Runs module code on layer state change
+ */
+
+__attribute__((weak)) layer_state_t layer_state_set_modules(layer_state_t state) {
+    return state;
+}
+
 /** \brief Layer state set
  *
  * Sets the layer to match the specified state (a bitmask)
  */
 void layer_state_set(layer_state_t state) {
+    state = layer_state_set_modules(state);
     state = layer_state_set_kb(state);
     ac_dprintf("layer_state: ");
     layer_debug();

+ 3 - 0
quantum/action_layer.h

@@ -78,6 +78,7 @@ extern layer_state_t default_layer_state;
 void                 default_layer_debug(void);
 void                 default_layer_set(layer_state_t state);
 
+__attribute__((weak)) layer_state_t default_layer_state_set_modules(layer_state_t state);
 __attribute__((weak)) layer_state_t default_layer_state_set_kb(layer_state_t state);
 __attribute__((weak)) layer_state_t default_layer_state_set_user(layer_state_t state);
 
@@ -114,6 +115,7 @@ void          layer_and(layer_state_t state);
 void          layer_xor(layer_state_t state);
 layer_state_t layer_state_set_user(layer_state_t state);
 layer_state_t layer_state_set_kb(layer_state_t state);
+layer_state_t layer_state_set_modules(layer_state_t state);
 
 /**
  * @brief Applies the tri layer to global layer state. Not be used in layer_state_set_(kb|user) functions.
@@ -149,6 +151,7 @@ layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_
 #    define layer_or(state) (void)state
 #    define layer_and(state) (void)state
 #    define layer_xor(state) (void)state
+#    define layer_state_set_modules(state) (void)state
 #    define layer_state_set_kb(state) (void)state
 #    define layer_state_set_user(state) (void)state
 #    define update_tri_layer(layer1, layer2, layer3)

+ 10 - 0
quantum/led_matrix/led_matrix.c

@@ -358,7 +358,12 @@ void led_matrix_task(void) {
     }
 }
 
+__attribute__((weak)) bool led_matrix_indicators_modules(void) {
+    return true;
+}
+
 void led_matrix_indicators(void) {
+    led_matrix_indicators_modules();
     led_matrix_indicators_kb();
 }
 
@@ -370,6 +375,10 @@ __attribute__((weak)) bool led_matrix_indicators_user(void) {
     return true;
 }
 
+__attribute__((weak)) bool led_matrix_indicators_advanced_modules(uint8_t led_min, uint8_t led_max) {
+    return true;
+}
+
 void led_matrix_indicators_advanced(effect_params_t *params) {
     /* special handling is needed for "params->iter", since it's already been incremented.
      * Could move the invocations to led_task_render, but then it's missing a few checks
@@ -377,6 +386,7 @@ void led_matrix_indicators_advanced(effect_params_t *params) {
      * led_task_render, right before the iter++ line.
      */
     LED_MATRIX_USE_LIMITS_ITER(min, max, params->iter - 1);
+    led_matrix_indicators_advanced_modules(min, max);
     led_matrix_indicators_advanced_kb(min, max);
 }
 

+ 8 - 1
quantum/pointing_device/pointing_device.c

@@ -109,6 +109,11 @@ const pointing_device_driver_t custom_pointing_device_driver = {
 
 const pointing_device_driver_t *pointing_device_driver = &POINTING_DEVICE_DRIVER(POINTING_DEVICE_DRIVER_NAME);
 
+__attribute__((weak)) void           pointing_device_init_modules(void) {}
+__attribute__((weak)) report_mouse_t pointing_device_task_modules(report_mouse_t mouse_report) {
+    return mouse_report;
+}
+
 /**
  * @brief Keyboard level code pointing device initialisation
  *
@@ -190,6 +195,7 @@ __attribute__((weak)) void pointing_device_init(void) {
     }
 #endif
 
+    pointing_device_init_modules();
     pointing_device_init_kb();
     pointing_device_init_user();
 }
@@ -319,8 +325,9 @@ __attribute__((weak)) bool pointing_device_task(void) {
     local_mouse_report = is_keyboard_left() ? pointing_device_task_combined_kb(local_mouse_report, shared_mouse_report) : pointing_device_task_combined_kb(shared_mouse_report, local_mouse_report);
 #else
     local_mouse_report = pointing_device_adjust_by_defines(local_mouse_report);
-    local_mouse_report = pointing_device_task_kb(local_mouse_report);
 #endif
+    local_mouse_report = pointing_device_task_modules(local_mouse_report);
+    local_mouse_report = pointing_device_task_kb(local_mouse_report);
     // automatic mouse layer function
 #ifdef POINTING_DEVICE_AUTO_MOUSE_ENABLE
     pointing_device_task_auto_mouse(local_mouse_report);

+ 1 - 0
quantum/pointing_device/pointing_device.h

@@ -17,6 +17,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 #pragma once
 
+#include <stdbool.h>
 #include <stdint.h>
 #include "host.h"
 #include "report.h"

+ 10 - 0
quantum/rgb_matrix/rgb_matrix.c

@@ -393,7 +393,12 @@ void rgb_matrix_task(void) {
     }
 }
 
+__attribute__((weak)) bool rgb_matrix_indicators_modules(void) {
+    return true;
+}
+
 void rgb_matrix_indicators(void) {
+    rgb_matrix_indicators_modules();
     rgb_matrix_indicators_kb();
 }
 
@@ -433,6 +438,10 @@ struct rgb_matrix_limits_t rgb_matrix_get_limits(uint8_t iter) {
     return limits;
 }
 
+__attribute__((weak)) bool rgb_matrix_indicators_advanced_modules(uint8_t led_min, uint8_t led_max) {
+    return true;
+}
+
 void rgb_matrix_indicators_advanced(effect_params_t *params) {
     /* special handling is needed for "params->iter", since it's already been incremented.
      * Could move the invocations to rgb_task_render, but then it's missing a few checks
@@ -440,6 +449,7 @@ void rgb_matrix_indicators_advanced(effect_params_t *params) {
      * rgb_task_render, right before the iter++ line.
      */
     RGB_MATRIX_USE_LIMITS_ITER(min, max, params->iter - 1);
+    rgb_matrix_indicators_advanced_modules(min, max);
     rgb_matrix_indicators_advanced_kb(min, max);
 }