Skip to content

Commit

Permalink
fix: improve key repeat-rate when held (closes #2026)
Browse files Browse the repository at this point in the history
  • Loading branch information
lwouis committed Nov 2, 2022
1 parent c9fd9a2 commit 1821dea
Show file tree
Hide file tree
Showing 4 changed files with 11 additions and 5 deletions.
5 changes: 3 additions & 2 deletions src/logic/KeyRepeatTimer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class KeyRepeatTimer {

static func toggleRepeatingKeyPreviousWindow() {
if let shortcut = ControlsTab.shortcuts["previousWindowShortcut"],
// events already repeat when using a shortcut with a keycode; no need for artificial repeat
shortcut.shortcut.keyCode == .none {
toggleRepeatingKey(shortcut) {
App.app.previousWindowShortcutWithRepeatingKey()
Expand All @@ -23,7 +24,7 @@ class KeyRepeatTimer {
}

private static func toggleRepeatingKey(_ atShortcut: ATShortcut, _ block: @escaping () -> Void) {
if (timer == nil || !timer!.isValid) {
if ((timer == nil || !timer!.isValid) && atShortcut.state != .up) {
let repeatRate = ticksToSeconds(defaults.string(forKey: "KeyRepeat") ?? "6")
let initialDelay = ticksToSeconds(defaults.string(forKey: "InitialKeyRepeat") ?? "25")
timer = Timer(fire: Date(timeIntervalSinceNow: initialDelay), interval: repeatRate, repeats: true, block: { _ in
Expand All @@ -40,6 +41,6 @@ class KeyRepeatTimer {
}

private static func ticksToSeconds(_ appleNumber: String) -> Double {
return Double(appleNumber)! / 60
return Double(appleNumber)! / 60 // Apple probably hard-coupled key repeat-rate with 60hz monitors
}
}
1 change: 0 additions & 1 deletion src/logic/Windows.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ class Windows {
let nextIndex = windowIndexAfterCycling(step)
if ((step > 0 && nextIndex < focusedWindowIndex) || (step < 0 && nextIndex > focusedWindowIndex)) &&
(KeyRepeatTimer.isARepeat || KeyRepeatTimer.timer?.isValid ?? false) {
KeyRepeatTimer.timer?.invalidate()
return
}
updateFocusedWindowIndex(nextIndex)
Expand Down
1 change: 0 additions & 1 deletion src/ui/main-window/ThumbnailsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ class ThumbnailsView: NSVisualEffectView {
let nextRow_ = nextRow < 0 ? rows.count + nextRow : nextRow
if ((step > 0 && nextRow_ < currentRow) || (step < 0 && nextRow_ > currentRow)) &&
(KeyRepeatTimer.isARepeat || KeyRepeatTimer.timer?.isValid ?? false) {
KeyRepeatTimer.timer?.invalidate()
return nil
}
return rows[nextRow_]
Expand Down
9 changes: 8 additions & 1 deletion src/ui/preferences-window/tabs/GeneralTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class GeneralTab {
App.app.restart()
}

// add/remove plist file in ~/Library/LaunchAgents/ depending on the checkbox state
/// add/remove plist file in ~/Library/LaunchAgents/ depending on the checkbox state
static func startAtLoginCallback(_ sender: NSControl) {
var launchAgentsPath = (try? FileManager.default.url(for: .libraryDirectory, in: .userDomainMask, appropriateFor: nil, create: false)) ?? URL.init(fileURLWithPath: "~/Library", isDirectory: true)
launchAgentsPath.appendPathComponent("LaunchAgents", isDirectory: true)
Expand All @@ -49,12 +49,19 @@ class GeneralTab {
launchAgentsPath.appendPathComponent("com.lwouis.alt-tab-macos.plist", isDirectory: false)
if (sender as! NSButton).state == .on {
// docs: https://developer.apple.com/library/archive/technotes/tn2083/_index.html#//apple_ref/doc/uid/DTS10003794-CH1-SECTION23
// docs: man launchd.plist
let plist: NSDictionary = [
"Label": App.id,
"Program": Bundle.main.executablePath ?? "/Applications/\(App.name).app/Contents/MacOS/\(App.name)",
"RunAtLoad": true,
"LimitLoadToSessionType": "Aqua",
"AssociatedBundleIdentifiers": App.id,
// "ProcessType: If left unspecified, the system will apply light resource limits to the job,
// throttling its CPU usage and I/O bandwidth"
"ProcessType": "Interactive",
// "LegacyTimers": If this key is set to true, timers created by the job will opt into less
// efficient but more precise behavior and not be coalesced with other timers.
"LegacyTimers": true,
]
plist.write(to: launchAgentsPath, atomically: true)
} else {
Expand Down

0 comments on commit 1821dea

Please sign in to comment.