Skip to content

Commit

Permalink
Merge pull request #11 from stormychel/stormychel-main
Browse files Browse the repository at this point in the history
sync
  • Loading branch information
stormychel authored Sep 24, 2024
2 parents 0c76058 + 5949935 commit 122174a
Show file tree
Hide file tree
Showing 28 changed files with 235 additions and 45 deletions.
2 changes: 2 additions & 0 deletions Example/KeyboardShortcutsExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
Expand Down Expand Up @@ -343,6 +344,7 @@
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
Expand Down
4 changes: 1 addition & 3 deletions Example/KeyboardShortcutsExample/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import SwiftUI

@main
struct AppMain: App {
@StateObject private var state = AppState()

var body: some Scene {
WindowGroup {
MainScreen()
.task {
state.createMenus()
AppState.shared.createMenus()
}
}
}
Expand Down
14 changes: 9 additions & 5 deletions Example/KeyboardShortcutsExample/AppState.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import SwiftUI

@MainActor
final class AppState: ObservableObject {
final class AppState {
static let shared = AppState()

private init() {}

func createMenus() {
let testMenuItem = NSMenuItem()
NSApp.mainMenu?.addItem(testMenuItem)
Expand All @@ -13,22 +17,22 @@ final class AppState: ObservableObject {
testMenu.addCallbackItem("Shortcut 1") { [weak self] in
self?.alert(1)
}
.setShortcut(for: .testShortcut1)
.setShortcut(for: .testShortcut1)

testMenu.addCallbackItem("Shortcut 2") { [weak self] in
self?.alert(2)
}
.setShortcut(for: .testShortcut2)
.setShortcut(for: .testShortcut2)

testMenu.addCallbackItem("Shortcut 3") { [weak self] in
self?.alert(3)
}
.setShortcut(for: .testShortcut3)
.setShortcut(for: .testShortcut3)

testMenu.addCallbackItem("Shortcut 4") { [weak self] in
self?.alert(4)
}
.setShortcut(for: .testShortcut4)
.setShortcut(for: .testShortcut4)
}

private func alert(_ number: Int) {
Expand Down
56 changes: 28 additions & 28 deletions Example/KeyboardShortcutsExample/MainScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ private struct DynamicShortcutRecorder: View {
Text("Pressed? \(isPressed ? "👍" : "👎")")
.frame(width: 100, alignment: .leading)
}
.onChange(of: name) {
isFocused = true
}
.onChange(of: name) {
isFocused = true
}
}
}

Expand Down Expand Up @@ -58,12 +58,12 @@ private struct DynamicShortcut: View {
DynamicShortcutRecorder(name: $shortcut.name, isPressed: $isPressed)
}
}
.frame(maxWidth: 300)
.padding()
.padding(.bottom, 20)
.onChange(of: shortcut) { oldValue, newValue in
onShortcutChange(oldValue: oldValue, newValue: newValue)
}
.frame(maxWidth: 300)
.padding()
.padding(.bottom, 20)
.onChange(of: shortcut) { oldValue, newValue in
onShortcutChange(oldValue: oldValue, newValue: newValue)
}
}

private func onShortcutChange(oldValue: Shortcut, newValue: Shortcut) {
Expand Down Expand Up @@ -93,30 +93,30 @@ private struct DoubleShortcut: View {
KeyboardShortcuts.Recorder(for: .testShortcut2) {
Text("Shortcut 2:") // Intentionally using the verbose initializer for testing.
}
.overlay(alignment: .trailing) {
Text("Pressed? \(isPressed2 ? "👍" : "👎")")
.offset(x: 90)
}
.overlay(alignment: .trailing) {
Text("Pressed? \(isPressed2 ? "👍" : "👎")")
.offset(x: 90)
}
Spacer()
Button("Reset All") {
KeyboardShortcuts.reset(.testShortcut1, .testShortcut2)
}
}
.offset(x: -40)
.frame(maxWidth: 300)
.padding()
.padding()
.onKeyboardShortcut(.testShortcut1) {
isPressed1 = $0 == .keyDown
}
.onKeyboardShortcut(.testShortcut2, type: .keyDown) {
isPressed2 = true
}
.task {
KeyboardShortcuts.onKeyUp(for: .testShortcut2) {
isPressed2 = false
}
.offset(x: -40)
.frame(maxWidth: 300)
.padding()
.padding()
.onGlobalKeyboardShortcut(.testShortcut1) {
isPressed1 = $0 == .keyDown
}
.onGlobalKeyboardShortcut(.testShortcut2, type: .keyDown) {
isPressed2 = true
}
.task {
KeyboardShortcuts.onKeyUp(for: .testShortcut2) {
isPressed2 = false
}
}
}
}

Expand All @@ -127,7 +127,7 @@ struct MainScreen: View {
Divider()
DynamicShortcut()
}
.frame(width: 400, height: 320)
.frame(width: 400, height: 320)
}
}

Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.10
// swift-tools-version:5.11
import PackageDescription

let package = Package(
Expand Down
2 changes: 2 additions & 0 deletions Sources/KeyboardShortcuts/CarbonKeyboardShortcuts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ enum CarbonKeyboardShortcuts {
registerError == noErr,
let carbonHotKey = eventHotKey
else {
print("Error registering hotkey \(shortcut):", registerError)
return
}

Expand Down Expand Up @@ -181,6 +182,7 @@ enum CarbonKeyboardShortcuts {
error == noErr,
let eventHotKey
else {
print("Error registering hotkey \(hotKey.shortcut):", error)
hotKeys.removeValue(forKey: hotKey.carbonHotKeyId)
continue
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"keyboard_shortcut_used_by_menu_item" = "لا يمكن استخدام اختصار لوحة المفاتيح هذا لأنه مستخدم بواسطة عنصر القائمة “%@”.";
"keyboard_shortcut_used_by_system" = "لا يمكن استخدام اختصار لوحة المفاتيح هذا لأنه مستخدم مسبقاً على مستوى النظام.";
"keyboard_shortcuts_can_be_changed" = "يمكن تغيير معظم اختصارات لوحة المفاتيح على مستوى النظام في “تفضيلات النظام > لوحة المفاتيح > الاختصارات ”.";
"keyboard_shortcut_disallowed" = "يجب دمج مفتاح Option مع Command أو Control.";
"ok" = "موافق";
"space_key" = "مسافة";
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"keyboard_shortcut_used_by_menu_item" = "Tuto zkratku nelze použít, protože je již využívána položkou „%@“";
"keyboard_shortcut_used_by_system" = "Tuto zkratku nelze použít, protože už ji používá systém.";
"keyboard_shortcuts_can_be_changed" = "Většinu systémových zkratek můžete změnit v „Nastavení systému › Klávesnice › Klávesové zkratky“.";
"keyboard_shortcut_disallowed" = "Modifikátor Option musí být kombinován s klávesou Command nebo Control.";
"ok" = "OK";
"space_key" = "Mezera";
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"keyboard_shortcut_used_by_menu_item" = "Dieses Tastaturkürzel kann nicht verwendet werden, da es bereits durch den Menüpunkt „%@” belegt ist.";
"keyboard_shortcut_used_by_system" = "Dieses Tastaturkürzel kann nicht verwendet werden, da es bereits systemweit verwendet wird.";
"keyboard_shortcuts_can_be_changed" = "Die meisten systemweiten Tastaturkürzel können unter „Systemeinstellungen › Tastatur › Tastaturkurzbefehle“ geändert werden.";
"keyboard_shortcut_disallowed" = "Die Option-Taste muss mit der Befehlstaste oder der Steuerungstaste kombiniert werden.";
"ok" = "OK";
"space_key" = "Leer";
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"keyboard_shortcut_used_by_menu_item" = "This keyboard shortcut cannot be used as it’s already used by the “%@” menu item.";
"keyboard_shortcut_used_by_system" = "This keyboard shortcut cannot be used as it’s already a system-wide keyboard shortcut.";
"keyboard_shortcuts_can_be_changed" = "Most system-wide keyboard shortcuts can be changed in “System Settings › Keyboard › Keyboard Shortcuts”.";
"keyboard_shortcut_disallowed" = "Option modifier must be combined with Command or Control.";
"force_use_shortcut" = "Use Anyway";
"ok" = "OK";
"space_key" = "Space";
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"keyboard_shortcut_used_by_menu_item" = "Este atajo de teclado no se puede utilizar ya que está siendo utilizado por el elemento de menú “%@”.";
"keyboard_shortcut_used_by_system" = "Este atajo de teclado no se puede utilizar ya que está siendo utilizado por un atajo del sistema operativo.";
"keyboard_shortcuts_can_be_changed" = "La mayoría de los atajos de teclado del sistema operativo pueden ser modificados en “Configuración del sistema › Teclado › Atajos de teclado“.";
"keyboard_shortcut_disallowed" = "El modificador Option debe combinarse con Command o Control.";
"ok" = "Aceptar";
"space_key" = "Espacio";
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"keyboard_shortcut_used_by_menu_item" = "Ce raccourci ne peut pas être utilisé, car il est déjà utilisé par le menu “%@”.";
"keyboard_shortcut_used_by_system" = "Ce raccourci ne peut pas être utilisé car il s'agit d'un raccourci déjà présent dans le système.";
"keyboard_shortcuts_can_be_changed" = "La plupart des raccourcis clavier de l'ensemble du système peuvent être modifiés en “Réglages du système… › Clavier › Raccourcis clavier…”.";
"keyboard_shortcut_disallowed" = "Le modificateur Option doit être combiné avec Command ou Control.";
"ok" = "OK";
"space_key" = "Espace";
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"keyboard_shortcut_used_by_menu_item" = "Ez a billentyűparancs nem használható mert már a “%@” menü elem használja.";
"keyboard_shortcut_used_by_system" = "Ez a billentyűparancs nem használható mert már egy rendszerszintü billentyűparancs.";
"keyboard_shortcuts_can_be_changed" = "A legtöbb rendszerszintü billentyűparancsot a “Rendszerbeállítások › Billentyűzet › Billentyűparancsok“ menüben meg lehet változtatni";
"keyboard_shortcut_disallowed" = "Az Option módosítót a Command vagy Control billentyűvel együtt kell használni.";
"ok" = "OK";
"space_key" = "Szóköz";
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"keyboard_shortcut_used_by_menu_item" = "このショートカットは既に“%@”で使われており使えません。";
"keyboard_shortcut_used_by_system" = "このショートカットキーは既にシステムで使われており使えません。";
"keyboard_shortcuts_can_be_changed" = "システムで設定されているショートカットキーは“システム設定 › キーボード › キーボードショートカット”で変更できます。";
"keyboard_shortcut_disallowed" = "Optionキーは、CommandキーまたはControlキーと組み合わせる必要があります。";
"force_use_shortcut" = "強制使用";
"ok" = "OK";
"space_key" = "スペース";
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"keyboard_shortcut_used_by_menu_item" = "이 키보드 단축키는 이미 “%@” 메뉴 항목에 사용되고 있으므로 등록할 수 없습니다.";
"keyboard_shortcut_used_by_system" = "이 키보드 단축키는 이미 시스템상에서 사용되고 있으므로 등록할 수 없습니다.";
"keyboard_shortcuts_can_be_changed" = "대부분의 시스템 키보드 단축키는 “시스템 설정 › 키보드 › 키보드 단축키”에서 변경 가능합니다.";
"keyboard_shortcut_disallowed" = "Option 수정자는 Command 또는 Control과 함께 사용해야 합니다.";
"ok" = "확인";
"space_key" = "빈칸";
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"keyboard_shortcut_used_by_menu_item" = "Deze toetscombinatie kan niet worden gebruikt omdat hij al wordt gebruikt door het menu item “%@”.";
"keyboard_shortcut_used_by_system" = "Deze toetscombinatie kan niet worden gebruikt omdat hij al door het systeem gebruikt wordt.";
"keyboard_shortcuts_can_be_changed" = "De meeste systeem toetscombinaties kunnen onder “Systeeminstellingen… > Toetsenbord > Toetscombinaties…” veranderd worden.";
"keyboard_shortcut_disallowed" = "De Option-toets moet worden gecombineerd met Command of Control.";
"ok" = "OK";
"space_key" = "spatie";
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"keyboard_shortcut_used_by_menu_item" = "Este atalho não pode ser usado porque ele já é usado pelo item de menu “%@”.";
"keyboard_shortcut_used_by_system" = "Este atalho não pode ser usado porque ele já é usado por um atalho do sistema.";
"keyboard_shortcuts_can_be_changed" = "A maioria dos atalhos do sistema podem ser alterados em “Ajustes do Sistema › Teclado › Atalhos de Teclado”.";
"keyboard_shortcut_disallowed" = "O modificador Option deve ser combinado com Command ou Control.";
"ok" = "OK";
"space_key" = "Espaço";
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"keyboard_shortcut_used_by_menu_item" = "Это сочетание клавиш нельзя использовать, так как оно уже используется в пункте меню «%@».";
"keyboard_shortcut_used_by_system" = "Это сочетание клавиш нельзя использовать, поскольку оно является системным.";
"keyboard_shortcuts_can_be_changed" = "Большинство системных сочетаний клавиш можно изменить в «Системные настройки › Клавиатура › Сочетания клавиш».";
"keyboard_shortcut_disallowed" = "Клавиша Option должна использоваться в сочетании с Command или Control.";
"ok" = "OK";
"space_key" = "Пробел";
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"keyboard_shortcut_used_by_menu_item" = "Túto klávesovú skratku nemožno použiť, pretože ju už používa položka menu “%@”.";
"keyboard_shortcut_used_by_system" = "Túto klávesovú skratku nemožno použiť, pretože je už použivaná pre celý systém.";
"keyboard_shortcuts_can_be_changed" = "Väčšinu systémových klávesových skratiek môžeš zmeniť v “Systémové nastavenia › Klávesnica › Klávesové skratky”.";
"keyboard_shortcut_disallowed" = "Modifikátor Option musí byť kombinovaný s klávesmi Command alebo Control.";
"force_use_shortcut" = "Použiť napriek tomu";
"ok" = "OK";
"space_key" = "Medzerník";
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"keyboard_shortcut_used_by_menu_item" = "当前快捷键无法使用,因为它已被用作菜单项 “%@” 的快捷键。";
"keyboard_shortcut_used_by_system" = "当前快捷键无法使用,因为它已被用作系统快捷键。";
"keyboard_shortcuts_can_be_changed" = "可以在 “系统设置 › 键盘 › 键盘快捷键” 中更改大多数系统快捷键。";
"keyboard_shortcut_disallowed" = "Option 修飾鍵必須與 Command 或 Control 組合使用。";
"force_use_shortcut" = "强制使用";
"ok" = "好";
"space_key" = "空格";
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"keyboard_shortcut_used_by_menu_item" = "此快速鍵無法使用,因為它已被選單項目「%@」使用。";
"keyboard_shortcut_used_by_system" = "此快速鍵無法使用,因為它已被系統使用。";
"keyboard_shortcuts_can_be_changed" = "可以在「系統設定 › 鍵盤 › 鍵盤快速鍵」中更改大多數的系統快速鍵。";
"keyboard_shortcut_disallowed" = "Option 鍵必須與 Command 或 Control 鍵組合使用。";
"force_use_shortcut" = "強制使用";
"ok" = "好";
"space_key" = "空格";
2 changes: 1 addition & 1 deletion Sources/KeyboardShortcuts/Name.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ extension KeyboardShortcuts {

/**
- Parameter name: Name of the shortcut.
- Parameter default: Optional default key combination. Do not set this unless it's essential. Users find it annoying when random apps steal their existing keyboard shortcuts. It's generally better to show a welcome screen on the first app launch that lets the user set the shortcut.
- Parameter initialShortcut: Optional default key combination. Do not set this unless it's essential. Users find it annoying when random apps steal their existing keyboard shortcuts. It's generally better to show a welcome screen on the first app launch that lets the user set the shortcut.
*/
public init(_ name: String, default initialShortcut: Shortcut? = nil) {
self.rawValue = name
Expand Down
2 changes: 2 additions & 0 deletions Sources/KeyboardShortcuts/Recorder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ extension KeyboardShortcuts {
}
}
```

- Note: Since macOS 15, for sandboxed apps, it's [no longer possible](https://developer.apple.com/forums/thread/763878?answerId=804374022#804374022) to specify the `Option` key without also using `Command` or `Control`.
*/
public struct Recorder<Label: View>: View { // swiftlint:disable:this type_name
private let name: Name
Expand Down
19 changes: 19 additions & 0 deletions Sources/KeyboardShortcuts/RecorderCocoa.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ extension KeyboardShortcuts {
showsCancelButton = !stringValue.isEmpty
restoreCaret()
KeyboardShortcuts.isPaused = false
NotificationCenter.default.post(name: .recorderActiveStatusDidChange, object: nil, userInfo: ["isActive": false])
}

private func preventBecomingKey() {
Expand Down Expand Up @@ -211,6 +212,7 @@ extension KeyboardShortcuts {
showsCancelButton = !stringValue.isEmpty
hideCaret()
KeyboardShortcuts.isPaused = true // The position here matters.
NotificationCenter.default.post(name: .recorderActiveStatusDidChange, object: nil, userInfo: ["isActive": true])

eventMonitor = LocalEventMonitor(events: [.keyDown, .leftMouseUp, .rightMouseUp]) { [weak self] event in
guard let self else {
Expand Down Expand Up @@ -284,6 +286,19 @@ extension KeyboardShortcuts {
return nil
}

// See: https://developer.apple.com/forums/thread/763878?answerId=804374022#804374022
if shortcut.isDisallowed {
blur()

NSAlert.showModal(
for: window,
title: "keyboard_shortcut_disallowed".localized
)

focus()
return nil
}

if shortcut.isTakenBySystem {
blur()

Expand Down Expand Up @@ -324,4 +339,8 @@ extension KeyboardShortcuts {
}
}
}

extension Notification.Name {
static let recorderActiveStatusDidChange = Self("KeyboardShortcuts_recorderActiveStatusDidChange")
}
#endif
Loading

0 comments on commit 122174a

Please sign in to comment.