// mousectl - Swap mouse buttons from the macOS Terminal // From https://superuser.com/a/1782251 // with changes by taeber@rapczak.com // Compile: // clang -framework IOKit -framework Foundation -o mousectl mousectl.c #include #include #include #include #include #include #include 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 ""; } } 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 \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; }