aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorcbdev <cb@cbcdn.com>2020-08-18 06:37:01 +0200
committercbdev <cb@cbcdn.com>2020-08-18 06:37:01 +0200
commite131992bbe0893a3e5b79cf9423830ea90b4a4d7 (patch)
tree85466669d2dfee6512f103178baa35c39a44b07c
parent4d7db4128985229ebdbaae66be25b2710360f464 (diff)
downloadmidimonster-e131992bbe0893a3e5b79cf9423830ea90b4a4d7.tar.gz
midimonster-e131992bbe0893a3e5b79cf9423830ea90b4a4d7.tar.bz2
midimonster-e131992bbe0893a3e5b79cf9423830ea90b4a4d7.zip
Implement wininput mouse wheel control (Fixes #65)
-rw-r--r--backends/wininput.c56
-rw-r--r--backends/wininput.h2
-rw-r--r--backends/wininput.md15
-rw-r--r--config.c2
4 files changed, 71 insertions, 4 deletions
diff --git a/backends/wininput.c b/backends/wininput.c
index 8926782..6d21a76 100644
--- a/backends/wininput.c
+++ b/backends/wininput.c
@@ -65,9 +65,13 @@ static struct {
//sorted in _start
wininput_request* request;
uint32_t interval;
+ uint64_t wheel, wheel_max, wheel_delta;
+ uint8_t wheel_inverted;
} cfg = {
.requests = 0,
- .interval = 50
+ .interval = 50,
+ .wheel_max = 0xFFFF,
+ .wheel_delta = 1
};
MM_PLUGIN_API int init(){
@@ -120,10 +124,38 @@ static uint32_t wininput_interval(){
}
static int wininput_configure(char* option, char* value){
+ int64_t parameter = 0;
+ char* next_token = NULL;
+
if(!strcmp(option, "interval")){
cfg.interval = strtoul(value, NULL, 0);
return 0;
}
+ else if(!strcmp(option, "wheel")){
+ parameter = strtoll(value, &next_token, 0);
+
+ cfg.wheel_max = parameter;
+ if(parameter < 0){
+ LOG("Inverting mouse wheel data");
+ cfg.wheel_max = -parameter;
+ cfg.wheel_inverted = 1;
+ }
+ else if(!parameter){
+ LOGPF("Invalid mouse wheel configuration %s", value);
+ return 1;
+ }
+
+ if(next_token && *next_token){
+ cfg.wheel = strtoul(next_token, NULL, 0);
+ }
+
+ return 0;
+ }
+ else if(!strcmp(option, "wheeldelta")){
+ cfg.wheel_delta = strtoul(value, NULL, 0);
+ return 0;
+ }
+
LOGPF("Unknown backend configuration option %s", option);
return 1;
@@ -196,6 +228,13 @@ static uint64_t wininput_channel_mouse(instance* inst, char* spec, uint8_t flags
ident.fields.channel = position;
ident.fields.control = 1;
}
+ else if(!strcmp(spec, "wheel")){
+ ident.fields.channel = wheel;
+ if(flags & mmchannel_input){
+ LOG("The mouse wheel can only be used as an output channel");
+ return 0;
+ }
+ }
else{
//check the buttons
for(u = 0; u < sizeof(keys) / sizeof(keys[0]); u++){
@@ -354,7 +393,7 @@ static INPUT wininput_event_mouse(uint8_t channel, uint8_t control, double value
ev.mi.dx = cfg.mouse_x;
ev.mi.dy = cfg.mouse_y;
}
- if(channel == button){
+ else if(channel == button){
switch(control){
case VK_LBUTTON:
flags_up |= MOUSEEVENTF_LEFTUP;
@@ -383,6 +422,15 @@ static INPUT wininput_event_mouse(uint8_t channel, uint8_t control, double value
ev.mi.dwFlags |= flags_up;
}
}
+ else if(channel == wheel){
+ ev.mi.dwFlags |= MOUSEEVENTF_WHEEL;
+ ev.mi.mouseData = ((value * cfg.wheel_max) - cfg.wheel) * cfg.wheel_delta;
+ if(cfg.wheel_inverted){
+ ev.mi.mouseData *= -1;
+ }
+ DBGPF("Moving wheel %d (invert %d) with delta %d: %d", (value * cfg.wheel_max) - cfg.wheel, cfg.wheel_inverted, cfg.wheel_delta, ev.mi.mouseData);
+ cfg.wheel = (value * cfg.wheel_max);
+ }
return ev;
}
@@ -479,6 +527,10 @@ static int wininput_handle(size_t num, managed_fd* fds){
push_event = 1;
}
}
+ else if(cfg.request[u].ident.fields.type == mouse
+ && cfg.request[u].ident.fields.channel == wheel){
+ //ignore wheel requests, can't read that
+ }
else if(cfg.request[u].ident.fields.type == keyboard
|| cfg.request[u].ident.fields.type == mouse){
//check key state
diff --git a/backends/wininput.h b/backends/wininput.h
index 6ec9f46..0939cc3 100644
--- a/backends/wininput.h
+++ b/backends/wininput.h
@@ -22,7 +22,7 @@ enum /*wininput_control_channel*/ {
keypress = 0,
button,
position,
- //wheel, /*relative*/
+ wheel,
key_unicode
};
diff --git a/backends/wininput.md b/backends/wininput.md
index bcf6a1b..87e9321 100644
--- a/backends/wininput.md
+++ b/backends/wininput.md
@@ -11,6 +11,12 @@ access (as is available under Linux) is possible.
This backend does not take any global configuration.
+| Option | Example value | Default value | Description |
+|---------------|-----------------------|-----------------------|---------------------------------------|
+| `interval` | `100` | `50` | Data polling interval in milliseconds. Lower intervals lead to higher CPU load. This value should normally not be changed. |
+| `wheel` | `4000 2000` | `65535 0` | Mouse wheel range and optional initial value. To invert the mouse wheel control, specify the range as a negative integer. As the mouse wheel is a relative control, we need to specify a range incoming absolute values are mapped to. This can be used control the wheel resolution and travel size. |
+| `wheeldelta` | `20` | `1` | Multiplier for wheel travel |
+
#### Instance configuration
This backend does not take any instance-specific configuration.
@@ -30,6 +36,11 @@ as well as one channel per mouse button
* `mouse.xmb1`: Extra mouse button 1
* `mouse.xmb2`: Extra mouse button 2
+The (vertical) mouse wheel can be controlled from the MIDIMonster using the `mouse.wheel` channel, but it can not be used
+as an input channel due to limitations in the Windows API. All instances share one wheel control (see the section on known
+bugs below). The mouse wheel sensitivity can be controlled by adjusting the absolute travel range, its initial value and
+a wheel delta multiplier.
+
All keys that have an [assigned virtual keycode](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes)
are mappable as MIDIMonster channels using the syntax `key.<keyname>`, with *keyname* being one of the following specifiers:
@@ -120,3 +131,7 @@ Some antivirus applications may detect this backend as problematic because it us
interfaces to read keyboard and mouse input as any malicious application would. While it is definitely
possible to configure the MIDIMonster to do malicious things, the code itself does not log anything.
You can verify this by reading the backend code yourself.
+
+Since the Windows input system merges all keyboard/mouse input data into one data stream, using multiple
+instances of this backend is not necessary or useful. It is still supported for technical reasons.
+There may be unexpected side effects when mapping the mouse wheel in multiple instances.
diff --git a/config.c b/config.c
index 9945319..c1c3124 100644
--- a/config.c
+++ b/config.c
@@ -545,7 +545,7 @@ static int config_line(char* line){
//find separator
separator = strchr(line, '=');
if(!separator){
- fprintf(stderr, "Not an assignment: %s\n", line);
+ fprintf(stderr, "Not an assignment (currently expecting %s configuration): %s\n", line, (parser_state == backend_cfg) ? "backend" : "instance");
return 1;
}