joystick.md (8785B)
1 # Joystick {#joystick} 2 3 This feature provides game controller input as a joystick device supporting up to 6 axes, 32 buttons and a hat switch. Axes can be read either from an [ADC-capable input pin](../drivers/adc), or can be virtual, so that its value is provided by your code. 4 5 An analog device such as a [potentiometer](https://en.wikipedia.org/wiki/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. 6 7 ## Usage {#usage} 8 9 Add the following to your `rules.mk`: 10 11 ```make 12 JOYSTICK_ENABLE = yes 13 ``` 14 15 By default the joystick driver is `analog`, but you can change this with: 16 17 ```make 18 JOYSTICK_DRIVER = digital 19 ``` 20 21 When using `analog` with ARM, [you must use 3.3v with your Joystick](../drivers/adc). Although ARM boards such as the [Helios](https://keeb.supply/products/0xcb-helios) have 5v pin output, the ADC driver does not support it. 22 23 ## Configuration {#configuration} 24 25 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`: 26 27 ```c 28 // Min 0, max 32 29 #define JOYSTICK_BUTTON_COUNT 16 30 // Min 0, max 6: X, Y, Z, Rx, Ry, Rz 31 #define JOYSTICK_AXIS_COUNT 3 32 // Min 8, max 16 33 #define JOYSTICK_AXIS_RESOLUTION 10 34 ``` 35 36 ::: tip 37 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. 38 ::: 39 40 ### Hat Switch {#hat-switch} 41 42 To enable the 8-way hat switch, add the following to your `config.h`: 43 44 ```c 45 #define JOYSTICK_HAS_HAT 46 ```` 47 48 The position can be set by calling `joystick_set_hat(value)`. The range of values moves clockwise from the top (ie. north), with the default "center" position represented by a value of `-1`: 49 50 ``` 51 0 52 7 N 1 53 NW .--'--. NE 54 / \ 55 6 W | -1 | E 2 56 \ / 57 SW '--.--' SE 58 5 S 3 59 4 60 ``` 61 62 Alternatively you can use these predefined names: 63 64 |Define |Value|Angle| 65 |------------------------|-----|-----| 66 |`JOYSTICK_HAT_CENTER` |`-1` | | 67 |`JOYSTICK_HAT_NORTH` |`0` |0° | 68 |`JOYSTICK_HAT_NORTHEAST`|`1` |45° | 69 |`JOYSTICK_HAT_EAST` |`2` |90° | 70 |`JOYSTICK_HAT_SOUTHEAST`|`3` |135° | 71 |`JOYSTICK_HAT_SOUTH` |`4` |180° | 72 |`JOYSTICK_HAT_SOUTHWEST`|`5` |225° | 73 |`JOYSTICK_HAT_WEST` |`6` |270° | 74 |`JOYSTICK_HAT_NORTHWEST`|`7` |315° | 75 76 ### Axes {#axes} 77 78 When defining axes for your joystick, you must provide a definition array typically in your `keymap.c`. 79 80 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. 81 82 ```c 83 joystick_config_t joystick_axes[JOYSTICK_AXIS_COUNT] = { 84 JOYSTICK_AXIS_IN(A4, 900, 575, 285), 85 JOYSTICK_AXIS_VIRTUAL 86 }; 87 ``` 88 89 Axes can be configured using one of the following macros: 90 91 * `JOYSTICK_AXIS_IN(input_pin, low, rest, high)` 92 The ADC samples the provided pin. `low`, `high` and `rest` correspond to the minimum, maximum, and resting (or centered) analog values of the axis, respectively. 93 * `JOYSTICK_AXIS_VIRTUAL` 94 No ADC reading is performed. The value should be provided by user code. 95 96 The `low` and `high` values can be swapped to effectively invert the axis. 97 98 #### Virtual Axes {#virtual-axes} 99 100 The following example adjusts two virtual axes (X and Y) based on keypad presses, with `KC_P0` as a precision modifier: 101 102 ```c 103 joystick_config_t joystick_axes[JOYSTICK_AXIS_COUNT] = { 104 JOYSTICK_AXIS_VIRTUAL, // x 105 JOYSTICK_AXIS_VIRTUAL // y 106 }; 107 108 static bool precision = false; 109 static uint16_t precision_mod = 64; 110 static uint16_t axis_val = 127; 111 112 bool process_record_user(uint16_t keycode, keyrecord_t *record) { 113 int16_t precision_val = axis_val; 114 if (precision) { 115 precision_val -= precision_mod; 116 } 117 118 switch (keycode) { 119 case KC_P8: 120 joystick_set_axis(1, record->event.pressed ? -precision_val : 0); 121 return false; 122 case KC_P2: 123 joystick_set_axis(1, record->event.pressed ? precision_val : 0); 124 return false; 125 case KC_P4: 126 joystick_set_axis(0, record->event.pressed ? -precision_val : 0); 127 return false; 128 case KC_P6: 129 joystick_set_axis(0, record->event.pressed ? precision_val : 0); 130 return false; 131 case KC_P0: 132 precision = record->event.pressed; 133 return false; 134 } 135 return true; 136 } 137 ``` 138 139 ## Keycodes {#keycodes} 140 141 |Key |Aliases|Description| 142 |-----------------------|-------|-----------| 143 |`QK_JOYSTICK_BUTTON_0` |`JS_0` |Button 0 | 144 |`QK_JOYSTICK_BUTTON_1` |`JS_1` |Button 1 | 145 |`QK_JOYSTICK_BUTTON_2` |`JS_2` |Button 2 | 146 |`QK_JOYSTICK_BUTTON_3` |`JS_3` |Button 3 | 147 |`QK_JOYSTICK_BUTTON_4` |`JS_4` |Button 4 | 148 |`QK_JOYSTICK_BUTTON_5` |`JS_5` |Button 5 | 149 |`QK_JOYSTICK_BUTTON_6` |`JS_6` |Button 6 | 150 |`QK_JOYSTICK_BUTTON_7` |`JS_7` |Button 7 | 151 |`QK_JOYSTICK_BUTTON_8` |`JS_8` |Button 8 | 152 |`QK_JOYSTICK_BUTTON_9` |`JS_9` |Button 9 | 153 |`QK_JOYSTICK_BUTTON_10`|`JS_10`|Button 10 | 154 |`QK_JOYSTICK_BUTTON_11`|`JS_11`|Button 11 | 155 |`QK_JOYSTICK_BUTTON_12`|`JS_12`|Button 12 | 156 |`QK_JOYSTICK_BUTTON_13`|`JS_13`|Button 13 | 157 |`QK_JOYSTICK_BUTTON_14`|`JS_14`|Button 14 | 158 |`QK_JOYSTICK_BUTTON_15`|`JS_15`|Button 15 | 159 |`QK_JOYSTICK_BUTTON_16`|`JS_16`|Button 16 | 160 |`QK_JOYSTICK_BUTTON_17`|`JS_17`|Button 17 | 161 |`QK_JOYSTICK_BUTTON_18`|`JS_18`|Button 18 | 162 |`QK_JOYSTICK_BUTTON_19`|`JS_19`|Button 19 | 163 |`QK_JOYSTICK_BUTTON_20`|`JS_20`|Button 20 | 164 |`QK_JOYSTICK_BUTTON_21`|`JS_21`|Button 21 | 165 |`QK_JOYSTICK_BUTTON_22`|`JS_22`|Button 22 | 166 |`QK_JOYSTICK_BUTTON_23`|`JS_23`|Button 23 | 167 |`QK_JOYSTICK_BUTTON_24`|`JS_24`|Button 24 | 168 |`QK_JOYSTICK_BUTTON_25`|`JS_25`|Button 25 | 169 |`QK_JOYSTICK_BUTTON_26`|`JS_26`|Button 26 | 170 |`QK_JOYSTICK_BUTTON_27`|`JS_27`|Button 27 | 171 |`QK_JOYSTICK_BUTTON_28`|`JS_28`|Button 28 | 172 |`QK_JOYSTICK_BUTTON_29`|`JS_29`|Button 29 | 173 |`QK_JOYSTICK_BUTTON_30`|`JS_30`|Button 30 | 174 |`QK_JOYSTICK_BUTTON_31`|`JS_31`|Button 31 | 175 176 ## API {#api} 177 178 ### `struct joystick_t` {#api-joystick-t} 179 180 Contains the state of the joystick. 181 182 #### Members {#api-joystick-t-members} 183 184 - `uint8_t buttons[]` 185 A bit-packed array containing the joystick button states. The size is calculated as `(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1`. 186 - `int16_t axes[]` 187 An array of analog values for each defined axis. 188 - `int8_t hat` 189 The hat switch position. 190 - `bool dirty` 191 Whether the current state needs to be sent to the host. 192 193 --- 194 195 ### `struct joystick_config_t` {#api-joystick-config-t} 196 197 Describes a single axis. 198 199 #### Members {#api-joystick-config-t-members} 200 201 - `pin_t input_pin` 202 The pin to read the analog value from, or `JS_VIRTUAL_AXIS`. 203 - `uint16_t min_digit` 204 The minimum analog value. 205 - `uint16_t mid_digit` 206 The resting or midpoint analog value. 207 - `uint16_t max_digit` 208 The maximum analog value. 209 210 --- 211 212 ### `void joystick_flush(void)` {#api-joystick-flush} 213 214 Send the joystick report to the host, if it has been marked as dirty. 215 216 --- 217 218 ### `void register_joystick_button(uint8_t button)` {#api-register-joystick-button} 219 220 Set the state of a button, and flush the report. 221 222 #### Arguments {#api-register-joystick-button-arguments} 223 224 - `uint8_t button` 225 The index of the button to press, from 0 to 31. 226 227 --- 228 229 ### `void unregister_joystick_button(uint8_t button)` {#api-unregister-joystick-button} 230 231 Reset the state of a button, and flush the report. 232 233 #### Arguments {#api-unregister-joystick-button-arguments} 234 235 - `uint8_t button` 236 The index of the button to release, from 0 to 31. 237 238 --- 239 240 ### `int16_t joystick_read_axis(uint8_t axis)` {#api-joystick-read-axis} 241 242 Sample and process the analog value of the given axis. 243 244 #### Arguments {#api-joystick-read-axis-arguments} 245 246 - `uint8_t axis` 247 The axis to read. 248 249 #### Return Value {#api-joystick-read-axis-return} 250 251 A signed 16-bit integer, where 0 is the resting or mid point. 252 253 ### `void joystick_set_axis(uint8_t axis, int16_t value)` {#api-joystick-set-axis} 254 255 Set the value of the given axis. 256 257 #### Arguments {#api-joystick-set-axis-arguments} 258 259 - `uint8_t axis` 260 The axis to set the value of. 261 - `int16_t value` 262 The value to set. 263 264 --- 265 266 ### `void joystick_set_hat(int8_t value)` {#api-joystick-set-hat} 267 268 Set the position of the hat switch. 269 270 #### Arguments {#api-joystick-set-hat-arguments} 271 272 - `int8_t value` 273 The hat switch position to set.