Giữ Dock đứng yên một màn hình trên macOS đa màn hình
Tóm tắt
Trên opera-macbook chạy hai màn hình (built-in Liquid Retina XDR + Samsung LF24T450F), Dock nhảy sang bất kỳ màn hình nào con trỏ chạm vào cạnh dưới. Mẹo defaults write com.apple.dock autohide-delay — nền tảng của hai app Automator tự chế trước đây — đã hết tác dụng từ macOS Sequoia, và được xác minh là vô hiệu trên macOS 26.5.2 ngày 2026-08-21. Giải pháp thay thế duy nhất còn hiệu lực là chặn ở tầng sự kiện chuột bằng cgeventtap; đã tự viết lại app Dock Stick Forever v2 theo hướng này.
Điểm chính
- macOS chuyển Dock sang màn hình mà con trỏ ép vào cạnh dưới. Đây là hành vi mặc định, không có tuỳ chọn tắt trong System Settings.
- Mẹo cũ đặt
autohide-delaythành một số rất lớn (999999 hoặc 31536000 giây), với ý tưởng kéo dài vô hạn khoảng chờ trước khi Dock chịu đổi màn hình. - Mẹo này chết từ macOS Sequoia. Apple đổi hành vi Dock đa màn hình và trả lời trên Developer Forums rằng đó là expected behavior, không phải lỗi.
- Không có key
defaultsnào thay thế. RepoJakubBelau/DockAnchorquảng cáo “one-command fix” nhưng mởinstall.shra thì chính là mẹoautohide-delaycộng LaunchAgent giữ giá trị — tức đã hỏng sẵn. - Cách còn hiệu lực: dựng
CGEventTap, chặn con trỏ không cho chạm dải vài điểm sát cạnh dưới của các màn hình không được neo. Điều kiện kích hoạt của Dock không bao giờ đúng vì con trỏ không bao giờ tới đó.
Bằng chứng
Xác minh mẹo cũ đã chết trên chính máy này (2026-08-21, macOS 26.5.2 build 25F84):
defaults read com.apple.dock autohide-delay→3.1536e+07(Dock Lock đã áp dụng).~/Library/Preferences/com.apple.dock.plistsửa lúc 09:22; tiến trình Dock khởi động lúc 09:22:50.- Vì Dock khởi động sau khi plist được ghi, giá trị chắc chắn đã được nạp. Loại trừ giả thuyết “quên
killall Dock” và “giá trị bị macOS reset”. - Dock vẫn nhảy màn hình bình thường → mẹo được đọc nhưng không còn ảnh hưởng.
Hình học màn hình thật, đọc bằng CGDisplayBounds:
| Display | ID | Main | Origin | Size | maxY |
|---|---|---|---|---|---|
| Built-in Liquid Retina XDR | 1 | có | (0, 0) | 1512×982 | 982 |
| Samsung LF24T450F | 3 | không | (1512, −98) | 1920×1080 | 982 |
Hai màn có cùng maxY — mép dưới thẳng hàng. Nên thuật toán phải phân biệt màn hình theo định danh, không thể dựa vào toạ độ đáy.
Lịch sử các bản tự chế
| Bản | Vị trí | Kỹ thuật | Tình trạng |
|---|---|---|---|
Dock Stick Forever.app (2025-08-12) | iCloud Automator Documents | Automator applet, một dòng defaults write autohide-delay 999999 | Vô hiệu từ Sequoia |
Dock Lock.app v1.3 (2026-08-10) | ~/Applications/ | Automator applet, thêm dialog Áp dụng/Khôi phục, DELAY=31536000 | Vô hiệu từ Sequoia |
Dock Stick Forever v2 (2026-08-21) | ~/Code/dock-stick-forever | Swift, CGEventTap chặn con trỏ | Đang dùng |
Giải pháp đang dùng
App Swift tại ~/Code/dock-stick-forever, cài vào ~/Applications/Dock Stick Forever.app. Từ 2026-08-21 đã mở mã nguồn công khai (MIT) tại binhsonnguyen/dock-stick-forever, release v1.0.0 kèm bản build universal (arm64 + x86_64), ký ad-hoc không notarize:
- Menu bar agent (
LSUIElement), ~172 KB, ký ad-hoc. - Dựng
CGEventTapở.cgSessionEventTap/.headInsertEventTap, bắtmouseMovedvà các sự kiện drag. - Với mỗi mẫu vị trí: nếu con trỏ nằm trong dải 4 pt sát cạnh dưới của màn hình không được neo thì ghi đè
event.location, kéo lên mép dải. Chuyển động ngang không bị ảnh hưởng. - Định danh màn hình theo UUID (
CGDisplayCreateUUIDFromDisplayID) chứ không theoCGDirectDisplayID, vì ID bị cấp lại sau khi ngủ/rút cáp/khởi động lại. - Rút màn hình đang neo thì tự lùi về màn hình chính — nếu không, mọi màn đều bị canh và con trỏ bị nhốt khỏi cạnh dưới ở khắp nơi.
- Phần hình học tách thành module thuần (
DockStickCore), có 9 test chạy bằngswift testkhông cần cắm màn hình hay rê chuột.
Đánh đổi: cần quyền Accessibility, có tiến trình chạy nền, và vài điểm sát đáy màn phụ không bấm được.
Các hướng khác đã cân nhắc
- Tắt “Displays have separate Spaces” (System Settings → Desktop & Dock → Mission Control). Là cách chính thức duy nhất của Apple. Đổi lại: mất menu bar riêng mỗi màn, mất fullscreen độc lập từng màn, phải đăng xuất/đăng nhập lại. Máy đang bật tuỳ chọn này (key
com.apple.spaces spans-displayschưa set = mặc định bật). - Đưa Dock sang trái/phải: Dock bám mép ngoài cùng của bố cục, hết đường nhảy. Rẻ nhất nhưng đổi thói quen dùng.
- bwya77/DockAnchor (MIT, Swift): cùng kỹ thuật event tap, nhiều tính năng hơn (profile, sơ đồ màn hình trực quan). Lựa chọn tốt nếu không muốn tự bảo trì.
Khái niệm liên quan
Xác nhận hoạt động (2026-08-21)
Đã kiểm chứng thực tế trên máy, ở cấu hình mặc định: dải chặn 4 pt, không cần bật “chế độ mạnh”. Dock đứng yên ở màn built-in khi rê con trỏ xuống cạnh dưới màn Samsung.
Kết luận rút ra:
- Ghi đè
event.locationtrong event tap là đủ để window server dời con trỏ; không cần tớiCGWarpMouseCursorPosition. Đường warp vẫn giữ trong app làm phương án dự phòng. - Dải 4 pt đủ vượt độ sâu kích hoạt thật của Dock, và mỏng tới mức không cảm nhận được khi thao tác.
Cùng ngày đã dọn dấu vết của cách tiếp cận cũ:
- Xoá
autohide-delayvàautohide-time-modifierkhỏicom.apple.dock(autohidegiữ nguyên0). Đây từng là bẫy: để lại thì sau này bật auto-hide Dock sẽ không bao giờ hiện ra. - Chuyển
Dock Lock.appvà bản AutomatorDock Stick Forever.app(trong iCloud Drive) vào Thùng rác.
Câu hỏi mở
- Quyền Accessibility gắn với cdhash của bản ký ad-hoc, nên mỗi lần chạy lại
build-app.shlà phải cấp quyền lại. Chưa quyết có đáng đăng ký Developer ID để ký ổn định không.