add support for hid gamepad interface
add documentation for HID joystick Add joystick_task to read analog axes values even when no key is pressed or release. update doc Update docs/feature_joystick.md Manage pin setup and read to maintain matrix scan after analog read
This commit is contained in:
parent
d8f3c28a37
commit
3cf7611139
15 changed files with 675 additions and 2 deletions
|
@ -511,3 +511,12 @@ ifeq ($(strip $(AUTO_SHIFT_ENABLE)), yes)
|
||||||
OPT_DEFS += -DAUTO_SHIFT_MODIFIERS
|
OPT_DEFS += -DAUTO_SHIFT_MODIFIERS
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(JOYSTICK_ENABLE)), yes)
|
||||||
|
OPT_DEFS += -DJOYSTICK_ENABLE
|
||||||
|
SRC += $(QUANTUM_DIR)/process_keycode/process_joystick.c
|
||||||
|
SRC += $(QUANTUM_DIR)/joystick.c
|
||||||
|
ifeq ($(PLATFORM),AVR)
|
||||||
|
SRC += drivers/avr/analog.c
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
|
@ -97,6 +97,7 @@
|
||||||
* [DIP Switch](feature_dip_switch.md)
|
* [DIP Switch](feature_dip_switch.md)
|
||||||
* [Encoders](feature_encoders.md)
|
* [Encoders](feature_encoders.md)
|
||||||
* [Haptic Feedback](feature_haptic_feedback.md)
|
* [Haptic Feedback](feature_haptic_feedback.md)
|
||||||
|
* [Joystick](feature_joystick.md)
|
||||||
* [Proton C Conversion](proton_c_conversion.md)
|
* [Proton C Conversion](proton_c_conversion.md)
|
||||||
* [PS/2 Mouse](feature_ps2_mouse.md)
|
* [PS/2 Mouse](feature_ps2_mouse.md)
|
||||||
* [Split Keyboard](feature_split_keyboard.md)
|
* [Split Keyboard](feature_split_keyboard.md)
|
||||||
|
|
85
docs/feature_joystick.md
Normal file
85
docs/feature_joystick.md
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
## Joystick HID Device
|
||||||
|
|
||||||
|
The keyboard can be made to be recognized as a joystick HID device by the Operating System.
|
||||||
|
|
||||||
|
This is enabled by adding the following to `rules.mk`
|
||||||
|
|
||||||
|
```
|
||||||
|
JOYSTICK_ENABLE = yes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuring the joystick
|
||||||
|
|
||||||
|
The default joystick has 2 axes and and 8 buttons. This can be changed from the config.h file :
|
||||||
|
|
||||||
|
```
|
||||||
|
//max 32 for JOYSTICK_BUTTON_COUNT
|
||||||
|
#define JOYSTICK_BUTTON_COUNT 16
|
||||||
|
//max 6 for JOYSTICK_AXES_COUNT
|
||||||
|
#define JOYSTICK_AXES_COUNT 3
|
||||||
|
```
|
||||||
|
|
||||||
|
When defining axes for your joystick, you have to provide a definition array for it. You can do this from your keymap.c file.
|
||||||
|
A joystick will either be read from an input pin that allows the use of an ADC, or can be virtual, so that its value is provided by your code.
|
||||||
|
You have to define an array of type ''joystick_config_t'' and of proper size, in the following way :
|
||||||
|
|
||||||
|
```
|
||||||
|
//joystick config
|
||||||
|
joystick_config_t joystick_axes[JOYSTICK_AXES_COUNT] = {
|
||||||
|
[0] = {A1, D7, 65280, 65472},
|
||||||
|
[1] = {JS_VIRTUAL_AXIS, JS_VIRTUAL_AXIS, 65280, 65472}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, the first axis will be read from the D7 pin while A1 is set high, using an analogRead, whereas the second axis will not be read.
|
||||||
|
If you connected the your analog component to Vcc instead of an output pin, you can set the output setting to JS_VIRTUAL_AXIS.
|
||||||
|
In order to give a value to the second axis, you can do so in any customizable entry point of quantum : as an action, in process_record_user or in matrix_scan_user, or even in joystick_task(void) which is called even when no key has been pressed.
|
||||||
|
You assign a value by writing to joystick_status.axes[axis_index] a signed 8bit value (-127 to 127). Then it is necessary to assign the flag JS_UPDATED to joystick_status.status in order for the change to be taken into account.
|
||||||
|
|
||||||
|
The following example writes two axes based on keypad presses, with KP_5 as a precision modifier :
|
||||||
|
|
||||||
|
```
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
static bool precision_on;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
|
switch(keycode){
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
// virtual joystick
|
||||||
|
case KC_P8:
|
||||||
|
joystick_status.axes[1] -= (record->event.pressed ? 1 : -1) * (precision_on ?70 : 127);
|
||||||
|
joystick_status.status |= JS_UPDATED;
|
||||||
|
break;
|
||||||
|
case KC_P2:
|
||||||
|
joystick_status.axes[1] += (record->event.pressed ? 1 : -1) * (precision_on ?70 : 127);
|
||||||
|
joystick_status.status |= JS_UPDATED;
|
||||||
|
break;
|
||||||
|
case KC_P4:
|
||||||
|
joystick_status.axes[0] -= (record->event.pressed ? 1 : -1) * (precision_on ?70 : 127);
|
||||||
|
joystick_status.status |= JS_UPDATED;
|
||||||
|
break;
|
||||||
|
case KC_P6:
|
||||||
|
joystick_status.axes[0] += (record->event.pressed ? 1 : -1) * (precision_on ?70 : 127);
|
||||||
|
joystick_status.status |= JS_UPDATED;
|
||||||
|
break;
|
||||||
|
case KC_P5:
|
||||||
|
precision_on = record->event.pressed;
|
||||||
|
joystick_status.axes[0] *= record->event.pressed ? 70/127.f : 127/70.f;
|
||||||
|
joystick_status.axes[1] *= record->event.pressed ? 70/127.f : 127/70.f;
|
||||||
|
joystick_status.status |= JS_UPDATED;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Triggering joystick buttons
|
||||||
|
|
||||||
|
Joystick buttons are normal quantum keycode, defined as JS_BUTTON0 to JS_BUTTON_MAX, which depends on the number of buttons you have configured.
|
||||||
|
To trigger a joystick button, just add the corresponding keycode to your keymap.
|
||||||
|
|
||||||
|
|
||||||
|
|
11
quantum/joystick.c
Normal file
11
quantum/joystick.c
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include "joystick.h"
|
||||||
|
|
||||||
|
joystick_t joystick_status = {
|
||||||
|
.buttons = {0},
|
||||||
|
.axes = {0},
|
||||||
|
.status = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
//array defining the reading of analog values for each axis
|
||||||
|
__attribute__ ((weak))
|
||||||
|
joystick_config_t joystick_axes[JOYSTICK_AXES_COUNT] = {};
|
48
quantum/joystick.h
Normal file
48
quantum/joystick.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#ifndef JOYSTICK_H
|
||||||
|
#define JOYSTICK_H
|
||||||
|
|
||||||
|
#ifndef JOYSTICK_BUTTON_COUNT
|
||||||
|
#define JOYSTICK_BUTTON_COUNT 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JOYSTICK_AXES_COUNT
|
||||||
|
#define JOYSTICK_AXES_COUNT 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
//configure on input_pin of the joystick_axes array entry to JS_VIRTUAL_AXIS
|
||||||
|
// to prevent it from being read from the ADC. This allows outputing forged axis value.
|
||||||
|
//
|
||||||
|
#define JS_VIRTUAL_AXIS 0xFF
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t output_pin;
|
||||||
|
uint8_t input_pin;
|
||||||
|
|
||||||
|
//the AVR ADC offers 10 bit precision, with significant bits on the higher part
|
||||||
|
uint16_t min_digit;
|
||||||
|
uint16_t max_digit;
|
||||||
|
} joystick_config_t;
|
||||||
|
|
||||||
|
extern joystick_config_t joystick_axes[JOYSTICK_AXES_COUNT];
|
||||||
|
|
||||||
|
enum joystick_status{
|
||||||
|
JS_INITIALIZED = 1,
|
||||||
|
JS_UPDATED = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
uint8_t buttons[JOYSTICK_BUTTON_COUNT/8+1];
|
||||||
|
|
||||||
|
int8_t axes[JOYSTICK_AXES_COUNT];
|
||||||
|
uint8_t status:2;
|
||||||
|
} joystick_t;
|
||||||
|
|
||||||
|
extern joystick_t joystick_status;
|
||||||
|
|
||||||
|
//to be implemented in the hid protocol library
|
||||||
|
void send_joystick_packet(joystick_t* joystick);
|
||||||
|
|
||||||
|
#endif //JOYSTICK_H
|
79
quantum/process_keycode/process_joystick.c
Normal file
79
quantum/process_keycode/process_joystick.c
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#include "process_joystick.h"
|
||||||
|
|
||||||
|
#include <quantum/joystick.h>
|
||||||
|
#include <quantum/quantum_keycodes.h>
|
||||||
|
|
||||||
|
#ifdef __AVR__
|
||||||
|
# include <drivers/avr/analog.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
bool process_joystick_buttons(uint16_t keycode, keyrecord_t *record);
|
||||||
|
|
||||||
|
bool process_joystick(uint16_t keycode, keyrecord_t *record){
|
||||||
|
|
||||||
|
if (process_joystick_buttons(keycode, record)
|
||||||
|
&& (joystick_status.status & JS_UPDATED)>0){
|
||||||
|
send_joystick_packet(&joystick_status);
|
||||||
|
joystick_status.status &= ~JS_UPDATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((weak))
|
||||||
|
void joystick_task(void){
|
||||||
|
if (process_joystick_analog() && (joystick_status.status & JS_UPDATED)){
|
||||||
|
send_joystick_packet(&joystick_status);
|
||||||
|
joystick_status.status &= ~JS_UPDATED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool process_joystick_buttons(uint16_t keycode, keyrecord_t *record){
|
||||||
|
|
||||||
|
if (keycode < JS_BUTTON0 || keycode > JS_BUTTON_MAX){
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (record->event.pressed){
|
||||||
|
joystick_status.buttons[(keycode-JS_BUTTON0)/8] |= 1<<(keycode%8);
|
||||||
|
} else {
|
||||||
|
joystick_status.buttons[(keycode-JS_BUTTON0)/8] &= ~(1<<(keycode%8));
|
||||||
|
}
|
||||||
|
|
||||||
|
joystick_status.status |= JS_UPDATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((weak))
|
||||||
|
bool process_joystick_analog(){
|
||||||
|
#if JOYSTICK_AXES_COUNT > 0
|
||||||
|
for (int axis_index=0 ; axis_index<JOYSTICK_AXES_COUNT ; ++axis_index){
|
||||||
|
if (joystick_axes[axis_index].output_pin==JS_VIRTUAL_AXIS || joystick_axes[axis_index].input_pin==JS_VIRTUAL_AXIS){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPinOutput(joystick_axes[axis_index].output_pin);
|
||||||
|
writePinHigh(joystick_axes[axis_index].output_pin);
|
||||||
|
|
||||||
|
//disable pull-up resistance
|
||||||
|
setPinInput(joystick_axes[axis_index].input_pin);
|
||||||
|
writePinLow(joystick_axes[axis_index].input_pin);
|
||||||
|
|
||||||
|
#ifdef __AVR__
|
||||||
|
int16_t axis_val = analogReadPin(joystick_axes[axis_index].input_pin);
|
||||||
|
#else
|
||||||
|
int16_t axis_val = 0;
|
||||||
|
#endif
|
||||||
|
if (axis_val!=joystick_status.axes[axis_index]){
|
||||||
|
joystick_status.axes[axis_index] = axis_val;
|
||||||
|
joystick_status.status |= JS_UPDATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
writePinLow(joystick_axes[axis_index].output_pin);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
13
quantum/process_keycode/process_joystick.h
Normal file
13
quantum/process_keycode/process_joystick.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef PROCESS_JOYSTICK_H
|
||||||
|
#define PROCESS_JOYSTICK_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "quantum.h"
|
||||||
|
|
||||||
|
bool process_joystick(uint16_t keycode, keyrecord_t *record);
|
||||||
|
|
||||||
|
void joystick_task(void);
|
||||||
|
|
||||||
|
bool process_joystick_analog(void);
|
||||||
|
|
||||||
|
#endif //PROCESS_JOYSTICK_H
|
|
@ -63,6 +63,10 @@ float bell_song[][2] = SONG(TERMINAL_SOUND);
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
#include <process_keycode/process_joystick.h>
|
||||||
|
#endif //JOYSTICK_ENABLE
|
||||||
|
|
||||||
static void do_code16(uint16_t code, void (*f)(uint8_t)) {
|
static void do_code16(uint16_t code, void (*f)(uint8_t)) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case QK_MODS ... QK_MODS_MAX:
|
case QK_MODS ... QK_MODS_MAX:
|
||||||
|
@ -265,6 +269,9 @@ bool process_record_quantum(keyrecord_t *record) {
|
||||||
#endif
|
#endif
|
||||||
#if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE)
|
#if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE)
|
||||||
process_rgb(keycode, record) &&
|
process_rgb(keycode, record) &&
|
||||||
|
#endif
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
process_joystick(keycode, record) &&
|
||||||
#endif
|
#endif
|
||||||
true)) {
|
true)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -512,6 +512,41 @@ enum quantum_keycodes {
|
||||||
DYN_MACRO_PLAY1,
|
DYN_MACRO_PLAY1,
|
||||||
DYN_MACRO_PLAY2,
|
DYN_MACRO_PLAY2,
|
||||||
|
|
||||||
|
JS_BUTTON0,
|
||||||
|
JS_BUTTON_MIN = JS_BUTTON0,
|
||||||
|
JS_BUTTON1,
|
||||||
|
JS_BUTTON2,
|
||||||
|
JS_BUTTON3,
|
||||||
|
JS_BUTTON4,
|
||||||
|
JS_BUTTON5,
|
||||||
|
JS_BUTTON6,
|
||||||
|
JS_BUTTON7,
|
||||||
|
JS_BUTTON8,
|
||||||
|
JS_BUTTON9,
|
||||||
|
JS_BUTTON10,
|
||||||
|
JS_BUTTON11,
|
||||||
|
JS_BUTTON12,
|
||||||
|
JS_BUTTON13,
|
||||||
|
JS_BUTTON14,
|
||||||
|
JS_BUTTON15,
|
||||||
|
JS_BUTTON16,
|
||||||
|
JS_BUTTON17,
|
||||||
|
JS_BUTTON18,
|
||||||
|
JS_BUTTON19,
|
||||||
|
JS_BUTTON20,
|
||||||
|
JS_BUTTON21,
|
||||||
|
JS_BUTTON22,
|
||||||
|
JS_BUTTON23,
|
||||||
|
JS_BUTTON24,
|
||||||
|
JS_BUTTON25,
|
||||||
|
JS_BUTTON26,
|
||||||
|
JS_BUTTON27,
|
||||||
|
JS_BUTTON28,
|
||||||
|
JS_BUTTON29,
|
||||||
|
JS_BUTTON30,
|
||||||
|
JS_BUTTON31,
|
||||||
|
JS_BUTTON_MAX = JS_BUTTON31,
|
||||||
|
|
||||||
// always leave at the end
|
// always leave at the end
|
||||||
SAFE_RANGE
|
SAFE_RANGE
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,6 +71,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#ifdef MIDI_ENABLE
|
#ifdef MIDI_ENABLE
|
||||||
# include "process_midi.h"
|
# include "process_midi.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
# include "process_joystick.h"
|
||||||
|
#endif
|
||||||
#ifdef HD44780_ENABLE
|
#ifdef HD44780_ENABLE
|
||||||
# include "hd44780.h"
|
# include "hd44780.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -396,6 +399,10 @@ MATRIX_LOOP_END:
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
joystick_task();
|
||||||
|
#endif
|
||||||
|
|
||||||
// update LED
|
// update LED
|
||||||
if (led_status != host_keyboard_leds()) {
|
if (led_status != host_keyboard_leds()) {
|
||||||
led_status = host_keyboard_leds();
|
led_status = host_keyboard_leds();
|
||||||
|
|
|
@ -47,6 +47,10 @@
|
||||||
extern keymap_config_t keymap_config;
|
extern keymap_config_t keymap_config;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
# include <quantum/joystick.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ---------------------------------------------------------
|
/* ---------------------------------------------------------
|
||||||
* Global interface variables and declarations
|
* Global interface variables and declarations
|
||||||
* ---------------------------------------------------------
|
* ---------------------------------------------------------
|
||||||
|
@ -246,6 +250,9 @@ typedef struct {
|
||||||
#endif
|
#endif
|
||||||
#ifdef VIRTSER_ENABLE
|
#ifdef VIRTSER_ENABLE
|
||||||
usb_driver_config_t serial_driver;
|
usb_driver_config_t serial_driver;
|
||||||
|
#endif
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
usb_driver_config_t joystick_driver;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
usb_driver_config_t array[0];
|
usb_driver_config_t array[0];
|
||||||
|
@ -283,6 +290,14 @@ static usb_driver_configs_t drivers = {
|
||||||
# define CDC_OUT_MODE USB_EP_MODE_TYPE_BULK
|
# define CDC_OUT_MODE USB_EP_MODE_TYPE_BULK
|
||||||
.serial_driver = QMK_USB_DRIVER_CONFIG(CDC, CDC_NOTIFICATION_EPNUM, false),
|
.serial_driver = QMK_USB_DRIVER_CONFIG(CDC, CDC_NOTIFICATION_EPNUM, false),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
#define JOYSTICK_IN_CAPACITY 4
|
||||||
|
#define JOYSTICK_OUT_CAPACITY 4
|
||||||
|
#define JOYSTICK_IN_MODE USB_EP_MODE_TYPE_BULK
|
||||||
|
#define JOYSTICK_OUT_MODE USB_EP_MODE_TYPE_BULK
|
||||||
|
.joystick_driver = QMK_USB_DRIVER_CONFIG(JOYSTICK, 0, false),
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_USB_DRIVERS (sizeof(drivers) / sizeof(usb_driver_config_t))
|
#define NUM_USB_DRIVERS (sizeof(drivers) / sizeof(usb_driver_config_t))
|
||||||
|
@ -870,3 +885,61 @@ void virtser_task(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
#if JOYSTICK_AXES_COUNT>0
|
||||||
|
int8_t axes[JOYSTICK_AXES_COUNT];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>0
|
||||||
|
uint8_t buttons[(JOYSTICK_BUTTON_COUNT-1)/8+1];
|
||||||
|
#endif
|
||||||
|
} __attribute__ ((packed)) joystick_report_t;
|
||||||
|
|
||||||
|
void send_joystick_packet(joystick_t* joystick) {
|
||||||
|
joystick_report_t rep = {
|
||||||
|
#if JOYSTICK_AXES_COUNT>0
|
||||||
|
.axes = {
|
||||||
|
joystick->axes[0]
|
||||||
|
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 2
|
||||||
|
,joystick->axes[1]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 3
|
||||||
|
,joystick->axes[2]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 4
|
||||||
|
,joystick->axes[3]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 5
|
||||||
|
,joystick->axes[4]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 6
|
||||||
|
,joystick->axes[5]
|
||||||
|
#endif
|
||||||
|
},
|
||||||
|
#endif //JOYSTICK_AXES_COUNT>0
|
||||||
|
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>0
|
||||||
|
.buttons = {
|
||||||
|
joystick->buttons[0]
|
||||||
|
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>8
|
||||||
|
,joystick->buttons[1]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>16
|
||||||
|
,joystick->buttons[2]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>24
|
||||||
|
,joystick->buttons[3]
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif //JOYSTICK_BUTTON_COUNT>0
|
||||||
|
};
|
||||||
|
|
||||||
|
chnWrite(&drivers.joystick_driver.driver, (uint8_t*)&rep, sizeof(rep));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -85,6 +85,10 @@ extern keymap_config_t keymap_config;
|
||||||
# include "raw_hid.h"
|
# include "raw_hid.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
#include "joystick.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
uint8_t keyboard_idle = 0;
|
uint8_t keyboard_idle = 0;
|
||||||
/* 0: Boot Protocol, 1: Report Protocol(default) */
|
/* 0: Boot Protocol, 1: Report Protocol(default) */
|
||||||
uint8_t keyboard_protocol = 1;
|
uint8_t keyboard_protocol = 1;
|
||||||
|
@ -263,6 +267,85 @@ static void Console_Task(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Joystick
|
||||||
|
******************************************************************************/
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
#if JOYSTICK_AXES_COUNT>0
|
||||||
|
int8_t axes[JOYSTICK_AXES_COUNT];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>0
|
||||||
|
uint8_t buttons[(JOYSTICK_BUTTON_COUNT-1)/8+1];
|
||||||
|
#endif
|
||||||
|
} __attribute__ ((packed)) joystick_report_t;
|
||||||
|
|
||||||
|
void send_joystick_packet(joystick_t* joystick){
|
||||||
|
|
||||||
|
uint8_t timeout = 255;
|
||||||
|
uint8_t where = where_to_send();
|
||||||
|
|
||||||
|
if (where != OUTPUT_USB && where != OUTPUT_USB_AND_BT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
joystick_report_t r = {
|
||||||
|
#if JOYSTICK_AXES_COUNT>0
|
||||||
|
.axes = {
|
||||||
|
joystick->axes[0]
|
||||||
|
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 2
|
||||||
|
,joystick->axes[1]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 3
|
||||||
|
,joystick->axes[2]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 4
|
||||||
|
,joystick->axes[3]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 5
|
||||||
|
,joystick->axes[4]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 6
|
||||||
|
,joystick->axes[5]
|
||||||
|
#endif
|
||||||
|
},
|
||||||
|
#endif //JOYSTICK_AXES_COUNT>0
|
||||||
|
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>0
|
||||||
|
.buttons = {
|
||||||
|
joystick->buttons[0]
|
||||||
|
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>8
|
||||||
|
,joystick->buttons[1]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>16
|
||||||
|
,joystick->buttons[2]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>24
|
||||||
|
,joystick->buttons[3]
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif //JOYSTICK_BUTTON_COUNT>0
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Select the Joystick Report Endpoint */
|
||||||
|
Endpoint_SelectEndpoint(JOYSTICK_IN_EPNUM);
|
||||||
|
|
||||||
|
/* Check if write ready for a polling interval around 10ms */
|
||||||
|
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
|
||||||
|
if (!Endpoint_IsReadWriteAllowed()) return;
|
||||||
|
|
||||||
|
/* Write Joystick Report Data */
|
||||||
|
Endpoint_Write_Stream_LE(&r, sizeof(joystick_report_t), NULL);
|
||||||
|
|
||||||
|
/* Finalize the stream transfer to send the last packet */
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* USB Events
|
* USB Events
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
|
@ -278,6 +278,53 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM ConsoleReport[] = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
const USB_Descriptor_HIDReport_Datatype_t PROGMEM JoystickReport[] =
|
||||||
|
{
|
||||||
|
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
|
||||||
|
HID_RI_USAGE(8, 0x04), /* Joystick */
|
||||||
|
HID_RI_COLLECTION(8, 0x01), /* Application */
|
||||||
|
HID_RI_USAGE(8, 0x01), /* Pointer */
|
||||||
|
HID_RI_COLLECTION(8, 0x00), /* Physical */
|
||||||
|
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 1
|
||||||
|
HID_RI_USAGE(8, 0x30), // USAGE (X)
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 2
|
||||||
|
HID_RI_USAGE(8, 0x31), // USAGE (Y)
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 3
|
||||||
|
HID_RI_USAGE(8, 0x32), // USAGE (Z)
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 4
|
||||||
|
HID_RI_USAGE(8, 0x33), // USAGE (RX)
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 5
|
||||||
|
HID_RI_USAGE(8, 0x34), // USAGE (RY)
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 6
|
||||||
|
HID_RI_USAGE(8, 0x35), // USAGE (RZ)
|
||||||
|
#endif
|
||||||
|
HID_RI_LOGICAL_MINIMUM(8, -127),
|
||||||
|
HID_RI_LOGICAL_MAXIMUM(8, 127),
|
||||||
|
HID_RI_REPORT_COUNT(8, JOYSTICK_AXES_COUNT),
|
||||||
|
HID_RI_REPORT_SIZE(8, 0x08),
|
||||||
|
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),
|
||||||
|
|
||||||
|
HID_RI_USAGE_PAGE(8, 0x09), /* Button */
|
||||||
|
HID_RI_USAGE_MINIMUM(8, 0x01), /* Button 1 */
|
||||||
|
HID_RI_USAGE_MAXIMUM(8, JOYSTICK_BUTTON_COUNT), /* Button 5 */
|
||||||
|
HID_RI_LOGICAL_MINIMUM(8, 0x00),
|
||||||
|
HID_RI_LOGICAL_MAXIMUM(8, 0x01),
|
||||||
|
HID_RI_REPORT_COUNT(8, JOYSTICK_BUTTON_COUNT),
|
||||||
|
HID_RI_REPORT_SIZE(8, 0x01),
|
||||||
|
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
|
||||||
|
|
||||||
|
HID_RI_END_COLLECTION(0),
|
||||||
|
HID_RI_END_COLLECTION(0),
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Device descriptor
|
* Device descriptor
|
||||||
*/
|
*/
|
||||||
|
@ -287,7 +334,6 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = {
|
||||||
.Type = DTYPE_Device
|
.Type = DTYPE_Device
|
||||||
},
|
},
|
||||||
.USBSpecification = VERSION_BCD(1, 1, 0),
|
.USBSpecification = VERSION_BCD(1, 1, 0),
|
||||||
|
|
||||||
#if VIRTSER_ENABLE
|
#if VIRTSER_ENABLE
|
||||||
.Class = USB_CSCP_IADDeviceClass,
|
.Class = USB_CSCP_IADDeviceClass,
|
||||||
.SubClass = USB_CSCP_IADDeviceSubclass,
|
.SubClass = USB_CSCP_IADDeviceSubclass,
|
||||||
|
@ -812,6 +858,49 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = {
|
||||||
.PollingIntervalMS = 0x05
|
.PollingIntervalMS = 0x05
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Joystick
|
||||||
|
*/
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
.Joystick_Interface =
|
||||||
|
{
|
||||||
|
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
|
||||||
|
|
||||||
|
.InterfaceNumber = JOYSTICK_INTERFACE,
|
||||||
|
.AlternateSetting = 0x00,
|
||||||
|
|
||||||
|
.TotalEndpoints = 1,
|
||||||
|
|
||||||
|
.Class = HID_CSCP_HIDClass,
|
||||||
|
.SubClass = HID_CSCP_NonBootSubclass,
|
||||||
|
.Protocol = HID_CSCP_NonBootProtocol,
|
||||||
|
|
||||||
|
.InterfaceStrIndex = NO_DESCRIPTOR
|
||||||
|
},
|
||||||
|
|
||||||
|
.Joystick_HID =
|
||||||
|
{
|
||||||
|
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
|
||||||
|
|
||||||
|
.HIDSpec = VERSION_BCD(1,1,1),
|
||||||
|
.CountryCode = 0x00,
|
||||||
|
.TotalReportDescriptors = 1,
|
||||||
|
.HIDReportType = HID_DTYPE_Report,
|
||||||
|
.HIDReportLength = sizeof(JoystickReport)
|
||||||
|
},
|
||||||
|
|
||||||
|
.Joystick_INEndpoint =
|
||||||
|
{
|
||||||
|
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
|
||||||
|
|
||||||
|
.EndpointAddress = (ENDPOINT_DIR_IN | JOYSTICK_IN_EPNUM),
|
||||||
|
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
|
||||||
|
.EndpointSize = JOYSTICK_EPSIZE,
|
||||||
|
.PollingIntervalMS = 0x0A
|
||||||
|
},
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -943,6 +1032,12 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const
|
||||||
Size = sizeof(USB_HID_Descriptor_HID_t);
|
Size = sizeof(USB_HID_Descriptor_HID_t);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
case JOYSTICK_INTERFACE:
|
||||||
|
Address = &ConfigurationDescriptor.Joystick_HID;
|
||||||
|
Size = sizeof(USB_HID_Descriptor_HID_t);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -987,6 +1082,12 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const
|
||||||
Size = sizeof(ConsoleReport);
|
Size = sizeof(ConsoleReport);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
case JOYSTICK_INTERFACE:
|
||||||
|
Address = &JoystickReport;
|
||||||
|
Size = sizeof(JoystickReport);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,13 @@ typedef struct {
|
||||||
USB_Descriptor_Endpoint_t CDC_DataOutEndpoint;
|
USB_Descriptor_Endpoint_t CDC_DataOutEndpoint;
|
||||||
USB_Descriptor_Endpoint_t CDC_DataInEndpoint;
|
USB_Descriptor_Endpoint_t CDC_DataInEndpoint;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
// Joystick HID Interface
|
||||||
|
USB_Descriptor_Interface_t Joystick_Interface;
|
||||||
|
USB_HID_Descriptor_HID_t Joystick_HID;
|
||||||
|
USB_Descriptor_Endpoint_t Joystick_INEndpoint;
|
||||||
|
#endif
|
||||||
} USB_Descriptor_Configuration_t;
|
} USB_Descriptor_Configuration_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -164,6 +171,9 @@ enum usb_interfaces {
|
||||||
CDI_INTERFACE,
|
CDI_INTERFACE,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(JOYSTICK_ENABLE)
|
||||||
|
JOYSTICK_INTERFACE,
|
||||||
|
#endif
|
||||||
TOTAL_INTERFACES
|
TOTAL_INTERFACES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -224,6 +234,10 @@ enum usb_endpoints {
|
||||||
# define CDC_IN_EPADDR (ENDPOINT_DIR_IN | CDC_IN_EPNUM)
|
# define CDC_IN_EPADDR (ENDPOINT_DIR_IN | CDC_IN_EPNUM)
|
||||||
# define CDC_OUT_EPADDR (ENDPOINT_DIR_OUT | CDC_OUT_EPNUM)
|
# define CDC_OUT_EPADDR (ENDPOINT_DIR_OUT | CDC_OUT_EPNUM)
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef JOYSTICK_ENABLE
|
||||||
|
JOYSTICK_IN_EPNUM = NEXT_EPNUM,
|
||||||
|
JOYSTICK_OUT_EPNUM = NEXT_EPNUM,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef PROTOCOL_LUFA
|
#ifdef PROTOCOL_LUFA
|
||||||
|
@ -248,6 +262,7 @@ enum usb_endpoints {
|
||||||
#define MIDI_STREAM_EPSIZE 64
|
#define MIDI_STREAM_EPSIZE 64
|
||||||
#define CDC_NOTIFICATION_EPSIZE 8
|
#define CDC_NOTIFICATION_EPSIZE 8
|
||||||
#define CDC_EPSIZE 16
|
#define CDC_EPSIZE 16
|
||||||
|
#define JOYSTICK_EPSIZE 8
|
||||||
|
|
||||||
uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const void** const DescriptorAddress);
|
uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const void** const DescriptorAddress);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,6 +26,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "host_driver.h"
|
#include "host_driver.h"
|
||||||
#include "vusb.h"
|
#include "vusb.h"
|
||||||
|
#include "joystick.h"
|
||||||
|
#include "joystick.h"
|
||||||
#include <util/delay.h>
|
#include <util/delay.h>
|
||||||
|
|
||||||
static uint8_t vusb_keyboard_leds = 0;
|
static uint8_t vusb_keyboard_leds = 0;
|
||||||
|
@ -79,6 +81,7 @@ static void send_keyboard(report_keyboard_t *report);
|
||||||
static void send_mouse(report_mouse_t *report);
|
static void send_mouse(report_mouse_t *report);
|
||||||
static void send_system(uint16_t data);
|
static void send_system(uint16_t data);
|
||||||
static void send_consumer(uint16_t data);
|
static void send_consumer(uint16_t data);
|
||||||
|
static void send_joystick(void);
|
||||||
|
|
||||||
static host_driver_t driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer};
|
static host_driver_t driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer};
|
||||||
|
|
||||||
|
@ -139,6 +142,68 @@ static void send_consumer(uint16_t data) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t report_id;
|
||||||
|
|
||||||
|
#if JOYSTICK_AXES_COUNT>0
|
||||||
|
int8_t axes[JOYSTICK_AXES_COUNT];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>0
|
||||||
|
uint8_t buttons[(JOYSTICK_BUTTON_COUNT-1)/8+1];
|
||||||
|
#endif
|
||||||
|
} __attribute__ ((packed)) vusb_joystick_report_t;
|
||||||
|
|
||||||
|
void send_joystick_packet(joystick_t* status)
|
||||||
|
{
|
||||||
|
vusb_joystick_report_t r = {
|
||||||
|
.report_id = 0x4,
|
||||||
|
|
||||||
|
#if JOYSTICK_AXES_COUNT>0
|
||||||
|
.axes = {
|
||||||
|
status->axes[0]
|
||||||
|
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 2
|
||||||
|
,status->axes[1]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 3
|
||||||
|
,status->axes[2]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 4
|
||||||
|
,status->axes[3]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 5
|
||||||
|
,status->axes[4]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 6
|
||||||
|
,status->axes[5]
|
||||||
|
#endif
|
||||||
|
},
|
||||||
|
#endif //JOYSTICK_AXES_COUNT>0
|
||||||
|
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>0
|
||||||
|
.buttons = {
|
||||||
|
status->buttons[0]
|
||||||
|
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>8
|
||||||
|
,status->buttons[1]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>16
|
||||||
|
,status->buttons[2]
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_BUTTON_COUNT>24
|
||||||
|
,status->buttons[3]
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif //JOYSTICK_BUTTON_COUNT>0
|
||||||
|
};
|
||||||
|
if (usbInterruptIsReady3()) {
|
||||||
|
usbSetInterrupt3((void *)&r, sizeof(vusb_joystick_report_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------*
|
/*------------------------------------------------------------------*
|
||||||
* Request from host *
|
* Request from host *
|
||||||
*------------------------------------------------------------------*/
|
*------------------------------------------------------------------*/
|
||||||
|
@ -251,7 +316,7 @@ const PROGMEM uchar keyboard_hid_report[] = {
|
||||||
0xC0 // End Collection
|
0xC0 // End Collection
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
|
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE) || defined(JOYSTICK_ENABLE)
|
||||||
const PROGMEM uchar mouse_extra_hid_report[] = {
|
const PROGMEM uchar mouse_extra_hid_report[] = {
|
||||||
# ifdef MOUSE_ENABLE
|
# ifdef MOUSE_ENABLE
|
||||||
// Mouse report descriptor
|
// Mouse report descriptor
|
||||||
|
@ -332,6 +397,47 @@ const PROGMEM uchar mouse_extra_hid_report[] = {
|
||||||
0x81, 0x00, // Input (Data, Array, Absolute)
|
0x81, 0x00, // Input (Data, Array, Absolute)
|
||||||
0xC0 // End Collection
|
0xC0 // End Collection
|
||||||
# endif
|
# endif
|
||||||
|
#if JOYSTICK_ENABLE
|
||||||
|
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
||||||
|
0x09, 0x04, // USAGE (Joystick)
|
||||||
|
0xa1, 0x01, // COLLECTION (Application)
|
||||||
|
0x85, 0x4, // REPORT_ID (4)
|
||||||
|
0x09, 0x01, // USAGE (Pointer)
|
||||||
|
0xa1, 0x00, // COLLECTION (Physical)
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 1
|
||||||
|
0x09, 0x30, // USAGE (X)
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 2
|
||||||
|
0x09, 0x31, // USAGE (Y)
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 3
|
||||||
|
0x09, 0x32, // USAGE (Z)
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 4
|
||||||
|
0x09, 0x33, // USAGE (RX)
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 5
|
||||||
|
0x09, 0x34, // USAGE (RY)
|
||||||
|
#endif
|
||||||
|
#if JOYSTICK_AXES_COUNT >= 6
|
||||||
|
0x09, 0x35, // USAGE (RZ)
|
||||||
|
#endif
|
||||||
|
0x15, 0x81, // LOGICAL_MINIMUM (-127)
|
||||||
|
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
|
||||||
|
0x75, 0x08, // REPORT_SIZE (8)
|
||||||
|
0x95, JOYSTICK_AXES_COUNT, // REPORT_COUNT (JOYSTICK_AXES_COUNT)
|
||||||
|
0x81, 0x02, // INPUT (Data,Var,Abs)
|
||||||
|
0xc0, // END_COLLECTION
|
||||||
|
0x05, 0x09, // USAGE_PAGE (Button)
|
||||||
|
0x19, 0x01, // USAGE_MINIMUM (Button 1)
|
||||||
|
0x29, JOYSTICK_BUTTON_COUNT, // USAGE_MAXIMUM
|
||||||
|
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
||||||
|
0x25, 0x01, // LOGICAL_MAXIMUM (1)
|
||||||
|
0x75, 0x01, // REPORT_SIZE (1)
|
||||||
|
0x95, JOYSTICK_BUTTON_COUNT, // REPORT_COUNT
|
||||||
|
0x81, 0x02, // INPUT (Data,Var,Abs)
|
||||||
|
0xc0 // END_COLLECTION
|
||||||
|
#endif //GAMEPAD_ENABLE
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue