diff --git a/.gitignore b/.gitignore index d80e300..7585dc4 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ !modules/ !modules/**/ +!modules/darwin/paperwm/*.c !flake.lock diff --git a/modules/darwin/paperwm.nix b/modules/darwin/paperwm/default.nix similarity index 97% rename from modules/darwin/paperwm.nix rename to modules/darwin/paperwm/default.nix index b83e2d6..bac2ccd 100644 --- a/modules/darwin/paperwm.nix +++ b/modules/darwin/paperwm/default.nix @@ -64,6 +64,7 @@ in { AppWindowGroupingBehavior = false; # Show them one at a a time. }; + home-manager.sharedModules = [{ xdg.configFile."hammerspoon/Spoons/PaperWM.spoon" = { recursive = true; @@ -135,7 +136,7 @@ in { return current_index end - local changeSpaceBy = function(offset) + local __changeSpaceByHorriblySlowly = function(offset) local current_index = currentSpaceIndex() local spaces = hs.spaces.allSpaces()[hs.screen.mainScreen():getUUID()] @@ -155,6 +156,14 @@ in { hs.spaces.gotoSpace(next_space) end + local changeSpaceBy = function(offset) + local command = "${lib.getExe pkgs.fast-workspace-switch} " .. (offset > 0 and "right" or "left") + + for n = 1, math.abs(offset) do + os.execute(command) + end + end + local gotoSpace = function(index) local current_index = currentSpaceIndex() local change_by = index - current_index diff --git a/modules/darwin/paperwm/fast-workspace-switch.c b/modules/darwin/paperwm/fast-workspace-switch.c new file mode 100644 index 0000000..27870d9 --- /dev/null +++ b/modules/darwin/paperwm/fast-workspace-switch.c @@ -0,0 +1,84 @@ +#include +#include + +#define FLOAT_MIN 1.401298464324817e-45 + +void workingSpaceSwitch(int direction) { + double magnitude = direction == 0 ? -2.25 : 2.25; + double gestureValue = 200.0 * magnitude; + + CGEventRef event1a = CGEventCreate(NULL); + CGEventSetIntegerValueField(event1a, 0x37, 29); + CGEventSetIntegerValueField(event1a, 0x29, 33231); + + CGEventRef event1b = CGEventCreate(NULL); + CGEventSetIntegerValueField(event1b, 0x37, 30); + CGEventSetIntegerValueField(event1b, 0x6E, 23); + CGEventSetIntegerValueField(event1b, 0x84, 1); + CGEventSetIntegerValueField(event1b, 0x86, 1); + CGEventSetDoubleValueField(event1b, 0x7C, magnitude); + + float magnitudeAsFloat = (float)magnitude; + int32_t magnitudeAsInt = *(int32_t *)&magnitudeAsFloat; + CGEventSetIntegerValueField(event1b, 0x87, magnitudeAsInt); + + CGEventSetIntegerValueField(event1b, 0x7B, 1); + CGEventSetIntegerValueField(event1b, 0xA5, 1); + CGEventSetDoubleValueField(event1b, 0x77, FLOAT_MIN); + CGEventSetDoubleValueField(event1b, 0x8B, FLOAT_MIN); + CGEventSetIntegerValueField(event1b, 0x29, 33231); + CGEventSetIntegerValueField(event1b, 0x88, 0); + + CGEventPost(kCGHIDEventTap, event1b); + CGEventPost(kCGHIDEventTap, event1a); + + CFRelease(event1a); + CFRelease(event1b); + + usleep(15000); // 15ms + + CGEventRef event2a = CGEventCreate(NULL); + CGEventSetIntegerValueField(event2a, 0x37, 29); + CGEventSetIntegerValueField(event2a, 0x29, 33231); + + CGEventRef event2b = CGEventCreate(NULL); + CGEventSetIntegerValueField(event2b, 0x37, 30); + CGEventSetIntegerValueField(event2b, 0x6E, 23); + CGEventSetIntegerValueField(event2b, 0x84, 4); + CGEventSetIntegerValueField(event2b, 0x86, 4); + CGEventSetDoubleValueField(event2b, 0x7C, magnitude); + CGEventSetIntegerValueField(event2b, 0x87, magnitudeAsInt); + CGEventSetIntegerValueField(event2b, 0x7B, 1); + CGEventSetIntegerValueField(event2b, 0xA5, 1); + CGEventSetDoubleValueField(event2b, 0x77, FLOAT_MIN); + CGEventSetDoubleValueField(event2b, 0x8B, FLOAT_MIN); + CGEventSetIntegerValueField(event2b, 0x29, 33231); + CGEventSetIntegerValueField(event2b, 0x88, 0); + + CGEventSetDoubleValueField(event2b, 0x81, gestureValue); + CGEventSetDoubleValueField(event2b, 0x82, gestureValue); + + CGEventPost(kCGHIDEventTap, event2b); + CGEventPost(kCGHIDEventTap, event2a); + + CFRelease(event2a); + CFRelease(event2b); +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + if (strcmp(argv[1], "right") == 0) { + workingSpaceSwitch(1); + } else if (strcmp(argv[1], "left") == 0) { + workingSpaceSwitch(0); + } else { + fprintf(stderr, "Invalid argument: %s (use 'left' or 'right')\n", argv[1]); + return 1; + } + + return 0; +} diff --git a/modules/darwin/paperwm/fast-workspace-switch.nix b/modules/darwin/paperwm/fast-workspace-switch.nix new file mode 100644 index 0000000..3d0cfc7 --- /dev/null +++ b/modules/darwin/paperwm/fast-workspace-switch.nix @@ -0,0 +1,29 @@ +{ + nixpkgs.overlays = [(self: super: { + fast-workspace-switch = self.stdenv.mkDerivation (finalAttrs: { + pname = "fast-workspace-switch"; + version = "1.0.0"; + src = ./.; + + dontConfigure = true; + + buildPhase = '' + $CC -O2 -Wall -Wextra \ + -framework CoreGraphics \ + -framework CoreFoundation \ + -o ${finalAttrs.pname} ${finalAttrs.pname}.c + ''; + + installPhase = '' + mkdir -p $out/bin + install -m755 ${finalAttrs.pname} $out/bin/ + ''; + + meta = { + description = "Fast workspace switcher for macOS"; + platforms = self.lib.platforms.darwin; + mainProgram = finalAttrs.pname; + }; + }); + })]; +}