Współtworzenie
Zbuduj BetterCmdTab ze źródeł, uruchom testy i doprowadź pull request do scalenia.
Mile widziane są zarówno zgłoszenia, jak i pull requesty — raporty błędów, pomysły na
funkcje oraz zmiany kodu. Ta strona odzwierciedla plik
CONTRIBUTING.md
w repozytorium; jeśli treści kiedykolwiek się różnią, ten plik jest źródłem prawdy.
Podstawowe zasady
Te cztery zasady nie podlegają negocjacji — PR, który łamie jedną z nich, będzie wymagał zmian bez względu na jakość funkcji.
| Zasada | Uzasadnienie |
|---|---|
| Tylko AppKit | Bez SwiftUI, Catalyst i zewnętrznych frameworków UI. Przełącznik musi działać natywnie i otwierać się natychmiast. |
| Bez telemetrii | Bez analityki, raportowania awarii i ruchu sieciowego w tle. Dozwolone są wyłącznie żądania sprawdzające aktualizacje w GitHub Releases. |
| macOS 13.0 pozostaje minimalną wersją | Funkcje nowszych systemów są chronione przez if #available i mają łagodny mechanizm zastępczy. |
| Ścieżka krytyczna pozostaje szybka | Wszystko, co działa podczas ⌘Tab, wykonuje się poza głównym wątkiem albo jest mierzone. |
Budowanie
git clone https://github.com/rokartur/BetterCmdTab.git
cd BetterCmdTab
xcodebuild -scheme "BetterCmdTab Debug" -configuration Debug buildWymagane są Xcode 16+ i SDK macOS 26. Ścieżki kodu Liquid Glass są ograniczone do
macOS 26 — budowanie ze starszym SDK nadal działa, ale aplikacja korzysta wtedy z
NSVisualEffectView w czasie działania.
Zanim uznasz, że zmiana nie działa, uruchom aplikację raz i przyznaj uprawnienie Dostępność. Bez niego przełącznik się nie uruchamia, więc ⌘Tab po prostu nic nie robi — zobacz Szybki start.
Uruchamianie testów
# whole suite
xcodebuild -scheme "BetterCmdTab Debug" -destination 'platform=macOS' test
# one suite
xcodebuild -scheme "BetterCmdTab Debug" -destination 'platform=macOS' \
test -only-testing:BetterCmdTabTests/FuzzyMatchTestsTesty używają Swift Testing (import Testing, @Suite / @Test), a nie XCTest.
Nie ma metod testXxx(), dlatego pojedynczy przypadek należy wskazać nazwą jego funkcji
Swift:
xcodebuild -scheme "BetterCmdTab Debug" -destination 'platform=macOS' \
test -only-testing:BetterCmdTabTests/FuzzyMatchTests/noMatchObejmują wyłącznie czystą logikę — metryki przełącznika, etykiety wierszy, filtrowanie katalogu, dopasowanie rozmyte, analizę aktualizacji, wybór Liquid Glass i przenośność ustawień. Zachowanie UI jest sprawdzane ręcznie: przełącznik potrzebuje działającego WindowServer i uprawnienia Dostępność, dlatego ten obszar nie działa w środowisku bez interfejsu graficznego i nie należy do testów jednostkowych.
Gdzie znajdują się poszczególne elementy
Kod jest niewielki. Od tych plików warto zacząć lekturę.
| Ścieżka | Działanie |
|---|---|
Input/HotkeyTap.swift | Globalne przechwytywanie CGEvent we własnym wątku; wykrywa skrót ⌘Tab i blokuje natywny przełącznik |
Switcher/SwitcherController.swift | Maszyna stanów — zaznaczanie, skok po literze, wyszukiwanie, przechodzenie do kart |
Switcher/SwitcherView.swift | Układa widoki listy / siatki / podglądu okien |
Switcher/SwitcherPanel.swift | Nieaktywujący panel i przypinanie jego aktywnego stanu |
Catalog/AppCatalog.swift | Wylicza aplikacje i okna przez Accessibility API |
Catalog/AppCatalogCache.swift | Przyrostowa pamięć podręczna zasilana obserwatorami AX i aktualizacjami MRU |
Windows/Activator.swift | Aktywowanie, podnoszenie, zamykanie, ukrywanie, kończenie |
Windows/MRUTracker.swift | Kolejność według ostatniego użycia |
System/PrivateAPIs.swift | Cały prywatny kod CGS / SkyLight, odizolowany w jednym pliku na potrzeby przeglądu |
Settings/ | Natywne okno ustawień AppKit, jeden kontroler na panel |
Dodawanie preferencji
Preferencje są kontraktem, a nie tylko zmienną — trzeba zaktualizować kilka elementów.
- Dodaj klucz do wyliczenia
KeyswApp/Preferences.swift, z prefiksemSwitcher.. Ciąg klucza jest kontraktem:CatalogFilteriSwitcherControllerodczytują niektóre klucze bezpośrednio zUserDefaultsw wątku tła, więc zmiana nazwy wymaga aktualizacji obu stron. - Dodaj odpowiednią właściwość
@PublishedzdidSet, który ją zapisuje. Zabezpiecz zapis przezguard oldValue != newValue else { return }— to zabezpieczenie powstrzymujereloadFromDefaults()przed ponownym zapisywaniem każdego klucza podczas importu. - Dodaj odpowiedni odczyt do
reloadFromDefaults()wraz z wartością domyślną. - Udokumentuj ją w
App/ConfigSchemaDocs.swift. Zasila to generowanyschema.json, więc pominięty tutaj klucz jest prawidłowy, ale nieudokumentowany — bez uzupełniania w edytorze i dokumentacji po wskazaniu kursorem. - Udostępnij ją we właściwym panelu ustawień. Wszystko, co niestabilne lub nowe, trafia do domyślnie wyłączonego panelu Eksperymentalne.
- Jeśli wpływa na czystą logikę, dodaj test.
Nowe klucze są automatycznie uwzględniane przez eksport/import i plik konfiguracyjny —
oba mechanizmy przechodzą przez całą przestrzeń nazw Switcher.*, zamiast korzystać z
ręcznie przygotowanej listy.
Dokumentacja konfiguracji na tej stronie jest generowana z kopii
tego samego pliku schema.json. Po dodaniu preferencji odśwież ją, aby dokumentacja
nie pozostawała w tyle — zobacz docs/README.md.
Lista kontrolna pull requestu
- Projekt buduje się bez błędów i nowych ostrzeżeń.
- Istniejące testy nadal przechodzą; nowa funkcja z czystą logiką zawiera co najmniej jeden test.
- Bez zakomentowanego kodu, martwych gałęzi i pozostawionego
print— logowanie przezLog.*(os.Logger). - Jeden logiczny zakres zmian na PR. Refaktoryzacje oddziel od zmian zachowania.
- Komunikaty commitów mają postać
type: short summary—fix:,feat:,perf:,refactor:,docs:,chore:— a treść wyjaśniająca dlaczego jest zawijana do około 72 znaków.
Zgłaszanie błędu
Otwórz zgłoszenie i podaj:
- Wersję macOS (
sw_vers) - Wersję BetterCmdTab (pasek menu → Informacje)
- Kroki odtworzenia — dokładną sekwencję klawiszy, otwarte aplikacje i używany monitor
- Oczekiwane zachowanie oraz to, co faktycznie się wydarzyło
- Krótkie nagranie ekranu, jeśli problem jest wizualny (migotanie fokusu, układ, renderowanie szkła)
W przypadku awarii dołącz plik .ips z ~/Library/Logs/DiagnosticReports/.
Proponowanie funkcji
Opisz oczekiwany sposób pracy, a nie implementację. „Chcę filtrować przełącznik według kategorii aplikacji” jest bardziej użyteczne niż „dodaj listę rozwijaną kategorii” — implementację można przedyskutować, ale to podstawowa potrzeba kieruje projektem.
Bezpieczeństwo
Jeśli znajdziesz lukę — cokolwiek, co pozwala zewnętrznej aplikacji odczytywać stan przełącznika, przechwytywać skróty lub zwiększać uprawnienia za pomocą Dostępności przyznanej BetterCmdTab — otwórz prywatne zgłoszenie bezpieczeństwa, a nie publiczne zgłoszenie.
Licencja
BetterCmdTab jest objęty licencją GPL v3. Wysyłając swój wkład, zgadzasz się, że Twoja praca również jest objęta tą licencją.