diff options
author | cbdev <cb@cbcdn.com> | 2020-06-11 12:27:57 +0200 |
---|---|---|
committer | cbdev <cb@cbcdn.com> | 2020-06-11 12:27:57 +0200 |
commit | 5e4c3fe5a81f548243aab01a42973333b559004f (patch) | |
tree | 2cc9125aa681e6fac7d263413959db1388a97b46 | |
parent | e52c67ce0da7c3847d2583c8df6d5f1bd1fecb9e (diff) | |
download | midimonster-5e4c3fe5a81f548243aab01a42973333b559004f.tar.gz midimonster-5e4c3fe5a81f548243aab01a42973333b559004f.tar.bz2 midimonster-5e4c3fe5a81f548243aab01a42973333b559004f.zip |
Query joystick buttons
-rw-r--r-- | backends/maweb.c | 2 | ||||
-rw-r--r-- | backends/wininput.c | 87 | ||||
-rw-r--r-- | backends/wininput.h | 5 | ||||
-rw-r--r-- | backends/wininput.md | 5 |
4 files changed, 84 insertions, 15 deletions
diff --git a/backends/maweb.c b/backends/maweb.c index 7829ec4..33d2b7e 100644 --- a/backends/maweb.c +++ b/backends/maweb.c @@ -669,7 +669,7 @@ static void maweb_disconnect(instance* inst){ char xmit_buffer[MAWEB_XMIT_CHUNK]; if(data->fd){ - //close the session if one is active + //close the session if one is active if(data->session > 0){ snprintf(xmit_buffer, sizeof(xmit_buffer), "{\"requestType\":\"close\",\"session\":%" PRIu64 "}", data->session); maweb_send_frame(inst, ws_text, (uint8_t*) xmit_buffer, strlen(xmit_buffer)); diff --git a/backends/wininput.c b/backends/wininput.c index 71e9855..627891e 100644 --- a/backends/wininput.c +++ b/backends/wininput.c @@ -1,5 +1,5 @@ #define BACKEND_NAME "wininput" -#define DEBUG +//#define DEBUG #include <string.h> #include "wininput.h" @@ -7,6 +7,7 @@ #include <mmsystem.h> //TODO check whether feedback elimination is required +//TODO might want to store virtual desktop extents in request->limit static key_info keys[] = { {VK_LBUTTON, "lmb", button}, {VK_RBUTTON, "rmb", button}, {VK_MBUTTON, "mmb", button}, @@ -57,6 +58,17 @@ static key_info keys[] = { {VK_ZOOM, "zoom"} }; +//this monstrosity is necessary because not only are the buttons not a simple bitmask, the bits are also partially reused. +//i get why they replaced this heap of trash API, but the replacement would require me to jump through even more hoops. +static uint32_t button_masks[32] = {JOY_BUTTON1, JOY_BUTTON2, JOY_BUTTON3, JOY_BUTTON4, + JOY_BUTTON5, JOY_BUTTON6, JOY_BUTTON7, JOY_BUTTON8, + JOY_BUTTON9, JOY_BUTTON10, JOY_BUTTON11, JOY_BUTTON12, + JOY_BUTTON13, JOY_BUTTON14, JOY_BUTTON15, JOY_BUTTON16, + JOY_BUTTON17, JOY_BUTTON18, JOY_BUTTON19, JOY_BUTTON20, + JOY_BUTTON21, JOY_BUTTON22, JOY_BUTTON23, JOY_BUTTON24, + JOY_BUTTON25, JOY_BUTTON26, JOY_BUTTON27, JOY_BUTTON28, + JOY_BUTTON29, JOY_BUTTON30, JOY_BUTTON31, JOY_BUTTON32}; + static struct { int virtual_x, virtual_y, virtual_width, virtual_height; long mouse_x, mouse_y; @@ -159,7 +171,7 @@ static int wininput_subscribe(uint64_t ident, channel* chan){ cfg.request[u].ident.label = ident; cfg.request[u].channels = 0; cfg.request[u].channel = NULL; - cfg.request[u].state = 0; + cfg.request[u].state = cfg.request[u].min = cfg.request[u].max = 0; cfg.requests++; } @@ -276,7 +288,7 @@ static uint64_t wininput_channel_joystick(instance* inst, char* spec, uint8_t fl if(strlen(token) == 1 || !strcmp(token, "pov")){ if(strchr(axes, token[0])){ ident.fields.channel = position; - ident.fields.control = (controller << 8) | token[0]; + ident.fields.control = ((controller - 1) << 8) | token[0]; return ident.label; } @@ -511,13 +523,25 @@ 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){ - //TODO handle button requests + key_state = (joy_info.dwButtons & button_masks[(cfg.request[u].ident.fields.control & 0xFF)]) > 0 ? 1 : 0; + if(key_state != cfg.request[u].state){ + if(key_state){ + val.normalised = 1.0; + } + cfg.request[u].state = key_state; + push_event = 1; + DBGPF("Joystick %d button %d: %d", + cfg.request[u].ident.fields.control >> 8, + cfg.request[u].ident.fields.control & 0xFF, + key_state); + } } else{ LOGPF("No button data received for joystick %d", cfg.request[u].ident.fields.control >> 8); } } else{ + //TODO handle axis requests } } @@ -542,17 +566,11 @@ static int wininput_handle(size_t num, managed_fd* fds){ return 0; } -static int wininput_start(size_t n, instance** inst){ - size_t u; - POINT cursor_position; +static void wininput_start_joystick(){ + size_t u, p; JOYINFOEX joy_info; JOYCAPS joy_caps; - //if no input requested, don't request polling - if(!cfg.requests){ - cfg.interval = 0; - } - DBGPF("This system supports a maximum of %u joysticks", joyGetNumDevs()); for(u = 0; u < joyGetNumDevs(); u++){ joy_info.dwSize = sizeof(joy_info); @@ -560,12 +578,57 @@ static int wininput_start(size_t n, instance** inst){ if(joyGetPosEx(u, &joy_info) == JOYERR_NOERROR){ if(joyGetDevCaps(u, &joy_caps, sizeof(joy_caps)) == JOYERR_NOERROR){ LOGPF("Joystick %" PRIsize_t " (%s) is available for input", u + 1, joy_caps.szPname ? joy_caps.szPname : "unknown model"); + for(p = 0; p < cfg.requests; p++){ + if(cfg.request[p].ident.fields.type == joystick + && cfg.request[p].ident.fields.channel == position + && (cfg.request[p].ident.fields.control >> 8) == u){ + //this looks really dumb, but the structure is defined in a way that prevents us from doing anything clever here + switch(cfg.request[p].ident.fields.control & 0xFF){ + case 'x': + cfg.request[p].min = joy_caps.wXmin; + cfg.request[p].max = joy_caps.wXmax; + break; + case 'y': + cfg.request[p].min = joy_caps.wYmin; + cfg.request[p].max = joy_caps.wYmax; + break; + case 'z': + cfg.request[p].min = joy_caps.wZmin; + cfg.request[p].max = joy_caps.wZmax; + break; + case 'r': + cfg.request[p].min = joy_caps.wRmin; + cfg.request[p].max = joy_caps.wRmax; + break; + case 'u': + cfg.request[p].min = joy_caps.wUmin; + cfg.request[p].max = joy_caps.wUmax; + break; + case 'v': + cfg.request[p].min = joy_caps.wVmin; + 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); + } + } } else{ LOGPF("Joystick %" PRIsize_t " available for input, but no capabilities reported", u + 1); } } } +} + +static int wininput_start(size_t n, instance** inst){ + POINT cursor_position; + + //if no input requested, don't request polling + if(!cfg.requests){ + cfg.interval = 0; + } + + wininput_start_joystick(); //read virtual desktop extents for later normalization cfg.virtual_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); diff --git a/backends/wininput.h b/backends/wininput.h index 0318724..6ec9f46 100644 --- a/backends/wininput.h +++ b/backends/wininput.h @@ -47,5 +47,8 @@ typedef struct /*_input_request*/ { wininput_channel_ident ident; size_t channels; channel** channel; - uint16_t state; + uint32_t state; + + //used for jostick axes + uint32_t min, max; } wininput_request; diff --git a/backends/wininput.md b/backends/wininput.md index 6ead158..6e665bb 100644 --- a/backends/wininput.md +++ b/backends/wininput.md @@ -79,8 +79,11 @@ input.X > wi1.key.escape #### Known bugs / problems +Joysticks can only be used as input to the MIDIMonster, as Windows does not provide a method to emulate +Joystick input from user space. This is unlikely to change. + Keyboard and mouse input is subject to UIPI. You can not send input to applications that run at a higher -privilege level than the MIDIMonster. +privilege level than the MIDIMonster. This limitation is by design and will not change. Due to inconsistencies in the Windows API, mouse position input and output may differ for the same cursor location. This may be correlated with the use and arrangement of multi-monitor desktops. If you encounter problems with either |