From f44a50028e6fb65ffd44af247664e00a1197d3d5 Mon Sep 17 00:00:00 2001 From: Martin Paljak Date: Tue, 14 Jan 2025 10:06:18 +0200 Subject: [PATCH 1/2] Fix #8: allow changing the default button with keyboard in confirm mode. --- ssh-askpass/ViewController.swift | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/ssh-askpass/ViewController.swift b/ssh-askpass/ViewController.swift index ac2f5cf..1274fcb 100644 --- a/ssh-askpass/ViewController.swift +++ b/ssh-askpass/ViewController.swift @@ -48,13 +48,32 @@ class ViewController: NSViewController { // set first responder to allow closing window with escape key switch self.sshAskpass.type { case .confirmation, .information: - if let window = self.view.window { - window.makeFirstResponder(cancelButton) - } + self.view.window?.makeFirstResponder(cancelButton) default: break // passwordTextField is first responder by default } } + // Handle tab key, even if navigation disabled in settings. + override func keyDown(with event: NSEvent) { + let switchers: [UInt16] = [48, 123, 124] // tab, left arrow, right arrow + guard switchers.contains(event.keyCode) else { + super.keyDown(with: event) + return + } + + if (self.sshAskpass.type == .confirmation) { + if self.view.window?.firstResponder === cancelButton { + self.view.window?.makeFirstResponder(okButton) + cancelButton.keyEquivalent = "" + okButton.keyEquivalent = "\r" + } else { + self.view.window?.makeFirstResponder(cancelButton) + okButton.keyEquivalent = "" + cancelButton.keyEquivalent = "\r" + } + } + } + override func viewDidLoad() { super.viewDidLoad() From 191bf4d21d9a183aaff60422eca515187a2461c1 Mon Sep 17 00:00:00 2001 From: Martin Paljak Date: Tue, 14 Jan 2025 10:36:04 +0200 Subject: [PATCH 2/2] fix #9: automatically cancel in seconds --- ssh-askpass/ViewController.swift | 43 +++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/ssh-askpass/ViewController.swift b/ssh-askpass/ViewController.swift index 1274fcb..31f46fb 100644 --- a/ssh-askpass/ViewController.swift +++ b/ssh-askpass/ViewController.swift @@ -37,6 +37,8 @@ class ViewController: NSViewController { let sshKeychain = SSHKeychain.shared let sshAskpass = SSHAskpass.shared + var timeout = 0 + var timer: Timer? #if swift(>=4.2) let cautionName = NSImage.cautionName @@ -62,6 +64,11 @@ class ViewController: NSViewController { } if (self.sshAskpass.type == .confirmation) { + if self.timeout > 0 { + timer?.invalidate() + timer = nil + cancelButton.title = "Cancel" + } if self.view.window?.firstResponder === cancelButton { self.view.window?.makeFirstResponder(okButton) cancelButton.keyEquivalent = "" @@ -74,6 +81,28 @@ class ViewController: NSViewController { } } + func startCountdown() { + updateCounter() // Set the initial title + + // Schedule a timer to update the countdown every second + timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in + guard let self = self else { return } + + self.timeout -= 1 + if self.timeout <= 0 { + self.timer?.invalidate() + self.timer = nil + self.cancel(self) // Cancel the dialog when timeout reaches zero + } else { + self.updateCounter() + } + } + } + + func updateCounter() { + cancelButton.title = "Cancel (in \(timeout)s)" + } + override func viewDidLoad() { super.viewDidLoad() @@ -86,9 +115,20 @@ class ViewController: NSViewController { if let controlView = keychainCheckBox.controlView { controlView.isHidden = true } - + okButton.keyEquivalent = "" // reset default behaviour cancelButton.keyEquivalent = "\r" // set to return key + + // Start the counter, if asked for + if let timeoutString = ProcessInfo.processInfo.environment["SSH_ASKPASS_TIMEOUT"], + let timeoutValue = Int(timeoutString) { + self.timeout = timeoutValue + } + + // Start the countdown if timeout is greater than zero + if self.timeout > 0 { + startCountdown() + } case .passphrase: if sshAskpass.account.isEmpty { keychainCheckBox.state = NSControl.StateValue.off @@ -128,6 +168,7 @@ class ViewController: NSViewController { } @IBAction func cancel(_ sender: Any) { + timer?.invalidate() // Stop the timer exit(1) }