import { _ as _export_sfc, c as createElementBlock, o as openBlock, a8 as createStaticVNode } from "./chunks/framework.DyMmIvSC.js"; const __pageData = JSON.parse('{"title":"Joystick","description":"","frontmatter":{},"headers":[],"relativePath":"features/joystick.md","filePath":"features/joystick.md"}'); const _sfc_main = { name: "features/joystick.md" }; const _hoisted_1 = /* @__PURE__ */ createStaticVNode('
This feature provides game controller input as a joystick device supporting up to 6 axes and 32 buttons. Axes can be read either from an ADC-capable input pin, or can be virtual, so that its value is provided by your code.
An analog device such as a potentiometer found on an analog joystick's axes is based on a voltage divider, where adjusting the movable wiper controls the output voltage which can then be read by the microcontroller's ADC.
Add the following to your rules.mk
:
JOYSTICK_ENABLE = yes
By default the joystick driver is analog
, but you can change this with:
JOYSTICK_DRIVER = digital
By default, two axes and eight buttons are defined, with a reported resolution of 8 bits (-127 to +127). This can be changed in your config.h
:
// Min 0, max 32\n#define JOYSTICK_BUTTON_COUNT 16\n// Min 0, max 6: X, Y, Z, Rx, Ry, Rz\n#define JOYSTICK_AXIS_COUNT 3\n// Min 8, max 16\n#define JOYSTICK_AXIS_RESOLUTION 10
TIP
You must define at least one button or axis. Also note that the maximum ADC resolution of the supported AVR MCUs is 10-bit, and 12-bit for most STM32 MCUs.
When defining axes for your joystick, you must provide a definition array typically in your keymap.c
.
For instance, the below example configures two axes. The X axis is read from the A4
pin. With the default axis resolution of 8 bits, the range of values between 900 and 575 are scaled to -127 through 0, and values 575 to 285 are scaled to 0 through 127. The Y axis is configured as a virtual axis, and its value is not read from any pin. Instead, the user must update the axis value programmatically.
joystick_config_t joystick_axes[JOYSTICK_AXIS_COUNT] = {\n JOYSTICK_AXIS_IN(A4, 900, 575, 285),\n JOYSTICK_AXIS_VIRTUAL\n};
Axes can be configured using one of the following macros:
JOYSTICK_AXIS_IN(input_pin, low, rest, high)
low
, high
and rest
correspond to the minimum, maximum, and resting (or centered) analog values of the axis, respectively.JOYSTICK_AXIS_VIRTUAL
The low
and high
values can be swapped to effectively invert the axis.
The following example adjusts two virtual axes (X and Y) based on keypad presses, with KC_P0
as a precision modifier:
joystick_config_t joystick_axes[JOYSTICK_AXIS_COUNT] = {\n JOYSTICK_AXIS_VIRTUAL, // x\n JOYSTICK_AXIS_VIRTUAL // y\n};\n\nstatic bool precision = false;\nstatic uint16_t precision_mod = 64;\nstatic uint16_t axis_val = 127;\n\nbool process_record_user(uint16_t keycode, keyrecord_t *record) {\n int16_t precision_val = axis_val;\n if (precision) {\n precision_val -= precision_mod;\n }\n\n switch (keycode) {\n case KC_P8:\n joystick_set_axis(1, record->event.pressed ? -precision_val : 0);\n return false;\n case KC_P2:\n joystick_set_axis(1, record->event.pressed ? precision_val : 0);\n return false;\n case KC_P4:\n joystick_set_axis(0, record->event.pressed ? -precision_val : 0);\n return false;\n case KC_P6:\n joystick_set_axis(0, record->event.pressed ? precision_val : 0);\n return false;\n case KC_P0:\n precision = record->event.pressed;\n return false;\n }\n return true;\n}
Key | Aliases | Description |
---|---|---|
QK_JOYSTICK_BUTTON_0 | JS_0 | Button 0 |
QK_JOYSTICK_BUTTON_1 | JS_1 | Button 1 |
QK_JOYSTICK_BUTTON_2 | JS_2 | Button 2 |
QK_JOYSTICK_BUTTON_3 | JS_3 | Button 3 |
QK_JOYSTICK_BUTTON_4 | JS_4 | Button 4 |
QK_JOYSTICK_BUTTON_5 | JS_5 | Button 5 |
QK_JOYSTICK_BUTTON_6 | JS_6 | Button 6 |
QK_JOYSTICK_BUTTON_7 | JS_7 | Button 7 |
QK_JOYSTICK_BUTTON_8 | JS_8 | Button 8 |
QK_JOYSTICK_BUTTON_9 | JS_9 | Button 9 |
QK_JOYSTICK_BUTTON_10 | JS_10 | Button 10 |
QK_JOYSTICK_BUTTON_11 | JS_11 | Button 11 |
QK_JOYSTICK_BUTTON_12 | JS_12 | Button 12 |
QK_JOYSTICK_BUTTON_13 | JS_13 | Button 13 |
QK_JOYSTICK_BUTTON_14 | JS_14 | Button 14 |
QK_JOYSTICK_BUTTON_15 | JS_15 | Button 15 |
QK_JOYSTICK_BUTTON_16 | JS_16 | Button 16 |
QK_JOYSTICK_BUTTON_17 | JS_17 | Button 17 |
QK_JOYSTICK_BUTTON_18 | JS_18 | Button 18 |
QK_JOYSTICK_BUTTON_19 | JS_19 | Button 19 |
QK_JOYSTICK_BUTTON_20 | JS_20 | Button 20 |
QK_JOYSTICK_BUTTON_21 | JS_21 | Button 21 |
QK_JOYSTICK_BUTTON_22 | JS_22 | Button 22 |
QK_JOYSTICK_BUTTON_23 | JS_23 | Button 23 |
QK_JOYSTICK_BUTTON_24 | JS_24 | Button 24 |
QK_JOYSTICK_BUTTON_25 | JS_25 | Button 25 |
QK_JOYSTICK_BUTTON_26 | JS_26 | Button 26 |
QK_JOYSTICK_BUTTON_27 | JS_27 | Button 27 |
QK_JOYSTICK_BUTTON_28 | JS_28 | Button 28 |
QK_JOYSTICK_BUTTON_29 | JS_29 | Button 29 |
QK_JOYSTICK_BUTTON_30 | JS_30 | Button 30 |
QK_JOYSTICK_BUTTON_31 | JS_31 | Button 31 |
struct joystick_t
Contains the state of the joystick.
uint8_t buttons[]
(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1
.int16_t axes[]
bool dirty
struct joystick_config_t
Describes a single axis.
pin_t input_pin
JS_VIRTUAL_AXIS
.uint16_t min_digit
uint16_t mid_digit
uint16_t max_digit
void joystick_flush(void)
Send the joystick report to the host, if it has been marked as dirty.
void register_joystick_button(uint8_t button)
Set the state of a button, and flush the report.
uint8_t button
void unregister_joystick_button(uint8_t button)
Reset the state of a button, and flush the report.
uint8_t button
int16_t joystick_read_axis(uint8_t axis)
Sample and process the analog value of the given axis.
uint8_t axis
A signed 16-bit integer, where 0 is the resting or mid point.
void joystick_set_axis(uint8_t axis, int16_t value)
Set the value of the given axis.
uint8_t axis
int16_t value