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
When using analog
with ARM, you must use 3.3v with your Joystick. Although ARM boards such as the Helios have 5v pin output, the ADC driver does not support it.
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