Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raise only on change screen #44

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 65 additions & 31 deletions AutoRaise.mm
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#include <Carbon/Carbon.h>
#include <libproc.h>

#define AUTORAISE_VERSION "3.5"
#define AUTORAISE_VERSION "3.6"
#define STACK_THRESHOLD 20

#define __MAC_11_06_0 110600
Expand Down Expand Up @@ -57,10 +57,6 @@
static CGPoint oldCorrectedPoint = {0, 0};
#endif

// Lowering the polling interval increases responsiveness, but steals more cpu
// cycles. A workable, yet responsible value seems to be about 50 microseconds.
#define POLLING_MS 50

// An activate delay of about 10 microseconds is just high enough to ensure we always
// find the latest focused (main)window. This value should be kept as low as possible.
#define ACTIVATE_DELAY_MS 10
Expand Down Expand Up @@ -98,6 +94,7 @@
#endif

CFMachPortRef eventTap = NULL;
static NSScreen * previousScreen = NULL;
static char pathBuffer[PROC_PIDPATHINFO_MAXSIZE];
static bool activated_by_task_switcher = false;
static AXUIElementRef _accessibility_object = AXUIElementCreateSystemWide();
Expand All @@ -113,9 +110,11 @@
static const NSString * NoTitle = @"";
static CGPoint desktopOrigin = {0, 0};
static CGPoint oldPoint = {0, 0};
static bool ignoreSpaceChanged = false;
static bool spaceHasChanged = false;
static bool appWasActivated = false;
static bool altTaskSwitcher = false;
static bool onScreenChangedOnly = true;
static bool warpMouse = false;
static bool verbose = false;
static float warpX = 0.5;
Expand All @@ -127,6 +126,7 @@
static int raiseTimes = 0;
static int delayTicks = 0;
static int delayCount = 0;
static int pollMillis = 0;
#ifdef FOCUS_FIRST
static int raiseDelayCount = 0;
#endif
Expand Down Expand Up @@ -526,7 +526,6 @@ inline bool main_window(AXUIElementRef _window) {
}
#endif

#if MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_12_00_0
inline NSScreen * findScreen(CGPoint point) {
NSScreen * main_screen = NSScreen.screens[0];
point.y = NSMaxY(main_screen.frame) - point.y;
Expand All @@ -537,7 +536,19 @@ inline bool main_window(AXUIElementRef _window) {
}
return NULL;
}
#endif

inline bool screenChanged(CGPoint point) {
bool changed = false;
NSScreen * screen = findScreen(point);
if (screen) {
changed = previousScreen != screen;
previousScreen = screen;
}

if (verbose && changed) { NSLog(@"screen changed"); }
return changed;
}

//-----------------------------------------------notifications----------------------------------------------

void spaceChanged();
Expand Down Expand Up @@ -613,10 +624,10 @@ - (void)onTick:(NSNumber *)timerInterval {

#ifdef FOCUS_FIRST
- (void)windowFocused:(AXUIElementRef)_window {
if (verbose) { NSLog(@"Window focused, waiting %0.3fs", raiseDelayCount*POLLING_MS/1000.0); }
if (verbose) { NSLog(@"Window focused, waiting %0.3fs", raiseDelayCount*pollMillis/1000.0); }
[self performSelector: @selector(onWindowFocused:)
withObject: [NSNumber numberWithUnsignedLong: (uint64_t) _window]
afterDelay: raiseDelayCount*POLLING_MS/1000.0];
afterDelay: raiseDelayCount*pollMillis/1000.0];
}

- (void)onWindowFocused:(NSNumber *)_window {
Expand All @@ -635,13 +646,15 @@ - (void)onWindowFocused:(NSNumber *)_window {
const NSString *kScale = @"scale";
const NSString *kVerbose = @"verbose";
const NSString *kAltTaskSwitcher = @"altTaskSwitcher";
const NSString *kIgnoreSpaceChanged = @"ignoreSpaceChanged";
const NSString *kIgnoreApps = @"ignoreApps";
const NSString *kMouseDelta = @"mouseDelta";
const NSString *kPollMillis = @"pollMillis";
#ifdef FOCUS_FIRST
const NSString *kFocusDelay = @"focusDelay";
NSArray *parametersDictionary = @[kDelay, kWarpX, kWarpY, kScale, kVerbose, kAltTaskSwitcher, kFocusDelay, kIgnoreApps, kMouseDelta];
NSArray *parametersDictionary = @[kDelay, kWarpX, kWarpY, kScale, kVerbose, kAltTaskSwitcher, kFocusDelay, kIgnoreSpaceChanged, kIgnoreApps, kMouseDelta, kPollMillis];
#else
NSArray *parametersDictionary = @[kDelay, kWarpX, kWarpY, kScale, kVerbose, kAltTaskSwitcher, kIgnoreApps, kMouseDelta];
NSArray *parametersDictionary = @[kDelay, kWarpX, kWarpY, kScale, kVerbose, kAltTaskSwitcher, kIgnoreSpaceChanged, kIgnoreApps, kMouseDelta, kPollMillis];
#endif
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];

Expand Down Expand Up @@ -744,6 +757,7 @@ - (void) validateParameters {
#endif
parameters[kDelay] = @"1";
}
if ([parameters[kPollMillis] intValue] < 20) { parameters[kPollMillis] = @"50"; }
if ([parameters[kMouseDelta] floatValue] < 0) { parameters[kMouseDelta] = @"0"; }
if ([parameters[kScale] floatValue] < 1) { parameters[kScale] = @"2.0"; }
warpMouse =
Expand Down Expand Up @@ -911,8 +925,10 @@ void onTick() {
// spaceHasChanged has priority
// over waiting for the delay
if (mouseMoved) { return; }
raiseTimes = 3;
delayTicks = 0;
else if (!ignoreSpaceChanged) {
raiseTimes = 3;
delayTicks = 0;
}
spaceHasChanged = false;
} else if (delayTicks && mouseMoved) {
delayTicks = 0;
Expand Down Expand Up @@ -947,6 +963,13 @@ void onTick() {

AXUIElementRef _mouseWindow = get_mousewindow(mousePoint);
if (_mouseWindow) {
if (onScreenChangedOnly && (raiseTimes || delayCount == 1 || delayTicks == 1) &&
!desktop_window(_mouseWindow) && !screenChanged(mousePoint)) {
CFRelease(_mouseWindow);
raiseTimes = 0;
delayTicks = 0;
return;
}
pid_t mouseWindow_pid;
if (AXUIElementGetPid(_mouseWindow, &mouseWindow_pid) == kAXErrorSuccess) {
bool needs_raise = true;
Expand Down Expand Up @@ -1089,51 +1112,62 @@ CGEventRef eventTapHandler(CGEventTapProxy proxy, CGEventType type, CGEventRef e

int main(int argc, const char * argv[]) {
@autoreleasepool {
ConfigClass * config = [[ConfigClass alloc] init];
[config readConfig: argc];
[config validateParameters];

delayCount = [parameters[kDelay] intValue];
warpX = [parameters[kWarpX] floatValue];
warpY = [parameters[kWarpY] floatValue];
cursorScale = [parameters[kScale] floatValue];
verbose = [parameters[kVerbose] boolValue];
altTaskSwitcher = [parameters[kAltTaskSwitcher] boolValue];
mouseDelta = [parameters[kMouseDelta] floatValue];
pollMillis = [parameters[kPollMillis] intValue];
ignoreSpaceChanged = [parameters[kIgnoreSpaceChanged] boolValue];

printf("\nv%s by sbmpost(c) 2022, usage:\n\nAutoRaise\n", AUTORAISE_VERSION);
printf(" -delay <0=no-raise, 1=no-delay, 2=%dms, 3=%dms, ...>\n", POLLING_MS, POLLING_MS*2);
printf(" -pollMillis <20, 30, 40, 50, ...>\n");
printf(" -delay <0=no-raise, 1=no-delay, 2=%dms, 3=%dms, ...>\n", pollMillis, pollMillis*2);
#ifdef FOCUS_FIRST
printf(" -focusDelay <0=no-focus, 1=no-delay, 2=%dms, 3=%dms, ...>\n", POLLING_MS, POLLING_MS*2);
printf(" -focusDelay <0=no-focus, 1=no-delay, 2=%dms, 3=%dms, ...>\n", pollMillis, pollMillis*2);
#endif
printf(" -warpX <0.5> -warpY <0.5> -scale <2.0>\n");
printf(" -altTaskSwitcher <true|false>\n");
printf(" -ignoreSpaceChanged <true|false>\n");
printf(" -ignoreApps \"<App1,App2, ...>\"\n");
printf(" -mouseDelta <0.1>\n");
printf(" -verbose <true|false>\n\n");

ConfigClass * config = [[ConfigClass alloc] init];
[config readConfig: argc];
[config validateParameters];

delayCount = [parameters[kDelay] intValue];
warpX = [parameters[kWarpX] floatValue];
warpY = [parameters[kWarpY] floatValue];
cursorScale = [parameters[kScale] floatValue];
verbose = [parameters[kVerbose] boolValue];
altTaskSwitcher = [parameters[kAltTaskSwitcher] boolValue];
mouseDelta = [parameters[kMouseDelta] floatValue];

NSMutableArray * ignore;
if (parameters[kIgnoreApps]) {
ignore = [[NSMutableArray alloc] initWithArray:
[parameters[kIgnoreApps] componentsSeparatedByString:@","]];
} else { ignore = [[NSMutableArray alloc] init]; }

printf("Started with:\n");
printf(" * pollMillis: %dms\n", pollMillis);
if (delayCount) {
printf(" * delay: %dms\n", (delayCount-1)*POLLING_MS);
printf(" * delay: %dms\n", (delayCount-1)*pollMillis);
} else {
printf(" * delay: disabled\n");
}
#ifdef FOCUS_FIRST
if ([parameters[kFocusDelay] intValue]) {
raiseDelayCount = delayCount;
delayCount = [parameters[kFocusDelay] intValue];
printf(" * focusDelay: %dms\n", (delayCount-1)*POLLING_MS);
} else { raiseDelayCount = 1; }
printf(" * focusDelay: %dms\n", (delayCount-1)*pollMillis);
} else {
raiseDelayCount = 1;
printf(" * focusDelay: disabled\n");
}
#endif
if (warpMouse) {
printf(" * warpX: %.1f, warpY: %.1f, scale: %.1f\n", warpX, warpY, cursorScale);
printf(" * altTaskSwitcher: %s\n", altTaskSwitcher ? "true" : "false");
}

printf(" * ignoreSpaceChanged: %s\n", ignoreSpaceChanged ? "true" : "false");
for (id ignoreApp in ignore) {
printf(" * ignoreApp: %s\n", [ignoreApp UTF8String]);
}
Expand Down Expand Up @@ -1185,7 +1219,7 @@ int main(int argc, const char * argv[]) {
#else
if (altTaskSwitcher || delayCount) {
#endif
[workspaceWatcher onTick: [NSNumber numberWithFloat: POLLING_MS/1000.0]];
[workspaceWatcher onTick: [NSNumber numberWithFloat: pollMillis/1000.0]];
}

_dock_app = findDockApplication();
Expand Down
2 changes: 1 addition & 1 deletion Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<key>CFBundleGetInfoString</key>
<string>Copyright © 2022 sbmpost</string>
<key>CFBundleShortVersionString</key>
<string>3.5</string>
<string>3.6</string>
<key>CFBundleIconFile</key>
<string>AutoRaise</string>
<key>CFBundleName</key>
Expand Down
27 changes: 19 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,15 @@ can only be stopped via "Activity Monitor" or the AppleScript provided near the

**Command line usage:**

./AutoRaise -delay 1 -focusDelay 0 -warpX 0.5 -warpY 0.1 -scale 2.5 -altTaskSwitcher false -ignoreApps "App1,App2" -mouseDelta 0.1
./AutoRaise -pollMillis 50 -delay 1 -focusDelay 0 -warpX 0.5 -warpY 0.1 -scale 2.5 -altTaskSwitcher false -ignoreSpaceChanged false -ignoreApps "App1,App2" -mouseDelta 0.1

*Note*: focusDelay is only supported when compiled with the "EXPERIMENTAL_FOCUS_FIRST" flag.

- delay: Raise delay, specified in units of 50ms. Disabled if 0. A delay > 1 requires the mouse to stop for a moment before raising.
- pollMillis: How often to poll the mouse position and consider a raise/focus. Lower values increase responsiveness but also CPU load. Default = 50

- focusDelay: Focus delay, specified in units of 50ms. Disabled if 0. A delay > 1 requires the mouse to stop for a moment before focusing.
- delay: Raise delay, specified in units of pollMillis. Disabled if 0. A delay > 1 requires the mouse to stop for a moment before raising.

- focusDelay: Focus delay, specified in units of pollMillis. Disabled if 0. A delay > 1 requires the mouse to stop for a moment before focusing.

- warpX: A Factor between 0 and 1. Makes the mouse jump horizontally to the activated window. By default disabled.

Expand All @@ -71,6 +73,8 @@ can only be stopped via "Activity Monitor" or the AppleScript provided near the

- altTaskSwitcher: Set to true if you use 3rd party tools to switch between applications (other than standard command-tab).

- ignoreSpaceChanged: Do not immediately raise/focus after a space change. The default is false.

- ignoreApps: Comma separated list of apps for which you would like to disable focus/raise.

- mouseDelta: Requires the mouse to move a certain distance. 0.0 = most sensitive whereas higher values decrease sensitivity.
Expand All @@ -79,12 +83,14 @@ AutoRaise can read these parameters from a configuration file. To make this happ
**~/.config/AutoRaise/config** file. The format is as follows:

#AutoRaise config file
pollMillis=50
delay=1
focusDelay=0
warpX=0.5
warpY=0.1
scale=2.5
altTaskSwitcher=false
ignoreSpaceChanged=false
ignoreApps="App1,App2"
mouseDelta=0.1

Expand Down Expand Up @@ -133,21 +139,26 @@ like so:

The output should look something like this:

v3.5 by sbmpost(c) 2022, usage:
v3.6 by sbmpost(c) 2022, usage:

AutoRaise
-pollMillis <20, 30, 40, 50, ...>
-delay <0=no-raise, 1=no-delay, 2=50ms, 3=100ms, ...>
-focusDelay <0=no-focus, 1=no-delay, 2=50ms, 3=100ms, ...>
-warpX <0.5> -warpY <0.5> -scale <2.0>
-altTaskSwitcher <true|false>
-ignoreSpaceChanged <true|false>
-ignoreApps "<App1,App2, ...>"
-mouseDelta <0.1>
-verbose <true|false>

Started with:
* pollMillis: 50ms
* delay: 0ms
* focusDelay: disabled
* warpX: 0.5, warpY: 0.1, scale: 2.5
* altTaskSwitcher: false
* ignoreSpaceChanged: false
* ignoreApp: App1
* ignoreApp: App2
* mouseDelta: 0.1
Expand All @@ -157,10 +168,10 @@ The output should look something like this:
* OLD_ACTIVATION_METHOD
* EXPERIMENTAL_FOCUS_FIRST

2022-08-06 00:37:22.187 AutoRaise[64697:2574991] AXIsProcessTrusted: YES
2022-08-06 00:37:22.209 AutoRaise[64697:2574991] System cursor scale: 1.000000
2022-08-06 00:37:22.225 AutoRaise[64697:2574991] Got run loop source: YES
2022-08-06 00:37:22.226 AutoRaise[64697:2574991] Registered app activated selector
2022-09-02 22:40:50.498 AutoRaise[60894:1255026] AXIsProcessTrusted: YES
2022-09-02 22:40:50.518 AutoRaise[60894:1255026] System cursor scale: 1.000000
2022-09-02 22:40:50.533 AutoRaise[60894:1255026] Got run loop source: YES
2022-09-02 22:40:50.533 AutoRaise[60894:1255026] Registered app activated selector
2022-08-06 00:37:22.273 AutoRaise[64697:2574991] Desktop origin (-1280.000000, 0.000000)
...
...
Expand Down