feat: even more flexible controls (closes #458, closes #463)

This commit is contained in:
Louis Pontoise authored and lwouis committed 2020-08-06 04:18:53 +09:00
1 parent 79ae6cab4c
commit a990bbef9c
33 files changed
+670 -225

No files matched your search

+4
View File
@@ -68,6 +68,7 @@
D04BA9557A6C9E192D228150 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA2C08725A5F2C34EB809 /* InfoPlist.strings */; };
D04BA9B7A964C5FABFEB9DA2 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA053A0E0157E817B2E04 /* Localizable.strings */; };
D04BA9D63A88AF2C20A1E656 /* SF-Pro-Text-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = D04BA60A6D08C041F5BF8CC9 /* SF-Pro-Text-Regular.otf */; };
D04BAA16F21AC41A23DDA63D /* ControlsTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA1B438BF3E65044D1138 /* ControlsTab.swift */; };
D04BAAAF5CFA991D3B078DB8 /* KeyboardEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA4A621A8A15660F973C1 /* KeyboardEvents.swift */; };
D04BAAB5C4E78AE375EA7D3C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BAA56B4EEAF17F767C7FD /* Localizable.strings */; };
D04BAABE804F3769CE22BEB6 /* HyperlinkLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA49E45BFFF3D9FC60E43 /* HyperlinkLabel.swift */; };
@@ -130,6 +131,7 @@
D04BA18724DC58FA95DB33DB /* Podfile.lock */ = {isa = PBXFileReference; lastKnownFileType = file.lock; path = Podfile.lock; sourceTree = "<group>"; };
D04BA18B55AA6C9EE41985D0 /* Contributing.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Contributing.md; sourceTree = "<group>"; };
D04BA19E22F2B73DB785E5DB /* subset_fonticon.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = subset_fonticon.sh; sourceTree = "<group>"; };
D04BA1B438BF3E65044D1138 /* ControlsTab.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControlsTab.swift; sourceTree = "<group>"; };
D04BA1C3E42AC44CA2C5D3D8 /* app-icon.svg */ = {isa = PBXFileReference; lastKnownFileType = file.svg; path = "app-icon.svg"; sourceTree = "<group>"; };
D04BA1D80F4EEF2A91BAD29C /* release.config.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = release.config.js; sourceTree = "<group>"; };
D04BA1DF8CAB2FAB7FE9244B /* ThumbnailFontIconView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbnailFontIconView.swift; sourceTree = "<group>"; };
@@ -494,6 +496,7 @@
D04BAD60C97E609A759E721E /* PoliciesTab.swift */,
D04BA788228BA86D9EFBD1ED /* AcknowledgmentsTab.swift */,
D04BA27695D9A5824720BD7B /* BlacklistsTab.swift */,
D04BA1B438BF3E65044D1138 /* ControlsTab.swift */,
);
path = tabs;
sourceTree = "<group>";
@@ -1120,6 +1123,7 @@
D04BAFF30A98CF287F85DA1E /* BlacklistsTab.swift in Sources */,
D04BA56789A2AF52557A9BFF /* AppCenterCrashes.swift in Sources */,
D04BADA3F2DAB820D6FC6E75 /* AppCenterApplication.m in Sources */,
D04BAA16F21AC41A23DDA63D /* ControlsTab.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+18 -6
View File
@@ -34,6 +34,9 @@
/* No comment provided by engineer. */
"Allowed" = "Allowed";
/* No comment provided by engineer. */
"Also select windows using:" = "Also select windows using:";
/* No comment provided by engineer. */
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -88,9 +91,15 @@
/* No comment provided by engineer. */
"Close window" = "Close window";
/* No comment provided by engineer. */
"Controls" = "Controls";
/* No comment provided by engineer. */
"Crash reports policy:" = "Crash reports policy:";
/* No comment provided by engineer. */
"Do nothing" = "Do nothing";
/* No comment provided by engineer. */
"Don’t check for updates periodically" = "Don’t check for updates periodically";
@@ -187,9 +196,6 @@
/* No comment provided by engineer. */
"Optional: email (if you want a reply)" = "Optional: email (if you want a reply)";
/* No comment provided by engineer. */
"or press:" = "or press:";
/* No comment provided by engineer. */
"Policies" = "Policies";
@@ -229,9 +235,6 @@
/* No comment provided by engineer. */
"Select previous window" = "Select previous window";
/* No comment provided by engineer. */
"Select windows using:" = "Select windows using:";
/* No comment provided by engineer. */
"Send" = "Send";
@@ -253,6 +256,12 @@
/* No comment provided by engineer. */
"Share improvement ideas, or report bugs" = "Share improvement ideas, or report bugs";
/* No comment provided by engineer. */
"Shortcut 1" = "Shortcut 1";
/* No comment provided by engineer. */
"Shortcut 2" = "Shortcut 2";
/* Menubar option */
"Show" = "Show";
@@ -295,6 +304,9 @@
/* No comment provided by engineer. */
"View existing discussions" = "View existing discussions";
/* No comment provided by engineer. */
"While open, press:" = "While open, press:";
/* No comment provided by engineer. */
"Window app icon size:" = "Window app icon size:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Allowed";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "إغلاق النافذة";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "لا تبحث عن تحديثات بشكل دوري";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "شارك أفكارك التطويرية، أو بلغ عن أخطاء";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "إظهار";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "أنظر للنقاشات الحالية";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "حجم أيقونة النافذة:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Erlaubt";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab ist bei der letzten Ausführung abgestürzt. Das Absenden von Absturzberichten hilft bei der Fehlerbeseitigung.";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "Fenster schließen";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Richtlinie für Absturzberichte:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "Nicht regelmäßig nach Updates suchen";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "Teile uns deine Vorschläge mit oder melden Fehler";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "Anzeigen";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "Bestehende Vorschläge anzeigen";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "Fenster Icon Größe:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Allowed";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "Close window";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "Don’t check for updates periodically";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "Share improvement ideas, or report bugs";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "Show";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "View existing discussions";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "Window app icon size:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Allowed";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "Cerrar ventana";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "No comprobar actualizaciones periódicamente";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "Comparta ideas de mejora o informe de errores";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "Mostrar";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "Ver discusiones existentes";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "Tamaño del icono de la ventana de aplicación:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Allowed";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "Sulje ikkuna";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "Älä tarkista päivityksiä";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "Jaa parannusehdotuksia tai raportoi bugeja";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "Näytä";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "Näytä keskustelut";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "Ohjelmaikonin koko:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Autorisé";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "Fermer la fenêtre";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "Ne pas chercher de mise-à-jour périodiquement";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "Partagez des idées d’amélioration, ou signalez des bugs";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "Afficher";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "Voir les discussions existantes";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "Taille des icones des applications :";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Engedélyezve";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "Ablak bezárása";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "Ne keressen frissítéseket automatikusan";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "Fejlesztési ötletek megosztása, hibabejelentés";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "Mutat";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "Aktuális beszélgetések megtekintése";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "Ablak alkalmazásikonméret:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Dibolehkan";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "Tutup jendela";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "Jangan periksa pembaruan secara berkala";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "Bagikan gagasan peningkatan, atau laporkan bug";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "Tampilkan";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "Lihat diskusi yang ada";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "Ukuran ikon aplikasi jendela:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Allowed";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "Chiudi la finestra";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "Non controllare gli aggiornamenti periodicamente";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "Condividi idee per miglioramenti oppure riporta problemi";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "Mostra";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "Mostra discussioni esistenti";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "Dimensione dell’icona della finestra dell’applicazione:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Allowed";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "ウィンドウを閉じる";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "定期的に更新を確認しない";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "改善点のご共有あるいはバグのご報告";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "アプリを表示";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "既にあるディスカッションを見る";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "ウィンドウに表示されるアイコンサイズ:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "허용됨";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "마지막으로 사용하고 나서 AltTab이 충돌했습니다. 충돌 리포트를 보내는 것은 이 문제를 해결하는데 도움을 줄 수 있습니다";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "윈도우 닫기";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "충돌 리포트 처리 방법:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "주기적으로 업데이트를 확인하지 않기";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "개선방안을 공유하거나 버그를 제보해주세요";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "보기";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "진행중인 논의 보기";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "윈도우 앱 아이콘 크기:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Allowed";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "Close window";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "Net reegelméisseg no Updates sichen";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "Share improvement ideas, or report bugs";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "Opbréngen";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "View existing discussions";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "Window app icon size:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Allowed";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "Sluit venster";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "Controleer niet regelmatig op updates";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "Deel verbetervoorstellen of meld bugs";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "Toon";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "Bekijk bestaande discussies";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "Icoongrootte vensterapplicatie:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Allowed";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "Fechar janela";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "Não verifique periodicamente por atualizações";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "Compartilhar sugestões ou reportar falhas";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "Exibir";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "Ver discussões existentes";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "Tamanho do ícone da aplicação:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Разрешено";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab аварийно завершился в последний раз, когда вы его использовали. Отправка отчета поможет исправить проблему";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "Закрыть окно";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Правило отчетов о вылетах:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "Не проверять обновления";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "Поделитесь идеями по улучшению или сообщите об ошибках";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "Показать";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "Посмотреть обсуждения";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "Размер иконки окна:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Allowed";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "Pencereyi kapat";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "Güncellemeleri periyodik olarak kontrol etme";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "Fikir yada hata paylaş";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "Göster";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "Mevcut tartışmaları görüntüle";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "Pencere simge boyutu:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "允许";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab 在您上次使用时崩溃了, 发送崩溃报告将有助于解决问题";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "关闭窗口";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "崩溃报告政策:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "不自动检查更新";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "反馈建议或报告错误";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "显示";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "查看现有讨论";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "窗口图标大小:";
@@ -35,6 +35,9 @@
/*No comment provided by engineer.*/
"Allowed" = "Allowed";
/*No comment provided by engineer.*/
"Also select windows using:" = "Also select windows using:";
/*No comment provided by engineer.*/
"AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed";
@@ -89,9 +92,15 @@
/*No comment provided by engineer.*/
"Close window" = "關閉視窗";
/*No comment provided by engineer.*/
"Controls" = "Controls";
/*No comment provided by engineer.*/
"Crash reports policy:" = "Crash reports policy:";
/*No comment provided by engineer.*/
"Do nothing" = "Do nothing";
/*No comment provided by engineer.*/
"Don’t check for updates periodically" = "不要定期自動檢查更新";
@@ -257,6 +266,12 @@
/*No comment provided by engineer.*/
"Share improvement ideas, or report bugs" = "分享改進的想法,或是回報問題";
/*No comment provided by engineer.*/
"Shortcut 1" = "Shortcut 1";
/*No comment provided by engineer.*/
"Shortcut 2" = "Shortcut 2";
/*No comment provided by engineer.*/
"Show" = "顯示";
@@ -299,6 +314,9 @@
/*No comment provided by engineer.*/
"View existing discussions" = "觀看目前的討論";
/*No comment provided by engineer.*/
"While open, press:" = "While open, press:";
/*No comment provided by engineer.*/
"Window app icon size:" = "視窗圖示的大小:";
+20
View File
@@ -127,3 +127,23 @@ extension DispatchQoS {
}
}
}
extension NSGridColumn {
func width(_ skipCell: Int? = nil) -> CGFloat {
var maxWidth = CGFloat(0)
for i in (0..<numberOfCells) {
if let skipCell = skipCell, i == skipCell { continue }
maxWidth = max(maxWidth, cell(at: i).contentView!.fittingSize.width)
}
return maxWidth
}
}
extension NSViewController {
func setView(_ subview: NSView) {
view = NSView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.subviews = [subview]
subview.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
}
}
+49 -31
View File
@@ -13,8 +13,10 @@ class Preferences {
"iconSize": "32",
"fontHeight": "15",
"holdShortcut": "⌥",
"holdShortcut2": "⌥",
"nextWindowShortcut": "⇥",
"nextWindowShortcut2": keyAboveTabDependingOnInputSource(),
"focusWindowShortcut": "↩",
"previousWindowShortcut": "⇧",
"cancelShortcut": "⎋",
"closeWindowShortcut": "W",
@@ -55,6 +57,7 @@ class Preferences {
"rowsCount": defaultsDependingOnScreenRatio_["rowsCount"]!,
"minCellsPerRow": defaultsDependingOnScreenRatio_["minCellsPerRow"]!,
"maxCellsPerRow": defaultsDependingOnScreenRatio_["maxCellsPerRow"]!,
"shortcutStyle": "0",
]
// constant values
@@ -74,7 +77,9 @@ class Preferences {
static var iconSize: CGFloat { defaults.cgfloat("iconSize") }
static var fontHeight: CGFloat { defaults.cgfloat("fontHeight") }
static var holdShortcut: String { defaults.string("holdShortcut") }
static var holdShortcut2: String { defaults.string("holdShortcut2") }
static var nextWindowShortcut: [String] { ["nextWindowShortcut", "nextWindowShortcut2"].map { defaults.string($0) } }
static var focusWindowShortcut: String { defaults.string("focusWindowShortcut") }
static var previousWindowShortcut: String { defaults.string("previousWindowShortcut") }
static var cancelShortcut: String { defaults.string("cancelShortcut") }
static var closeWindowShortcut: String { defaults.string("closeWindowShortcut") }
@@ -108,6 +113,7 @@ class Preferences {
static var appsToShow: [AppsToShowPreference] { ["appsToShow", "appsToShow2"].map { defaults.macroPref($0, AppsToShowPreference.allCases) } }
static var spacesToShow: [SpacesToShowPreference] { ["spacesToShow", "spacesToShow2"].map { defaults.macroPref($0, SpacesToShowPreference.allCases) } }
static var screensToShow: [ScreensToShowPreference] { ["screensToShow", "screensToShow2"].map { defaults.macroPref($0, ScreensToShowPreference.allCases) } }
static var shortcutStyle: ShortcutStylePreference { defaults.macroPref("shortcutStyle", ShortcutStylePreference.allCases) }
// derived values
static var cellBorderWidth: CGFloat { theme.themeParameters.cellBorderWidth }
@@ -203,9 +209,21 @@ struct ThemeParameters {
typealias LocalizedString = String
enum AppsToShowPreference: String, CaseIterable, MacroPreference {
case all = "All apps"
case active = "Active app"
enum ShortcutStylePreference: CaseIterable, MacroPreference {
case focusOnRelease
case doNothingOnRelease
var localizedString: LocalizedString {
switch self {
case .focusOnRelease: return NSLocalizedString("Focus selected window", comment: "")
case .doNothingOnRelease: return NSLocalizedString("Do nothing", comment: "")
}
}
}
enum AppsToShowPreference: CaseIterable, MacroPreference {
case all
case active
var localizedString: LocalizedString {
switch self {
@@ -215,9 +233,9 @@ enum AppsToShowPreference: String, CaseIterable, MacroPreference {
}
}
enum SpacesToShowPreference: String, CaseIterable, MacroPreference {
case all = "0"
case active = "1"
enum SpacesToShowPreference: CaseIterable, MacroPreference {
case all
case active
var localizedString: LocalizedString {
switch self {
@@ -227,9 +245,9 @@ enum SpacesToShowPreference: String, CaseIterable, MacroPreference {
}
}
enum ScreensToShowPreference: String, CaseIterable, MacroPreference {
case all = "0"
case showingAltTab = "1"
enum ScreensToShowPreference: CaseIterable, MacroPreference {
case all
case showingAltTab
var localizedString: LocalizedString {
switch self {
@@ -239,10 +257,10 @@ enum ScreensToShowPreference: String, CaseIterable, MacroPreference {
}
}
enum ShowOnScreenPreference: String, CaseIterable, MacroPreference {
case active = "0"
case includingMouse = "1"
case includingMenubar = "2"
enum ShowOnScreenPreference: CaseIterable, MacroPreference {
case active
case includingMouse
case includingMenubar
var localizedString: LocalizedString {
switch self {
@@ -253,10 +271,10 @@ enum ShowOnScreenPreference: String, CaseIterable, MacroPreference {
}
}
enum TitleTruncationPreference: String, CaseIterable, MacroPreference {
case end = "0"
case middle = "1"
case start = "2"
enum TitleTruncationPreference: CaseIterable, MacroPreference {
case end
case middle
case start
var localizedString: LocalizedString {
switch self {
@@ -267,9 +285,9 @@ enum TitleTruncationPreference: String, CaseIterable, MacroPreference {
}
}
enum AlignThumbnailsPreference: String, CaseIterable, MacroPreference {
case left = "0"
case center = "1"
enum AlignThumbnailsPreference: CaseIterable, MacroPreference {
case left
case center
var localizedString: LocalizedString {
switch self {
@@ -279,9 +297,9 @@ enum AlignThumbnailsPreference: String, CaseIterable, MacroPreference {
}
}
enum ThemePreference: String, CaseIterable, MacroPreference {
case macOs = "0"
case windows10 = "1"
enum ThemePreference: CaseIterable, MacroPreference {
case macOs
case windows10
var localizedString: LocalizedString {
switch self {
@@ -298,10 +316,10 @@ enum ThemePreference: String, CaseIterable, MacroPreference {
}
}
enum UpdatePolicyPreference: String, CaseIterable, MacroPreference {
case manual = "0"
case autoCheck = "1"
case autoInstall = "2"
enum UpdatePolicyPreference: CaseIterable, MacroPreference {
case manual
case autoCheck
case autoInstall
var localizedString: LocalizedString {
switch self {
@@ -312,10 +330,10 @@ enum UpdatePolicyPreference: String, CaseIterable, MacroPreference {
}
}
enum CrashPolicyPreference: String, CaseIterable, MacroPreference {
case never = "0"
case ask = "1"
case always = "2"
enum CrashPolicyPreference: CaseIterable, MacroPreference {
case never
case ask
case always
var localizedString: LocalizedString {
switch self {
+38 -15
View File
@@ -1,5 +1,6 @@
import Cocoa
import Carbon.HIToolbox.Events
import ShortcutRecorder
fileprivate var eventTap: CFMachPort?
@@ -27,22 +28,16 @@ private func observe_() {
private func keyboardHandler(_: CGEventTapProxy, type: CGEventType, cgEvent: CGEvent, _: UnsafeMutableRawPointer?) -> Unmanaged<CGEvent>? {
if (type == .keyDown || type == .keyUp || type == .flagsChanged) && !App.app.shortcutsShouldBeDisabled {
if let event_ = NSEvent(cgEvent: cgEvent),
// workaround: NSEvent.characters is not safe outside of the main thread; this is not documented by Apple
// see https://github.com/Kentzo/ShortcutRecorder/issues/114#issuecomment-606465340
let event = NSEvent.keyEvent(with: event_.type, location: event_.locationInWindow, modifierFlags: event_.modifierFlags,
timestamp: event_.timestamp, windowNumber: event_.windowNumber, context: nil, characters: "",
charactersIgnoringModifiers: "", isARepeat: type == .flagsChanged ? false : event_.isARepeat, keyCode: event_.keyCode) {
if let event = NSEvent(cgEvent: cgEvent) {
let appWasBeingUsed = App.app.appIsBeingUsed
// ShortcutRecorder handles only exact matches for modifiers-only .up shortcuts. We want to activate holdShortcut even if other modifiers are still pressed
// see https://github.com/lwouis/alt-tab-macos/issues/230
let holdShortcutAction = GeneralTab.shortcutActions["holdShortcut"]!
let holdShortcut = holdShortcutAction.shortcut!
if holdShortcut.keyCode == .none && type == .flagsChanged && event.sr_keyEventType == .up &&
event.modifierFlags.isDisjoint(with: holdShortcut.modifierFlags) {
_ = holdShortcutAction.actionHandler!(holdShortcutAction)
} else {
App.shortcutMonitor.handle(event, withTarget: nil)
if let shortcut = shortcutThatMatches(event, type) {
if shortcut.hasPrefix("nextWindowShortcut") {
App.app.appIsBeingUsed = true
} else if shortcut.hasPrefix("holdShortcut") || shortcut == "cancelShortcut" || shortcut == "focusWindowShortcut" {
App.app.appIsBeingUsed = false
App.app.isFirstSummon = true
}
DispatchQueue.main.async { () -> () in ControlsTab.shortcutsActions[shortcut]!() }
}
if appWasBeingUsed || App.app.appIsBeingUsed {
return nil // focused app won't receive the event
@@ -53,3 +48,31 @@ private func keyboardHandler(_: CGEventTapProxy, type: CGEventType, cgEvent: CGE
}
return Unmanaged.passRetained(cgEvent) // focused app will receive the event
}
// shortcutMonitor.handle only does exact matching; we match manually to allow flexible matching
// see https://github.com/lwouis/alt-tab-macos/issues/230
private func shortcutThatMatches(_ event: NSEvent, _ type: CGEventType) -> String? {
for shortcutId in ControlsTab.shortcuts.keys {
let postfix = App.app.shortcutIndex == 0 ? "" : "2"
let shortcut = ControlsTab.shortcuts[shortcutId]!
if shortcutId.hasPrefix("holdShortcut") {
if event.sr_keyEventType == .up && type == .flagsChanged && shortcut.keyCode == .none && event.modifierFlags.isDisjoint(with: shortcut.modifierFlags) &&
shortcutId == "holdShortcut" + postfix && App.app.appIsBeingUsed && Preferences.shortcutStyle == .focusOnRelease {
return shortcutId
}
} else if event.sr_keyEventType == .down && (shortcut.keyCode == .none || event.keyCode == shortcut.carbonKeyCode) {
if shortcutId.hasPrefix("nextWindowShortcut") {
if event.modifierFlags.intersection(.deviceIndependentFlagsMask) == shortcut.modifierFlags &&
(!App.app.appIsBeingUsed || shortcutId == "nextWindowShortcut" + postfix) {
return shortcutId
}
} else {
if event.modifierFlags.intersection(.deviceIndependentFlagsMask).contains(shortcut.modifierFlags) &&
App.app.appIsBeingUsed {
return shortcutId
}
}
}
}
return nil
}
+11 -6
View File
@@ -13,7 +13,6 @@ class App: AppCenterApplication, NSApplicationDelegate {
static let licence = Bundle.main.object(forInfoDictionaryKey: "NSHumanReadableCopyright") as! String
static let repository = "https://github.com/lwouis/alt-tab-macos"
static var app: App!
static let shortcutMonitor = LocalShortcutMonitor()
static var statusItem: NSStatusItem!
var thumbnailsPanel: ThumbnailsPanel!
var preferencesWindowController: PreferencesWindowController!
@@ -81,6 +80,7 @@ class App: AppCenterApplication, NSApplicationDelegate {
private func loadPreferencesWindow() {
let tabs = [
GeneralTab(),
ControlsTab(),
AppearanceTab(),
PoliciesTab(),
BlacklistsTab(),
@@ -88,7 +88,14 @@ class App: AppCenterApplication, NSApplicationDelegate {
AcknowledgmentsTab(),
]
// pre-load tabs so we can interact with them before the user opens the preferences window
tabs.forEach { (tab: NSViewController) in tab.loadView() }
let widest = tabs.reduce(CGFloat(0), {
$1.loadView()
return max($0, $1.view.subviews[0].fittingSize.width)
})
tabs.forEach {
$0.view.fit(widest, $0.view.subviews[0].fittingSize.height)
}
preferencesWindowController = PreferencesWindowController(preferencePanes: tabs as! [PreferencePane])
let window = preferencesWindowController.window!
@@ -96,10 +103,8 @@ class App: AppCenterApplication, NSApplicationDelegate {
let titleBarView = window.standardWindowButton(.closeButton)!.superview!
titleBarView.addSubview(quitButton)
quitButton.translatesAutoresizingMaskIntoConstraints = false
let topConstraint = NSLayoutConstraint(item: quitButton, attribute: .top, relatedBy: .equal, toItem: titleBarView, attribute: .top, multiplier: 1, constant: 5)
let rightConstraint = NSLayoutConstraint(item: quitButton, attribute: .right, relatedBy: .equal, toItem: titleBarView, attribute: .right, multiplier: 1, constant: -10)
titleBarView.addConstraints([topConstraint, rightConstraint])
quitButton.topAnchor.constraint(equalTo: titleBarView.topAnchor, constant: 5).isActive = true
quitButton.rightAnchor.constraint(equalTo: titleBarView.rightAnchor, constant: -8).isActive = true
}
// keyboard shortcuts are broken without a menu. We generated the default menu from XCode and load it
+5 -5
View File
@@ -4,16 +4,16 @@ class GridView: NSGridView {
static let padding = CGFloat(20)
static let interPadding = CGFloat(10)
convenience init(_ controls: [[NSView]]) {
convenience init(_ controls: [[NSView]], _ padding: CGFloat = GridView.padding) {
self.init(views: controls)
translatesAutoresizingMaskIntoConstraints = false
yPlacement = .fill
rowAlignment = .firstBaseline
columnSpacing = GridView.interPadding
rowSpacing = GridView.interPadding
column(at: 0).leadingPadding = GridView.padding
column(at: numberOfColumns - 1).trailingPadding = GridView.padding
row(at: 0).topPadding = GridView.padding
row(at: numberOfRows - 1).bottomPadding = GridView.padding
column(at: 0).leadingPadding = padding
column(at: numberOfColumns - 1).trailingPadding = padding
row(at: 0).topPadding = padding
row(at: numberOfRows - 1).bottomPadding = padding
}
}
+35 -10
View File
@@ -10,8 +10,8 @@ enum LabelPosition {
class LabelAndControl: NSObject {
static func makeLabelWithRecorder(_ labelText: String, _ rawName: String, _ shortcutString: String, _ clearable: Bool = true, labelPosition: LabelPosition = .leftWithSeparator) -> [NSView] {
let input = CustomRecorderControl(shortcutString, clearable)
let views = makeLabelWithProvidedControl(labelText, rawName, input, labelPosition: labelPosition, extraAction: { _ in GeneralTab.shortcutChangedCallback(input) })
GeneralTab.shortcutChangedCallback(input)
let views = makeLabelWithProvidedControl(labelText, rawName, input, labelPosition: labelPosition, extraAction: { _ in ControlsTab.shortcutChangedCallback(input) })
ControlsTab.shortcutChangedCallback(input)
return views
}
@@ -35,10 +35,10 @@ class LabelAndControl: NSObject {
}
static func makeLabelWithDropdown(_ labelText: String, _ rawName: String, _ values: [MacroPreference], _ suffixText: String? = nil) -> [NSView] {
return makeLabelWithProvidedControl(labelText, rawName, makeDropDown(rawName, values), suffixText)
return makeLabelWithProvidedControl(labelText, rawName, dropdown_(rawName, values), suffixText)
}
static func makeDropDown(_ rawName: String, _ macroPreferences: [MacroPreference]) -> NSPopUpButton {
static func dropdown_(_ rawName: String, _ macroPreferences: [MacroPreference]) -> NSPopUpButton {
let popUp = NSPopUpButton()
popUp.translatesAutoresizingMaskIntoConstraints = false
popUp.addItems(withTitles: macroPreferences.map { $0.localizedString })
@@ -46,6 +46,11 @@ class LabelAndControl: NSObject {
return popUp
}
static func makeDropdown(_ rawName: String, _ macroPreferences: [MacroPreference]) -> NSControl {
let dropdown = dropdown_(rawName, macroPreferences)
return setupControl(dropdown, rawName)
}
static func makeRadioButtons(_ macroPreferences: [MacroPreference], _ rawName: String, extraAction: ActionClosure? = nil) -> [NSButton] {
var i = 0
return macroPreferences.map {
@@ -111,11 +116,14 @@ class LabelAndControl: NSObject {
}
}
static func makeLabel(_ labelText: String, _ labelPosition: LabelPosition = .leftWithoutSeparator) -> NSTextField {
static func makeLabel(_ labelText: String, _ labelPosition: LabelPosition = .leftWithoutSeparator, shouldFit: Bool = true) -> NSTextField {
let label = TextField(labelText)
label.isSelectable = false
label.usesSingleLineMode = true
label.alignment = .right
if shouldFit {
label.fit()
}
return label
}
@@ -170,13 +178,30 @@ enum ControlIdentifierDiscriminator: String {
case SUFFIX = "_suffix"
}
class TabView: NSTabView {
// without the left/right value, the whole view is shifted to the right for some reason
// let insets = NSEdgeInsets(top: 0, left: 7, bottom: 0, right: 7)
// override var alignmentRectInsets: NSEdgeInsets { get { insets } }
class TabView: NSTabView, NSTabViewDelegate {
// removing insets fixes a bug where tab views shift to the right and bottom by 7px when switching to tab #2
let insets = NSEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
override var alignmentRectInsets: NSEdgeInsets { get { insets } }
convenience init() {
// workaround: this is the only I found to have NSTabView fittingSize be correct
override var intrinsicContentSize: NSSize {
get {
NSSize(width: selectedTabViewItem!.view!.fittingSize.width + TabView.padding * 2,
height: selectedTabViewItem!.view!.fittingSize.height + TabView.padding * 2 + subviews[0].frame.height)
}
}
static let padding = CGFloat(7)
convenience init(_ labelsAndViews: [(String, NSView)]) {
self.init(frame: .zero)
translatesAutoresizingMaskIntoConstraints = false
labelsAndViews.enumerated().forEach { (i, tuple) in
let tab = NSTabViewItem(identifier: i)
tab.label = tuple.0
tab.view = tuple.1
addTabViewItem(tab)
tab.view!.fit()
}
}
}
@@ -31,6 +31,7 @@ class AboutTab: NSViewController, PreferencePane {
sendFeedbackCell.xPlacement = .center
sendFeedbackCell.row!.topPadding = GridView.interPadding
grid.fit()
view = grid
setView(grid)
}
}
@@ -26,6 +26,8 @@ class AcknowledgmentsTab: NSViewController, PreferencePane {
subGrid.fit()
let scrollView = ScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.documentView!.translatesAutoresizingMaskIntoConstraints = false
scrollView.scrollerKnobStyle = .default
scrollView.documentView!.subviews = [subGrid]
let totalWidth = subGrid.fittingSize.width
@@ -35,6 +37,6 @@ class AcknowledgmentsTab: NSViewController, PreferencePane {
scrollView.documentView!.frame.size = subGrid.fittingSize
scrollView.fit(totalWidth, totalHeight)
view = scrollView
setView(scrollView)
}
}
@@ -29,6 +29,6 @@ class AppearanceTab: NSViewController, PreferencePane {
grid.rowAlignment = .lastBaseline
grid.fit()
view = grid
setView(grid)
}
}
@@ -23,6 +23,7 @@ class BlacklistsTab: NSViewController, PreferencePane {
])
grid.row(at: 2).topPadding = GridView.interPadding * 1.5
grid.fit()
view = grid
setView(grid)
}
}
@@ -0,0 +1,154 @@
import Cocoa
import ShortcutRecorder
import Preferences
class ControlsTab: NSViewController, PreferencePane {
let preferencePaneIdentifier = PreferencePane.Identifier("Controls")
let preferencePaneTitle = NSLocalizedString("Controls", comment: "")
let toolbarItemIcon = NSImage(named: NSImage.preferencesGeneralName)!
static var nextWindowShortcut: NSControl!
static var nextWindowShortcut2: NSControl!
static var shortcuts = [String: Shortcut]()
static var shortcutsActions = [
"holdShortcut": { App.app.focusTarget() },
"holdShortcut2": { App.app.focusTarget() },
"focusWindowShortcut": { App.app.focusTarget() },
"nextWindowShortcut": { App.app.showUiOrCycleSelection(0) },
"nextWindowShortcut2": { App.app.showUiOrCycleSelection(1) },
"previousWindowShortcut": { App.app.cycleSelection(.trailing) },
"→": { App.app.cycleSelection(.right) },
"←": { App.app.cycleSelection(.left) },
"↑": { App.app.cycleSelection(.up) },
"↓": { App.app.cycleSelection(.down) },
"cancelShortcut": { App.app.hideUi() },
"closeWindowShortcut": { App.app.closeSelectedWindow() },
"minDeminWindowShortcut": { App.app.minDeminSelectedWindow() },
"quitAppShortcut": { App.app.quitSelectedApp() },
"hideShowAppShortcut": { App.app.hideShowSelectedApp() },
]
override func loadView() {
let shortcutStyle = LabelAndControl.makeLabelWithDropdown(NSLocalizedString("then release:", comment: ""), "shortcutStyle", ShortcutStylePreference.allCases)
let focusWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Focus selected window", comment: ""), "focusWindowShortcut", Preferences.focusWindowShortcut, labelPosition: .right)
let previousWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Select previous window", comment: ""), "previousWindowShortcut", Preferences.previousWindowShortcut, labelPosition: .right)
let cancelShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Cancel and hide", comment: ""), "cancelShortcut", Preferences.cancelShortcut, labelPosition: .right)
let closeWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Close window", comment: ""), "closeWindowShortcut", Preferences.closeWindowShortcut, labelPosition: .right)
let minDeminWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Minimize/Deminimize window", comment: ""), "minDeminWindowShortcut", Preferences.minDeminWindowShortcut, labelPosition: .right)
let quitAppShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Quit app", comment: ""), "quitAppShortcut", Preferences.quitAppShortcut, labelPosition: .right)
let hideShowAppShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Hide/Show app", comment: ""), "hideShowAppShortcut", Preferences.hideShowAppShortcut, labelPosition: .right)
let enableArrows = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Arrow keys", comment: ""), "arrowKeysEnabled", extraAction: ControlsTab.arrowKeysEnabledCallback, labelPosition: .right)
let enableMouse = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Mouse hover", comment: ""), "mouseHoverEnabled", labelPosition: .right)
let checkboxesExplanations = LabelAndControl.makeLabel(NSLocalizedString("Also select windows using:", comment: ""))
let checkboxes = StackView([StackView(enableArrows), StackView(enableMouse)], .vertical)
let shortcuts = StackView([focusWindowShortcut, previousWindowShortcut, cancelShortcut, closeWindowShortcut, minDeminWindowShortcut, quitAppShortcut, hideShowAppShortcut].map { (view: [NSView]) in StackView(view) }, .vertical)
let orPress = LabelAndControl.makeLabel(NSLocalizedString("While open, press:", comment: ""), shouldFit: false)
let (nextWindowShortcut, tab1View) = toShowSection("")
let (nextWindowShortcut2, tab2View) = toShowSection("2")
let tabView = TabView([(NSLocalizedString("Shortcut 1", comment: ""), tab1View), (NSLocalizedString("Shortcut 2", comment: ""), tab2View)])
ControlsTab.nextWindowShortcut = nextWindowShortcut[0] as! NSControl
ControlsTab.nextWindowShortcut2 = nextWindowShortcut2[0] as! NSControl
ControlsTab.arrowKeysEnabledCallback(enableArrows[0] as! NSControl)
let grid = GridView([
[tabView],
shortcutStyle,
[orPress, shortcuts],
[checkboxesExplanations, checkboxes],
])
grid.column(at: 0).xPlacement = .trailing
grid.mergeCells(inHorizontalRange: NSRange(location: 0, length: 2), verticalRange: NSRange(location: 0, length: 1))
grid.cell(atColumnIndex: 0, rowIndex: 0).xPlacement = .leading
// TODO: better layout logic. Maybe freeze the width of the preference window and have labels wrap on multiple lines
// currently this looks bad if the right column inside the tabView is larger than the right column of the top gridView
let leftColumnWidthTabView = tab1View.column(at: 0).width()
let leftColumnWidthTopView = grid.column(at: 0).width(0)
debugPrint("hey", leftColumnWidthTabView, leftColumnWidthTopView)
if leftColumnWidthTabView > leftColumnWidthTopView {
orPress.fit(tab1View.column(at: 0).width() + GridView.interPadding + TabView.padding, orPress.fittingSize.height)
} else {
orPress.fit()
tabView.leftAnchor.constraint(equalTo: tabView.superview!.leftAnchor, constant: leftColumnWidthTopView - leftColumnWidthTabView + 3).isActive = true
}
setView(grid)
}
private func toShowSection(_ postfix: String) -> ([NSView], GridView) {
let toShowExplanations = LabelAndControl.makeLabel(NSLocalizedString("Show the following windows:", comment: ""))
var holdShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Hold", comment: ""), "holdShortcut" + postfix, Preferences.holdShortcut, false, labelPosition: .leftWithoutSeparator)
holdShortcut.append(LabelAndControl.makeLabel(NSLocalizedString("and press:", comment: "")))
let holdAndPress = StackView(holdShortcut)
let appsToShow = LabelAndControl.makeDropdown("appsToShow" + postfix, AppsToShowPreference.allCases)
let spacesToShow = LabelAndControl.makeDropdown("spacesToShow" + postfix, SpacesToShowPreference.allCases)
let screensToShow = LabelAndControl.makeDropdown("screensToShow" + postfix, ScreensToShowPreference.allCases)
let showMinimizedWindows = StackView(LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Minimized", comment: ""), "showMinimizedWindows" + postfix, labelPosition: .right))
let showHiddenWindows = StackView(LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hidden", comment: ""), "showHiddenWindows" + postfix, labelPosition: .right))
let showFullscreenWindows = StackView(LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Fullscreen", comment: ""), "showFullscreenWindows" + postfix, labelPosition: .right))
let nextWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Select next window", comment: ""), "nextWindowShortcut" + postfix, Preferences.nextWindowShortcut[postfix == "" ? 0 : 1], labelPosition: .right)
let toShowDropdowns = StackView([appsToShow, spacesToShow, screensToShow, showMinimizedWindows, showHiddenWindows, showFullscreenWindows], .vertical, false)
toShowDropdowns.spacing = TabView.padding
toShowDropdowns.fit()
let tab = GridView([
[toShowExplanations, toShowDropdowns],
[holdAndPress, StackView(nextWindowShortcut)],
], TabView.padding)
tab.column(at: 0).xPlacement = .trailing
tab.fit()
return (nextWindowShortcut, tab)
}
private static func addShortcut(_ type: KeyEventType, _ shortcut: Shortcut, _ controlId: String) {
removeShortcutIfExists(controlId, type) // remove the previous shortcut
shortcuts[controlId] = shortcut
}
@objc static func shortcutChangedCallback(_ sender: NSControl) {
let controlId = sender.identifier!.rawValue
if controlId == "holdShortcut" {
addShortcut(.up, Shortcut(keyEquivalent: Preferences.holdShortcut)!, controlId)
if let s = nextWindowShortcut {
shortcutChangedCallback(s)
}
} else if controlId == "holdShortcut2" {
addShortcut(.up, Shortcut(keyEquivalent: Preferences.holdShortcut2)!, controlId)
if let s = nextWindowShortcut2 {
shortcutChangedCallback(s)
}
} else {
let newValue = shortcutStringValue(controlId, sender)
if newValue.isEmpty {
removeShortcutIfExists(controlId, .down)
} else {
addShortcut(.down, Shortcut(keyEquivalent: newValue)!, controlId)
}
}
}
static func shortcutStringValue(_ controlId: String, _ sender: NSControl) -> String {
let baseValue = (sender as! RecorderControl).stringValue
if controlId == "nextWindowShortcut" || controlId == "nextWindowShortcut2" {
let holdShortcut = controlId == "nextWindowShortcut" ? Preferences.holdShortcut : Preferences.holdShortcut2
// remove the holdShortcut character in case they also use it in the other shortcuts
return holdShortcut + holdShortcut.reduce(baseValue, { $0.replacingOccurrences(of: String($1), with: "") })
}
return baseValue
}
@objc static func arrowKeysEnabledCallback(_ sender: NSControl) {
let keys = ["←", "→", "↑", "↓"]
if (sender as! NSButton).state == .on {
keys.forEach { addShortcut(.down, Shortcut(keyEquivalent: $0)!, $0) }
} else {
keys.forEach { removeShortcutIfExists($0, .down) }
}
}
private static func removeShortcutIfExists(_ controlId: String, _ type: KeyEventType) {
if let a = shortcuts[controlId] {
shortcuts.removeValue(forKey: controlId)
}
}
}
+2 -147
View File
@@ -1,5 +1,4 @@
import Cocoa
import ShortcutRecorder
import Preferences
class GeneralTab: NSViewController, PreferencePane {
@@ -7,165 +6,21 @@ class GeneralTab: NSViewController, PreferencePane {
let preferencePaneTitle = NSLocalizedString("General", comment: "")
let toolbarItemIcon = NSImage(named: NSImage.preferencesGeneralName)!
static var shortcutActions = [String: ShortcutAction]()
static var shortcutsDependentOnHoldShortcut = [NSControl]()
static var shortcutsActionsBlocks = [
"holdShortcut": { App.app.focusTarget() },
"nextWindowShortcut": { App.app.showUiOrCycleSelection(0) },
"nextWindowShortcut2": { App.app.showUiOrCycleSelection(1) },
"previousWindowShortcut": { App.app.cycleSelection(.trailing) },
"→": { App.app.cycleSelection(.right) },
"←": { App.app.cycleSelection(.left) },
"↑": { App.app.cycleSelection(.up) },
"↓": { App.app.cycleSelection(.down) },
"cancelShortcut": { App.app.hideUi() },
"closeWindowShortcut": { App.app.closeSelectedWindow() },
"minDeminWindowShortcut": { App.app.minDeminSelectedWindow() },
"quitAppShortcut": { App.app.quitSelectedApp() },
"hideShowAppShortcut": { App.app.hideShowSelectedApp() },
]
override func loadView() {
let startAtLogin = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Start at login:", comment: ""), "startAtLogin", extraAction: startAtLoginCallback)
let hideMenubarIcon = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hide menubar icon:", comment: ""), "hideMenubarIcon", extraAction: hideMenubarIconCallback)
var holdShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Hold", comment: ""), "holdShortcut", Preferences.holdShortcut, false, labelPosition: .leftWithoutSeparator)
holdShortcut.append(LabelAndControl.makeLabel(NSLocalizedString("and press:", comment: "")))
let previousWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Select previous window", comment: ""), "previousWindowShortcut", Preferences.previousWindowShortcut, labelPosition: .right)
let cancelShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Cancel and hide", comment: ""), "cancelShortcut", Preferences.cancelShortcut, labelPosition: .right)
let closeWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Close window", comment: ""), "closeWindowShortcut", Preferences.closeWindowShortcut, labelPosition: .right)
let minDeminWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Minimize/Deminimize window", comment: ""), "minDeminWindowShortcut", Preferences.minDeminWindowShortcut, labelPosition: .right)
let quitAppShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Quit app", comment: ""), "quitAppShortcut", Preferences.quitAppShortcut, labelPosition: .right)
let hideShowAppShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Hide/Show app", comment: ""), "hideShowAppShortcut", Preferences.hideShowAppShortcut, labelPosition: .right)
let enableArrows = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Arrow keys", comment: ""), "arrowKeysEnabled", extraAction: GeneralTab.arrowKeysEnabledCallback, labelPosition: .right)
let enableMouse = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Mouse hover", comment: ""), "mouseHoverEnabled", labelPosition: .right)
let holdAndPress = StackView(holdShortcut)
let checkboxesExplanations = LabelAndControl.makeLabel(NSLocalizedString("Select windows using:", comment: ""))
let checkboxes = StackView([StackView(enableArrows), StackView(enableMouse)], .vertical)
let shortcuts = StackView([previousWindowShortcut, cancelShortcut, closeWindowShortcut, minDeminWindowShortcut, quitAppShortcut, hideShowAppShortcut].map { (view: [NSView]) in StackView(view) }, .vertical)
let thenRelease = LabelAndControl.makeLabel(NSLocalizedString("then release:", comment: ""))
let orPress = LabelAndControl.makeLabel(NSLocalizedString("or press:", comment: ""))
let focusSelectedWindow = LabelAndControl.makeLabel(NSLocalizedString("Focus selected window", comment: ""))
let toShowExplanations = LabelAndControl.makeLabel(NSLocalizedString("Show the following windows:", comment: ""))
let tab1 = NSTabViewItem(identifier: 1)
tab1.label = "1"
let (nextWindowShortcut, tab1View) = toShowSection("")
tab1.view = tab1View
let tab2 = NSTabViewItem(identifier: 2)
tab2.label = "2"
let (nextWindowShortcut2, tab2View) = toShowSection("2")
tab2.view = tab2View
let tabView = TabView()
tabView.addTabViewItem(tab1)
tabView.addTabViewItem(tab2)
tabView.tabPosition = .right
tabView.heightAnchor.constraint(equalToConstant: tabView.fittingSize.height - 8).isActive = true
let vertical1 = StackView([toShowExplanations, holdAndPress], .vertical, false, top: 5, bottom: 3)
vertical1.alignment = .trailing
vertical1.distribution = .equalCentering
vertical1.heightAnchor.constraint(equalToConstant: tabView.fittingSize.height - 14).isActive = true
let grid = GridView([
startAtLogin,
hideMenubarIcon,
[vertical1, tabView],
[thenRelease, focusSelectedWindow],
[orPress, shortcuts],
[checkboxesExplanations, checkboxes],
])
grid.column(at: 0).xPlacement = .trailing
grid.row(at: 2).rowAlignment = .none
[2, 5].forEach { grid.row(at: $0).topPadding = GridView.interPadding }
grid.fit()
GeneralTab.shortcutsDependentOnHoldShortcut.append(contentsOf: [enableArrows[0] as! NSControl] +
[nextWindowShortcut, nextWindowShortcut2, previousWindowShortcut, cancelShortcut,
closeWindowShortcut, minDeminWindowShortcut, quitAppShortcut, hideShowAppShortcut].map { $0[0] as! NSControl })
GeneralTab.arrowKeysEnabledCallback(enableArrows[0] as! NSControl)
setView(grid)
startAtLoginCallback(startAtLogin[1] as! NSControl)
hideMenubarIconCallback(hideMenubarIcon[1] as! NSControl)
view = grid
}
private func toShowSection(_ postfix: String) -> ([NSView], NSView) {
let appsToShow = dropdown("appsToShow" + postfix, AppsToShowPreference.allCases)
let spacesToShow = dropdown("spacesToShow" + postfix, SpacesToShowPreference.allCases)
let screensToShow = dropdown("screensToShow" + postfix, ScreensToShowPreference.allCases)
let showMinimizedWindows = StackView(LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Minimized", comment: ""), "showMinimizedWindows" + postfix, labelPosition: .right))
let showHiddenWindows = StackView(LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hidden", comment: ""), "showHiddenWindows" + postfix, labelPosition: .right))
let showFullscreenWindows = StackView(LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Fullscreen", comment: ""), "showFullscreenWindows" + postfix, labelPosition: .right))
let nextWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Select next window", comment: ""), "nextWindowShortcut" + postfix, Preferences.nextWindowShortcut[postfix == "" ? 0 : 1], labelPosition: .right)
let toShowDropdowns = StackView([appsToShow, spacesToShow, screensToShow, showMinimizedWindows, showHiddenWindows, showFullscreenWindows], .vertical, false)
toShowDropdowns.spacing = 8
toShowDropdowns.fit()
let tab = StackView([toShowDropdowns, StackView(nextWindowShortcut)], .vertical, false)
tab.spacing = GridView.padding
tab.fit()
return (nextWindowShortcut, tab)
}
private func dropdown(_ rawName: String, _ macroPreferences: [MacroPreference]) -> NSControl {
let dropdown = LabelAndControl.makeDropDown(rawName, macroPreferences)
return LabelAndControl.setupControl(dropdown, rawName)
}
private static func addShortcut(_ type: KeyEventType, _ shortcut: Shortcut, _ controlId: String) {
removeShortcutIfExists(controlId, type) // remove the previous shortcut
shortcutActions[controlId] = ShortcutAction(shortcut: shortcut, actionHandler: { _ in
let isShortcutInitiatingTheApp = ["nextWindowShortcut", "nextWindowShortcut2"].contains(controlId)
if isShortcutInitiatingTheApp {
App.app.appIsBeingUsed = true
}
if App.app.appIsBeingUsed {
let isShortcutClosingTheUi = ["holdShortcut", "cancelShortcut"].contains(controlId)
if isShortcutClosingTheUi {
App.app.appIsBeingUsed = false
App.app.isFirstSummon = true
}
DispatchQueue.main.async { () -> () in shortcutsActionsBlocks[controlId]!() }
}
return true
})
App.shortcutMonitor.addAction(shortcutActions[controlId]!, forKeyEvent: type)
}
@objc static func shortcutChangedCallback(_ sender: NSControl) {
let controlId = sender.identifier!.rawValue
if controlId == "holdShortcut" {
addShortcut(.up, Shortcut(keyEquivalent: Preferences.holdShortcut)!, controlId)
shortcutsDependentOnHoldShortcut.forEach {
if $0.identifier!.rawValue == "arrowKeysEnabled" {
GeneralTab.arrowKeysEnabledCallback($0)
} else {
GeneralTab.shortcutChangedCallback($0)
}
}
} else {
// remove the holdShortcut character in case they also use it in the other shortcuts
let newValue = Preferences.holdShortcut.reduce((sender as! RecorderControl).stringValue, { $0.replacingOccurrences(of: String($1), with: "") })
if newValue.isEmpty {
removeShortcutIfExists(controlId, .down)
return
}
addShortcut(.down, Shortcut(keyEquivalent: Preferences.holdShortcut + newValue)!, controlId)
}
}
@objc static func arrowKeysEnabledCallback(_ sender: NSControl) {
let keys = ["←", "→", "↑", "↓"]
if (sender as! NSButton).state == .on {
keys.forEach { addShortcut(.down, Shortcut(keyEquivalent: Preferences.holdShortcut + $0)!, $0) }
} else {
keys.forEach { removeShortcutIfExists($0, .down) }
}
}
private static func removeShortcutIfExists(_ controlId: String, _ type: KeyEventType) {
if let a = shortcutActions[controlId] {
App.shortcutMonitor.removeAction(_: a, forKeyEvent: type)
shortcutActions.removeValue(forKey: controlId)
}
}
// adding/removing login item depending on the checkbox state
@@ -36,7 +36,8 @@ class PoliciesTab: NSViewController, PreferencePane {
grid.row(at: 2).topPadding = GridView.interPadding * 1.5
grid.fit()
view = grid
setView(grid)
UserDefaultsEvents.observe()
}