-
-
Save daniepetrov/917ffe963c69d6a26a8c05478e733696 to your computer and use it in GitHub Desktop.
mousectl - Swap mouse buttons from the macOS Terminal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// mousectl - Swap mouse buttons from the macOS Terminal | |
// From https://superuser.com/a/1782251 | |
// with changes by [email protected] | |
// Compile: | |
// clang -framework IOKit -framework Foundation -o mousectl mousectl.c | |
#include <IOKit/hidsystem/IOHIDLib.h> | |
#include <IOKit/hidsystem/IOHIDParameter.h> | |
#include <IOKit/hidsystem/event_status_driver.h> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
static char *describe(IOHIDButtonModes mode) { | |
switch (mode) { | |
case kIOHIDButtonMode_BothLeftClicks: // 0 | |
return "Both Left Clicks"; | |
case kIOHIDButtonMode_ReverseLeftRightClicks: // 1 | |
return "Reverse Left Right Clicks"; | |
case kIOHIDButtonMode_EnableRightClick: // 2 | |
return "Enable Right Click"; | |
default: | |
return "<unknown>"; | |
} | |
} | |
static bool GetButtonMode(io_connect_t handle, IOHIDButtonModes *mode) { | |
kern_return_t ret; | |
IOByteCount actualSize; | |
ret = IOHIDGetParameter(handle, CFSTR(kIOHIDPointerButtonMode), sizeof *mode, | |
mode, &actualSize); | |
if (ret != KERN_SUCCESS) { | |
fprintf(stderr, "Error! IOHIDGetParameter failed: %d.\n", ret); | |
return false; | |
} | |
if (actualSize != sizeof *mode) { | |
// TODO: maybe currentButtonStatus should be void* with an explicit cast | |
// to IOHIDButtonModes | |
fprintf( | |
stderr, | |
"Warning! IOHIDGetParameter returned unexpected actualSize! (Got %d; " | |
"wanted %ld)\n", | |
(int)actualSize, sizeof *mode); | |
} | |
return true; | |
} | |
static bool SetButtonMode(io_connect_t handle, IOHIDButtonModes newMode) { | |
kern_return_t ret; | |
IOByteCount actualSize; | |
ret = IOHIDSetParameter(handle, CFSTR(kIOHIDPointerButtonMode), &newMode, | |
sizeof newMode); | |
if (ret != KERN_SUCCESS) { | |
fprintf(stderr, "Error! IOHIDSetParameter failed: %d\n", ret); | |
return ret; | |
} | |
return true; | |
} | |
static int print(io_connect_t handle) { | |
IOHIDButtonModes buttonMode; | |
if (!GetButtonMode(handle, &buttonMode)) | |
return 1; | |
printf("Current mouse button mode: %s\n", describe(buttonMode)); | |
return 0; | |
} | |
static int swap(io_connect_t handle) { | |
IOHIDButtonModes currentButtonStatus; | |
if (!GetButtonMode(handle, ¤tButtonStatus)) | |
return 1; | |
IOHIDButtonModes newButtonStatus; | |
switch (currentButtonStatus) { | |
case kIOHIDButtonMode_BothLeftClicks: // 0 | |
case kIOHIDButtonMode_ReverseLeftRightClicks: // 1 | |
newButtonStatus = kIOHIDButtonMode_EnableRightClick; | |
break; | |
case kIOHIDButtonMode_EnableRightClick: // 2 | |
newButtonStatus = kIOHIDButtonMode_ReverseLeftRightClicks; | |
break; | |
default: | |
fprintf(stderr, "Unknown IOHIDButtonModes value: %d\n", | |
currentButtonStatus); | |
return 1; | |
} | |
if (!SetButtonMode(handle, newButtonStatus)) | |
return 1; | |
printf("New mouse button mode is : %s\n", describe(newButtonStatus)); | |
printf("Old mouse button mode was: %s\n", describe(currentButtonStatus)); | |
return 0; | |
} | |
static char cmd[] = "mousectl"; | |
static int usage(bool helpWanted) { | |
FILE *fp = helpWanted ? stdout : stderr; | |
fprintf(fp, "Usage: %s <subcommand>\n\n", cmd); | |
fprintf(fp, "%s\n", "Subcommands:"); | |
fprintf(fp, "%s\n", "\tprint Prints the current mouse button mode."); | |
fprintf(fp, "%s\n", "\tswap Swaps mouse buttons."); | |
fprintf(fp, "%s\n", "\thelp Prints this usage."); | |
return helpWanted ? 0 : 1; | |
} | |
int main(int argc, char *argv[]) { | |
if (argc <= 0) | |
return 42; | |
if (argc == 1) | |
return usage(false); | |
char *subcmd = argv[1]; | |
int (*sub)(io_connect_t); | |
if (strcmp("print", subcmd) == 0) { | |
sub = print; | |
} else if (strcmp("swap", subcmd) == 0) { | |
sub = swap; | |
} else if (strcmp("help", subcmd) == 0 || strcmp("-h", subcmd) == 0 || | |
strcmp("-help", subcmd) == 0 || strcmp("--help", subcmd) == 0 || | |
strcmp("/?", subcmd) == 0) { | |
return usage(true); | |
} else { | |
fprintf(stderr, "Error! Unrecognized subcommand: %s\n", subcmd); | |
return usage(false); | |
} | |
io_connect_t handle = NXOpenEventStatus(); | |
if (!handle) { | |
fprintf(stderr, "%s\n", "NXOpenEventStatus failed!"); | |
return 1; | |
} | |
int ret = sub(handle); | |
NXCloseEventStatus(handle); | |
return ret; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment