aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorcbdev <cb@cbcdn.com>2020-06-13 10:32:43 +0200
committercbdev <cb@cbcdn.com>2020-06-13 10:32:43 +0200
commit7b3245de94d5e9453ec1f817aa810f6bd3e64c28 (patch)
tree533201b402cd75cde0d5053bc75b5b5f4f6fc2a3
parent5e4c3fe5a81f548243aab01a42973333b559004f (diff)
downloadmidimonster-7b3245de94d5e9453ec1f817aa810f6bd3e64c28.tar.gz
midimonster-7b3245de94d5e9453ec1f817aa810f6bd3e64c28.tar.bz2
midimonster-7b3245de94d5e9453ec1f817aa810f6bd3e64c28.zip
Implement joystick axis input
-rw-r--r--backends/wininput.c57
-rw-r--r--backends/wininput.md27
2 files changed, 80 insertions, 4 deletions
diff --git a/backends/wininput.c b/backends/wininput.c
index 627891e..876e276 100644
--- a/backends/wininput.c
+++ b/backends/wininput.c
@@ -510,7 +510,7 @@ static int wininput_handle(size_t num, managed_fd* fds){
else if(cfg.request[u].ident.fields.type == joystick){
if(cfg.request[u].ident.fields.control >> 8 != current_joystick){
joy_info.dwSize = sizeof(joy_info);
- joy_info.dwFlags = JOY_RETURNALL;
+ joy_info.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS;
if(joyGetPosEx((cfg.request[u].ident.fields.control >> 8) - 1, &joy_info) != JOYERR_NOERROR){
LOGPF("Failed to query joystick %d", cfg.request[u].ident.fields.control >> 8);
//early exit because other joystick probably won't be connected either (though this may be wrong)
@@ -523,7 +523,7 @@ static int wininput_handle(size_t num, managed_fd* fds){
if(cfg.request[u].ident.fields.channel == button){
//button query
if(joy_info.dwFlags & JOY_RETURNBUTTONS){
- key_state = (joy_info.dwButtons & button_masks[(cfg.request[u].ident.fields.control & 0xFF)]) > 0 ? 1 : 0;
+ key_state = (joy_info.dwButtons & button_masks[(cfg.request[u].ident.fields.control & 0xFF) - 1]) > 0 ? 1 : 0;
if(key_state != cfg.request[u].state){
if(key_state){
val.normalised = 1.0;
@@ -541,12 +541,61 @@ static int wininput_handle(size_t num, managed_fd* fds){
}
}
else{
+ if(!cfg.request[u].max){
+ cfg.request[u].max = 0xFFFF;
+ }
+ val.raw.u64 = cfg.request[u].state;
- //TODO handle axis requests
+ //axis requests, every single access to these structures is stupid.
+ switch(cfg.request[u].ident.fields.control & 0xFF){
+ case 'x':
+ if(joy_info.dwFlags & JOY_RETURNX){
+ val.raw.u64 = joy_info.dwXpos;
+ }
+ break;
+ case 'y':
+ if(joy_info.dwFlags & JOY_RETURNY){
+ val.raw.u64 = joy_info.dwYpos;
+ }
+ break;
+ case 'z':
+ if(joy_info.dwFlags & JOY_RETURNZ){
+ val.raw.u64 = joy_info.dwZpos;
+ }
+ break;
+ case 'r':
+ if(joy_info.dwFlags & JOY_RETURNR){
+ val.raw.u64 = joy_info.dwRpos;
+ }
+ break;
+ case 'u':
+ if(joy_info.dwFlags & JOY_RETURNU){
+ val.raw.u64 = joy_info.dwUpos;
+ }
+ break;
+ case 'v':
+ if(joy_info.dwFlags & JOY_RETURNV){
+ val.raw.u64 = joy_info.dwVpos;
+ }
+ break;
+ case 'p':
+ if(joy_info.dwFlags & (JOY_RETURNPOV | JOY_RETURNPOVCTS)){
+ val.raw.u64 = joy_info.dwPOV;
+ }
+ break;
+ }
+
+ if(val.raw.u64 != cfg.request[u].state){
+ val.normalised = (double) (val.raw.u64 - cfg.request[u].min) / (double) (cfg.request[u].max - cfg.request[u].min);
+ cfg.request[u].state = val.raw.u64;
+ push_event = 1;
+ }
}
}
if(push_event){
+ //clamp value just to be safe
+ val.normalised = clamp(val.normalised, 1.0, 0.0);
//push current value to all channels
DBGPF("Pushing event %f on request %" PRIsize_t, val.normalised, u);
for(n = 0; n < cfg.request[u].channels; n++){
@@ -609,7 +658,7 @@ static void wininput_start_joystick(){
cfg.request[p].max = joy_caps.wVmax;
break;
}
- DBGPF("Updated limits on request %" PRIsize_t " to %" PRIu32 " / %" PRIu32, p, cfg.request[p].min, cfg.request[p].max);
+ DBGPF("Updated limits on request %" PRIsize_t " (%c) to %" PRIu32 " / %" PRIu32, p, cfg.request[p].ident.fields.control & 0xFF, cfg.request[p].min, cfg.request[p].max);
}
}
}
diff --git a/backends/wininput.md b/backends/wininput.md
index 6e665bb..bcf6a1b 100644
--- a/backends/wininput.md
+++ b/backends/wininput.md
@@ -77,6 +77,33 @@ input.a > wi1.key.a
input.X > wi1.key.escape
```
+Joystick and gamepad controllers with up to 32 buttons and 6 axes plus POV hat can be mapped as inputs to the
+MIDIMonster. When starting up, the MIDIMonster will output a list of all connected and usable game controllers.
+
+Controllers can be mapped using the syntax
+
+* `joy<n>.<axisname>` for axes, where `<n>` is the ID of the controller and `<axisname>` is one of
+ * `x`, `y`: Main joystick / analog controller axes
+ * `z`: Third axis / joystick rotation
+ * `r`: Fourth axis / Rudder controller / Slider
+ * `u`, `v`: non-specific fifth/sixth axis
+* `joy<n>.button<b>` for buttons, with `<n>` again being the controller ID and `b` being the button number between
+ 1 and 32 (the maximum supported by Windows)
+
+Use the Windows game controller input calibration and configuration tool to identify the axes and button IDs
+relevant to your controller.
+
+For button channels, the channel value will either be `0` or `1.0`, for axis channels it will be the normalized
+value of the axis (with calibration offsets applied), with the exception of the POV axis, where the channel value
+will be in some way correlated with the direction of view.
+
+Example mappings:
+```
+input.joy1.x > movinghead.pan
+input.joy1.y > movinghead.tilt
+input.joy1.button1 > movinghead.dim
+```
+
#### Known bugs / problems
Joysticks can only be used as input to the MIDIMonster, as Windows does not provide a method to emulate