Joystick: add support for 8-way hat switch (#24515)
This commit is contained in:
parent
69093f6de9
commit
a3cfb1dab7
@ -1,6 +1,6 @@
|
|||||||
# Joystick {#joystick}
|
# Joystick {#joystick}
|
||||||
|
|
||||||
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](../drivers/adc), or can be virtual, so that its value is provided by your code.
|
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.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
@ -37,6 +37,42 @@ By default, two axes and eight buttons are defined, with a reported resolution o
|
|||||||
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.
|
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.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
### Hat Switch {#hat-switch}
|
||||||
|
|
||||||
|
To enable the 8-way hat switch, add the following to your `config.h`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define JOYSTICK_HAS_HAT
|
||||||
|
````
|
||||||
|
|
||||||
|
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`:
|
||||||
|
|
||||||
|
```
|
||||||
|
0
|
||||||
|
7 N 1
|
||||||
|
NW .--'--. NE
|
||||||
|
/ \
|
||||||
|
6 W | -1 | E 2
|
||||||
|
\ /
|
||||||
|
SW '--.--' SE
|
||||||
|
5 S 3
|
||||||
|
4
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively you can use these predefined names:
|
||||||
|
|
||||||
|
|Define |Value|Angle|
|
||||||
|
|------------------------|-----|-----|
|
||||||
|
|`JOYSTICK_HAT_CENTER` |`-1` | |
|
||||||
|
|`JOYSTICK_HAT_NORTH` |`0` |0° |
|
||||||
|
|`JOYSTICK_HAT_NORTHEAST`|`1` |45° |
|
||||||
|
|`JOYSTICK_HAT_EAST` |`2` |90° |
|
||||||
|
|`JOYSTICK_HAT_SOUTHEAST`|`3` |135° |
|
||||||
|
|`JOYSTICK_HAT_SOUTH` |`4` |180° |
|
||||||
|
|`JOYSTICK_HAT_SOUTHWEST`|`5` |225° |
|
||||||
|
|`JOYSTICK_HAT_WEST` |`6` |270° |
|
||||||
|
|`JOYSTICK_HAT_NORTHWEST`|`7` |315° |
|
||||||
|
|
||||||
### Axes {#axes}
|
### Axes {#axes}
|
||||||
|
|
||||||
When defining axes for your joystick, you must provide a definition array typically in your `keymap.c`.
|
When defining axes for your joystick, you must provide a definition array typically in your `keymap.c`.
|
||||||
@ -149,6 +185,8 @@ Contains the state of the joystick.
|
|||||||
A bit-packed array containing the joystick button states. The size is calculated as `(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1`.
|
A bit-packed array containing the joystick button states. The size is calculated as `(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1`.
|
||||||
- `int16_t axes[]`
|
- `int16_t axes[]`
|
||||||
An array of analog values for each defined axis.
|
An array of analog values for each defined axis.
|
||||||
|
- `int8_t hat`
|
||||||
|
The hat switch position.
|
||||||
- `bool dirty`
|
- `bool dirty`
|
||||||
Whether the current state needs to be sent to the host.
|
Whether the current state needs to be sent to the host.
|
||||||
|
|
||||||
@ -222,3 +260,14 @@ Set the value of the given axis.
|
|||||||
The axis to set the value of.
|
The axis to set the value of.
|
||||||
- `int16_t value`
|
- `int16_t value`
|
||||||
The value to set.
|
The value to set.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `void joystick_set_hat(int8_t value)` {#api-joystick-set-hat}
|
||||||
|
|
||||||
|
Set the position of the hat switch.
|
||||||
|
|
||||||
|
#### Arguments {#api-joystick-set-hat-arguments}
|
||||||
|
|
||||||
|
- `int8_t value`
|
||||||
|
The hat switch position to set.
|
||||||
|
@ -29,6 +29,9 @@ joystick_t joystick_state = {
|
|||||||
0
|
0
|
||||||
#endif
|
#endif
|
||||||
},
|
},
|
||||||
|
#ifdef JOYSTICK_HAS_HAT
|
||||||
|
.hat = -1,
|
||||||
|
#endif
|
||||||
.dirty = false,
|
.dirty = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -145,6 +148,13 @@ void joystick_set_axis(uint8_t axis, int16_t value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef JOYSTICK_HAS_HAT
|
||||||
|
void joystick_set_hat(int8_t value) {
|
||||||
|
joystick_state.hat = value;
|
||||||
|
joystick_state.dirty = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void joystick_init(void) {
|
void joystick_init(void) {
|
||||||
joystick_init_axes();
|
joystick_init_axes();
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,16 @@
|
|||||||
|
|
||||||
#define JOYSTICK_MAX_VALUE ((1L << (JOYSTICK_AXIS_RESOLUTION - 1)) - 1)
|
#define JOYSTICK_MAX_VALUE ((1L << (JOYSTICK_AXIS_RESOLUTION - 1)) - 1)
|
||||||
|
|
||||||
|
#define JOYSTICK_HAT_CENTER -1
|
||||||
|
#define JOYSTICK_HAT_NORTH 0
|
||||||
|
#define JOYSTICK_HAT_NORTHEAST 1
|
||||||
|
#define JOYSTICK_HAT_EAST 2
|
||||||
|
#define JOYSTICK_HAT_SOUTHEAST 3
|
||||||
|
#define JOYSTICK_HAT_SOUTH 4
|
||||||
|
#define JOYSTICK_HAT_SOUTHWEST 5
|
||||||
|
#define JOYSTICK_HAT_WEST 6
|
||||||
|
#define JOYSTICK_HAT_NORTHWEST 7
|
||||||
|
|
||||||
// configure on input_pin of the joystick_axes array entry to NO_PIN
|
// configure on input_pin of the joystick_axes array entry to NO_PIN
|
||||||
// to prevent it from being read from the ADC. This allows outputting forged axis value.
|
// to prevent it from being read from the ADC. This allows outputting forged axis value.
|
||||||
#define JOYSTICK_AXIS_VIRTUAL \
|
#define JOYSTICK_AXIS_VIRTUAL \
|
||||||
@ -73,7 +83,10 @@ extern joystick_config_t joystick_axes[JOYSTICK_AXIS_COUNT];
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t buttons[(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1];
|
uint8_t buttons[(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1];
|
||||||
int16_t axes[JOYSTICK_AXIS_COUNT];
|
int16_t axes[JOYSTICK_AXIS_COUNT];
|
||||||
bool dirty;
|
#ifdef JOYSTICK_HAS_HAT
|
||||||
|
int8_t hat;
|
||||||
|
#endif
|
||||||
|
bool dirty;
|
||||||
} joystick_t;
|
} joystick_t;
|
||||||
|
|
||||||
extern joystick_t joystick_state;
|
extern joystick_t joystick_state;
|
||||||
@ -129,4 +142,11 @@ void joystick_read_axes(void);
|
|||||||
*/
|
*/
|
||||||
void joystick_set_axis(uint8_t axis, int16_t value);
|
void joystick_set_axis(uint8_t axis, int16_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the position of the hat switch.
|
||||||
|
*
|
||||||
|
* \param value The hat switch position to set.
|
||||||
|
*/
|
||||||
|
void joystick_set_hat(int8_t value);
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
@ -193,6 +193,10 @@ void host_joystick_send(joystick_t *joystick) {
|
|||||||
},
|
},
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
# ifdef JOYSTICK_HAS_HAT
|
||||||
|
.hat = joystick->hat,
|
||||||
|
# endif
|
||||||
|
|
||||||
# if JOYSTICK_BUTTON_COUNT > 0
|
# if JOYSTICK_BUTTON_COUNT > 0
|
||||||
.buttons =
|
.buttons =
|
||||||
{
|
{
|
||||||
|
@ -246,6 +246,11 @@ typedef struct {
|
|||||||
joystick_axis_t axes[JOYSTICK_AXIS_COUNT];
|
joystick_axis_t axes[JOYSTICK_AXIS_COUNT];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOYSTICK_HAS_HAT
|
||||||
|
int8_t hat : 4;
|
||||||
|
uint8_t reserved : 4;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if JOYSTICK_BUTTON_COUNT > 0
|
#if JOYSTICK_BUTTON_COUNT > 0
|
||||||
uint8_t buttons[(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1];
|
uint8_t buttons[(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1];
|
||||||
#endif
|
#endif
|
||||||
|
@ -247,6 +247,23 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
|
|||||||
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
|
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
# ifdef JOYSTICK_HAS_HAT
|
||||||
|
// Hat Switch (4 bits)
|
||||||
|
HID_RI_USAGE(8, 0x39), // Hat Switch
|
||||||
|
HID_RI_LOGICAL_MINIMUM(8, 0x00),
|
||||||
|
HID_RI_LOGICAL_MAXIMUM(8, 0x07),
|
||||||
|
HID_RI_PHYSICAL_MINIMUM(8, 0),
|
||||||
|
HID_RI_PHYSICAL_MAXIMUM(16, 315),
|
||||||
|
HID_RI_UNIT(8, 0x14), // Degree, English Rotation
|
||||||
|
HID_RI_REPORT_COUNT(8, 1),
|
||||||
|
HID_RI_REPORT_SIZE(8, 4),
|
||||||
|
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NULLSTATE),
|
||||||
|
// Padding (4 bits)
|
||||||
|
HID_RI_REPORT_COUNT(8, 0x04),
|
||||||
|
HID_RI_REPORT_SIZE(8, 0x01),
|
||||||
|
HID_RI_INPUT(8, HID_IOF_CONSTANT),
|
||||||
|
# endif
|
||||||
|
|
||||||
# if JOYSTICK_BUTTON_COUNT > 0
|
# if JOYSTICK_BUTTON_COUNT > 0
|
||||||
HID_RI_USAGE_PAGE(8, 0x09), // Button
|
HID_RI_USAGE_PAGE(8, 0x09), // Button
|
||||||
HID_RI_USAGE_MINIMUM(8, 0x01),
|
HID_RI_USAGE_MINIMUM(8, 0x01),
|
||||||
|
@ -621,6 +621,23 @@ const PROGMEM uchar shared_hid_report[] = {
|
|||||||
0x81, 0x02, // Input (Data, Variable, Absolute)
|
0x81, 0x02, // Input (Data, Variable, Absolute)
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
# ifdef JOYSTICK_HAS_HAT
|
||||||
|
// Hat Switch (4 bits)
|
||||||
|
0x09, 0x39, // Usage (Hat Switch)
|
||||||
|
0x15, 0x00, // Logical Minimum (0)
|
||||||
|
0x25, 0x07, // Logical Maximum (7)
|
||||||
|
0x35, 0x00, // Physical Minimum (0)
|
||||||
|
0x46, 0x3B, 0x01, // Physical Maximum (315)
|
||||||
|
0x65, 0x14, // Unit (Degree, English Rotation)
|
||||||
|
0x95, 0x01, // Report Count (1)
|
||||||
|
0x75, 0x04, // Report Size (4)
|
||||||
|
0x81, 0x42, // Input (Data, Variable, Absolute, Null State)
|
||||||
|
// Padding (4 bits)
|
||||||
|
0x95, 0x04, // Report Count (4)
|
||||||
|
0x75, 0x01, // Report Size (1)
|
||||||
|
0x81, 0x01, // Input (Constant)
|
||||||
|
# endif
|
||||||
|
|
||||||
# if JOYSTICK_BUTTON_COUNT > 0
|
# if JOYSTICK_BUTTON_COUNT > 0
|
||||||
0x05, 0x09, // Usage Page (Button)
|
0x05, 0x09, // Usage Page (Button)
|
||||||
0x19, 0x01, // Usage Minimum (Button 1)
|
0x19, 0x01, // Usage Minimum (Button 1)
|
||||||
|
Loading…
Reference in New Issue
Block a user