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
#define JOYSTICK_BUTTON_COUNT 16
// Min 0, max 6: X, Y, Z, Rx, Ry, Rz
#define JOYSTICK_AXIS_COUNT 3
// Min 8, max 16
#define JOYSTICK_AXIS_RESOLUTION 10
?> 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] = {
    JOYSTICK_AXIS_IN(A4, 900, 575, 285),
    JOYSTICK_AXIS_VIRTUAL
};
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_IN_OUT(input_pin, output_pin, low, rest, high)JOYSTICK_AXIS_IN(), but the provided output_pin will be pulled high before input_pin is read.JOYSTICK_AXIS_IN_OUT_GROUND(input_pin, output_pin, ground_pin, low, rest, high)JOYSTICK_AXIS_IN_OUT(), but the provided ground_pin will be pulled low before reading from input_pin.JOYSTICK_AXIS_VIRTUALThe 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] = {
    JOYSTICK_AXIS_VIRTUAL, // x
    JOYSTICK_AXIS_VIRTUAL  // y
};
static bool precision = false;
static uint16_t precision_mod = 64;
static uint16_t axis_val = 127;
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    int16_t precision_val = axis_val;
    if (precision) {
        precision_val -= precision_mod;
    }
    switch (keycode) {
        case KC_P8:
            joystick_set_axis(1, record->event.pressed ? -precision_val : 0);
            return false;
        case KC_P2:
            joystick_set_axis(1, record->event.pressed ? precision_val : 0);
            return false;
        case KC_P4:
            joystick_set_axis(0, record->event.pressed ? -precision_val : 0);
            return false;
        case KC_P6:
            joystick_set_axis(0, record->event.pressed ? precision_val : 0);
            return false;
        case KC_P0:
            precision = record->event.pressed;
            return false;
    }
    return true;
}
| 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 :id=api-joystick-tContains the state of the joystick.
uint8_t buttons[](JOYSTICK_BUTTON_COUNT - 1) / 8 + 1.int16_t axes[]bool dirtystruct joystick_config_t :id=api-joystick-config-tDescribes a single axis.
pin_t output_pinJS_VIRTUAL_AXIS.pin_t input_pinJS_VIRTUAL_AXIS.pin_t ground_pinJS_VIRTUAL_AXIS.uint16_t min_digituint16_t mid_digituint16_t max_digitvoid joystick_flush(void) :id=api-joystick-flushSend the joystick report to the host, if it has been marked as dirty.
void register_joystick_button(uint8_t button) :id=api-register-joystick-buttonSet the state of a button, and flush the report.
uint8_t buttonvoid unregister_joystick_button(uint8_t button) :id=api-unregister-joystick-buttonReset the state of a button, and flush the report.
uint8_t buttonint16_t joystick_read_axis(uint8_t axis) :id=api-joystick-read-axisSample and process the analog value of the given axis.
uint8_t axisA signed 16-bit integer, where 0 is the resting or mid point.
void joystick_set_axis(uint8_t axis, int16_t value) :id=api-joystick-set-axisSet the value of the given axis.
uint8_t axisint16_t value