Mouse Clicker Macro

Trying to write a macro that repeats the left mouse button when I hold the butterfly key down. Remapping that key to MouseBtnL lets me use it like fn-f, but that holds down while the key is pressed and releases when the key is released.

I tried to be cheeky by calling the macro D(MouseBtnL). While that gives me the functionality I want when I call it on a key (keypress, slight delay, continually toggling keypress while the the key is held down), that macro doesn’t seem to work on MouseBtnL.

Trying to define it using

static void clickerMacro(uint8_t keyState) {
if (keyToggledOn(keyState))
Key_MouseBtnL;
}

was also a bust.

I’m well past the limits of my competence here (only ever written short programs in python…) so don’t know where to look next. I’m guessing this is because the mouse key functions are defined and treated differently to the keyboard ones, but I can’t work out what that difference is and how to work around by reading the source code.

Can anyone point me in the right direction?

I can see that Mouse.cpp defines a function on line 87 that seems to do what I need, but I’ve got no idea how to call it:

void Mouse_::click(uint8_t b) {
press(b);
sendReport();
release(b);
}

You can call it like this:

kaleidoscope::hid::clickMouseButtons(MOUSE_LEFT)
1 Like

so, looking at xev the macro:

static void clickerMacro(uint8_t keyState) {
if (keyIsPressed(keyState))
kaleidoscope::hid::clickMouseButtons(MOUSE_LEFT);
}

Causes a mousedown event, a mouseup event, a mousedown event on the keypress, then a further mouseup event on the key release. That is, after the initial click, it holds down the button until the key gets released.

By contrast changing the VERSION_INFO macro to the same;

static void versionInfoMacro(uint8_t keyState) {
if (keyIsPressed(keyState)) {
Macros.type(PSTR("Keyboardio Model 01 - Kaleidoscope "));
Macros.type(PSTR(BUILD_INFORMATION));
}
}

Causes the string to be printed continuously while the key is held down. (interestingly, maybe 5-10% of the time, the string will print incorrectly in some way, but that’s not really an issue for me.) So it seems like there’s a difference between the way the firmware handles KeyPress events and Mouse events.

As noted above, this is literally the first time I’ve even looked at C++, so I’m in way over my head. That said, I found a code snippet in Mouse.cpp at line 187:

void Mouse_::sendReport(void) {
// If the last report is different than the current report, then we need to send a report.
// We guard sendReport like this so that calling code doesn’t end up spamming the host with empty reports
// if sendReport is called in a tight loop.
// if the two reports are the same, check if they’re empty, and return early
// without a report if they are.
static HID_MouseReport_Data_t emptyReport;
if (memcmp(&lastReport, &report, sizeof(report)) == 0 &&
memcmp(&report, &emptyReport, sizeof(report)) == 0)
return;

sendReportUnchecked();
memcpy(&lastReport, &report, sizeof(report));
}

The code for MouseClick is at line 83:

void Mouse_::click(uint8_t b) {
press(b);
sendReport();
release(b);
}

That seems to send a report only after calling press. Is the later block of code getting two identical reports, then sending off a blank report? Would changing the MouseClick function to:

void Mouse_::click(uint8_t b) {
press(b);
sendReport();
release(b);
sendReport();
}

make any difference? I tried changing it in my libraries and nothing changed, but I genuinely have no idea whether that then gets flashed to the keyboard, or whether it’s just the .ino file!

Anyone have any suggestions?

Update;

so, trying to force it with a do while loop doesn’t work. At all.

static void clickerMacro(uint8_t keyState) {
  do {
    kaleidoscope::hid::clickMouseButtons(MOUSE_LEFT);
  } while (keyIsPressed(keyState));

}

and similar variations on the loop cause the mouseclick to fire once, then then entire keyboard will freeze up until it’s unplugged.

So; don’t do that.