Change to a notification based approach to getting the focused app's name

This commit is contained in:
2026-03-23 19:30:57 -07:00
parent 80b93bdb1c
commit bec64b4291

View File

@@ -1,6 +1,6 @@
import signal, sys
import signal, sys, objc
from AppKit import NSWorkspace
from Foundation import NSRunLoop, NSDate
from Foundation import NSRunLoop, NSDate, NSObject
import hid
VID, PID = 0x3384, 0x0009
@@ -20,47 +20,60 @@ def send_app_name(dev, name):
dev.write(data)
dev.read(32, timeout=1000)
class AppObserver(NSObject):
def init(self):
self = objc.super(AppObserver, self).init()
self.dev = None
self.last_app = None
self.current_app = NSWorkspace.sharedWorkspace().frontmostApplication().localizedName()
return self
def appChanged_(self, notification):
app = notification.userInfo()["NSWorkspaceApplicationKey"].localizedName()
self.current_app = app
if self.dev is not None:
self.last_app = app
print(f"App: {app}")
try:
send_app_name(self.dev, app)
except Exception:
print("Keyboard disconnected")
self.dev = None
self.last_app = None
def main():
signal.signal(signal.SIGINT, lambda *_: sys.exit(0))
ws = NSWorkspace.sharedWorkspace()
dev = None
last_app = None
observer = AppObserver.alloc().init()
ws.notificationCenter().addObserver_selector_name_object_(
observer, "appChanged:", "NSWorkspaceDidActivateApplicationNotification", None
)
while True:
connected = find_keyboard_path() is not None
# Detect disconnect
if dev is not None and not connected:
if observer.dev is not None and not connected:
print("Keyboard disconnected")
dev = None
last_app = None
observer.dev = None
observer.last_app = None
# Connect and send current app
if dev is None and connected:
if observer.dev is None and connected:
try:
dev = hid.Device(path=find_keyboard_path())
observer.dev = hid.Device(path=find_keyboard_path())
print("Keyboard connected")
last_app = ws.frontmostApplication().localizedName()
print(f"App: {last_app}")
send_app_name(dev, last_app)
observer.last_app = observer.current_app
print(f"App: {observer.current_app}")
send_app_name(observer.dev, observer.current_app)
except Exception:
dev = None
# App change
if dev is not None:
app = ws.frontmostApplication().localizedName()
if app != last_app:
print(f"App: {app}")
last_app = app
try:
send_app_name(dev, app)
except Exception:
print("Keyboard disconnected")
dev = None
last_app = None
observer.dev = None
# Pump run loop — notifications fire here and send immediately;
# 2s is enough for connect/disconnect detection
NSRunLoop.currentRunLoop().runUntilDate_(
NSDate.dateWithTimeIntervalSinceNow_(0.25)
NSDate.dateWithTimeIntervalSinceNow_(2.0)
)
if __name__ == "__main__":