keyboard stuff
1# Joystick {#joystick}
2
3This 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
5An 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
9Add the following to your `rules.mk`:
10
11```make
12JOYSTICK_ENABLE = yes
13```
14
15By default the joystick driver is `analog`, but you can change this with:
16
17```make
18JOYSTICK_DRIVER = digital
19```
20
21When 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
25By 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
37You 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
42To enable the 8-way hat switch, add the following to your `config.h`:
43
44```c
45#define JOYSTICK_HAS_HAT
46````
47
48The 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 / \
556 W | -1 | E 2
56 \ /
57 SW '--.--' SE
58 5 S 3
59 4
60```
61
62Alternatively 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
78When defining axes for your joystick, you must provide a definition array typically in your `keymap.c`.
79
80For 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
83joystick_config_t joystick_axes[JOYSTICK_AXIS_COUNT] = {
84 JOYSTICK_AXIS_IN(A4, 900, 575, 285),
85 JOYSTICK_AXIS_VIRTUAL
86};
87```
88
89Axes 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
96The `low` and `high` values can be swapped to effectively invert the axis.
97
98#### Virtual Axes {#virtual-axes}
99
100The following example adjusts two virtual axes (X and Y) based on keypad presses, with `KC_P0` as a precision modifier:
101
102```c
103joystick_config_t joystick_axes[JOYSTICK_AXIS_COUNT] = {
104 JOYSTICK_AXIS_VIRTUAL, // x
105 JOYSTICK_AXIS_VIRTUAL // y
106};
107
108static bool precision = false;
109static uint16_t precision_mod = 64;
110static uint16_t axis_val = 127;
111
112bool 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
180Contains 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
197Describes 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
214Send 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
220Set 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
231Reset 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
242Sample 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
251A 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
255Set 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
268Set 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.