Post

Replies

Boosts

Views

Activity

NSToolbarItemViewer no longer resolves hit-testing to a view-based NSToolbarItem's subviews — interactive controls in custom toolbar item views receive no mouse events (regression in macOS 27 beta)
Area: AppKit / NSToolbar Type: Incorrect/Unexpected Behavior (Regression) Summary On macOS 27 beta, when an NSToolbarItem uses a custom view (NSToolbarItem.view) containing interactive controls (e.g. NSButton), clicks on those controls are silently swallowed. Window-level hit-testing stops at the private NSToolbarItemViewer instead of descending into the item's view hierarchy, so the controls never receive mouseDown and their target/action never fires. The same code works correctly on macOS 26 and earlier. This breaks the long-standing, documented view-based toolbar item pattern. Any app that places custom interactive controls inside toolbar items is affected. Steps to Reproduce Create a window with an NSToolbar. In toolbar(_:itemForItemIdentifier:willBeInsertedIntoToolbar:), return an NSToolbarItem whose view is a container NSView holding an NSButton with a target/action. Run on macOS 27 beta and click the button. Minimal repro (complete AppDelegate): import Cocoa @main class AppDelegate: NSObject, NSApplicationDelegate, NSToolbarDelegate { var window: NSWindow! func applicationDidFinishLaunching(_ notification: Notification) { window = NSWindow(contentRect: NSRect(x: 200, y: 200, width: 600, height: 400), styleMask: [.titled, .closable, .resizable], backing: .buffered, defer: false) let toolbar = NSToolbar(identifier: "Main") toolbar.delegate = self window.toolbar = toolbar window.makeKeyAndOrderFront(nil) } func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier id: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { let item = NSToolbarItem(itemIdentifier: id) let container = NSView(frame: NSRect(x: 0, y: 0, width: 120, height: 28)) let button = NSButton(title: "Click Me", target: self, action: #selector(clicked)) button.frame = container.bounds container.addSubview(button) item.view = container return item } @objc func clicked() { NSLog("BUTTON CLICKED") } // never logged on macOS 27 beta func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { [NSToolbarItem.Identifier("CustomItem")] } func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { toolbarDefaultItemIdentifiers(toolbar) } } Expected Results: Clicking the button highlights it and fires its action, as on macOS 26 and every earlier release: window hit-testing resolves to the NSButton inside the toolbar item's custom view. Actual Results The click is silently consumed. The button never receives mouseDown, its action never fires, and no toolbar item action is sent either (the item is view-based and has no target/action of its own). Diagnostic Evidence We instrumented hitTest(_:) throughout the hierarchy in our production app and observed, for a single leftMouseDown over the button: The custom subview's own hitTest is invoked during the traversal and correctly returns the NSButton. However, hit-testing initiated from the window's frame view (NSThemeFrame) resolves to NSToolbarItemViewer itself — the subview's result is discarded on the way up. Observed hit path: NSToolbarItemViewer <- NSToolbarView <- NSTitlebarView <- NSTitlebarContainerView <- NSThemeFrame Consequently AppKit dispatches mouseDown to NSToolbarItemViewer, which does nothing for a view-based item, and the event is dropped. This looks like an extension of the macOS 26 beta issue where NSGlassContainerView inside NSToolbarView intercepted hit-testing over the title bar (FB18201935, developer forums thread 788928). On macOS 27 the interception now also applies inside NSToolbarItemViewer for view-based items. Impact All interactive controls hosted in view-based toolbar items are unusable: buttons, search fields, segmented controls, etc. In our production app (RingCentral Video, a video-conferencing client), every in-meeting title-bar control (meeting info, network quality, view switcher, report) stopped responding on macOS 27 beta. We have shipped an application-level workaround that re-dispatches the event to the control when window hit-testing terminates at an ancestor of it, but this requires every affected app to implement custom event routing around a private view's behavior. FB24375035
Topic: UI Frameworks SubTopic: AppKit
1
0
194
Aug ’26
How to get accurate Mouse/Trackpad deltas on macOS when using CGWarpMouseCursorPosition?
I am working on a remote control application for macOS where I need to maintain two "virtual" cursors: Remote Cursor: Follows the remote user's movements. Local Cursor: Follows the local user's physical mouse/trackpad movements. To move the system cursor (for the remote side), I use CGWarpMouseCursorPosition as follows: void DualCursorMac::UpdateSystemCursorPosition(int x, int y) { CGPoint point = CGPointMake(static_cast<CGFloat>(x), static_cast<CGFloat>(y)); // Warp the cursor to match remote coordinates CGWarpMouseCursorPosition(point); } Meanwhile, I use a CGEventTap to monitor local physical movements to update my local virtual cursor's UI: CGEventRef Mouse::MouseTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { if (remoteControlMode) { // We want to suppress system cursor movement but still read the delta const int deltaX = static_cast<int>(CGEventGetIntegerValueField(event, kCGMouseEventDeltaX)); const int deltaY = static_cast<int>(CGEventGetIntegerValueField(event, kCGMouseEventDeltaY)); NSLog(@"MouseTapCallback: delta:(%d, %d)", deltaX, deltaY); // Update local virtual cursor UI based on deltas... return nullptr; // Consume the event } return event; } The Problem: When CGWarpMouseCursorPosition is called frequently to update the system cursor, it interferes with the kCGMouseEventDeltaX/Y values in the Event Tap. Specifically, if the local user moves the trackpad slowly (expecting deltas of 1 or 2), but a "Warp" occurs simultaneously (e.g., jumping the cursor from (100, 100) to (300, 300)), the deltaX and deltaY in the callback suddenly spike to very large values. It seems the system calculates the delta based on the new warped position rather than the pure physical displacement of the trackpad. This makes the local virtual cursor "jump" erratically and makes it impossible to track smooth local movement during remote control. My Question: Is there a way to get the "raw" or "pure" physical relative movement (delta) from the trackpad/mouse that is independent of the system cursor's absolute position or warping? Are there alternative APIs (perhaps IOKit or different CGEvent fields) that would allow me to get consistent deltas even when the cursor is being warped programmatically?
0
0
1.3k
Feb ’26
NSToolbarItemViewer no longer resolves hit-testing to a view-based NSToolbarItem's subviews — interactive controls in custom toolbar item views receive no mouse events (regression in macOS 27 beta)
Area: AppKit / NSToolbar Type: Incorrect/Unexpected Behavior (Regression) Summary On macOS 27 beta, when an NSToolbarItem uses a custom view (NSToolbarItem.view) containing interactive controls (e.g. NSButton), clicks on those controls are silently swallowed. Window-level hit-testing stops at the private NSToolbarItemViewer instead of descending into the item's view hierarchy, so the controls never receive mouseDown and their target/action never fires. The same code works correctly on macOS 26 and earlier. This breaks the long-standing, documented view-based toolbar item pattern. Any app that places custom interactive controls inside toolbar items is affected. Steps to Reproduce Create a window with an NSToolbar. In toolbar(_:itemForItemIdentifier:willBeInsertedIntoToolbar:), return an NSToolbarItem whose view is a container NSView holding an NSButton with a target/action. Run on macOS 27 beta and click the button. Minimal repro (complete AppDelegate): import Cocoa @main class AppDelegate: NSObject, NSApplicationDelegate, NSToolbarDelegate { var window: NSWindow! func applicationDidFinishLaunching(_ notification: Notification) { window = NSWindow(contentRect: NSRect(x: 200, y: 200, width: 600, height: 400), styleMask: [.titled, .closable, .resizable], backing: .buffered, defer: false) let toolbar = NSToolbar(identifier: "Main") toolbar.delegate = self window.toolbar = toolbar window.makeKeyAndOrderFront(nil) } func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier id: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { let item = NSToolbarItem(itemIdentifier: id) let container = NSView(frame: NSRect(x: 0, y: 0, width: 120, height: 28)) let button = NSButton(title: "Click Me", target: self, action: #selector(clicked)) button.frame = container.bounds container.addSubview(button) item.view = container return item } @objc func clicked() { NSLog("BUTTON CLICKED") } // never logged on macOS 27 beta func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { [NSToolbarItem.Identifier("CustomItem")] } func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { toolbarDefaultItemIdentifiers(toolbar) } } Expected Results: Clicking the button highlights it and fires its action, as on macOS 26 and every earlier release: window hit-testing resolves to the NSButton inside the toolbar item's custom view. Actual Results The click is silently consumed. The button never receives mouseDown, its action never fires, and no toolbar item action is sent either (the item is view-based and has no target/action of its own). Diagnostic Evidence We instrumented hitTest(_:) throughout the hierarchy in our production app and observed, for a single leftMouseDown over the button: The custom subview's own hitTest is invoked during the traversal and correctly returns the NSButton. However, hit-testing initiated from the window's frame view (NSThemeFrame) resolves to NSToolbarItemViewer itself — the subview's result is discarded on the way up. Observed hit path: NSToolbarItemViewer <- NSToolbarView <- NSTitlebarView <- NSTitlebarContainerView <- NSThemeFrame Consequently AppKit dispatches mouseDown to NSToolbarItemViewer, which does nothing for a view-based item, and the event is dropped. This looks like an extension of the macOS 26 beta issue where NSGlassContainerView inside NSToolbarView intercepted hit-testing over the title bar (FB18201935, developer forums thread 788928). On macOS 27 the interception now also applies inside NSToolbarItemViewer for view-based items. Impact All interactive controls hosted in view-based toolbar items are unusable: buttons, search fields, segmented controls, etc. In our production app (RingCentral Video, a video-conferencing client), every in-meeting title-bar control (meeting info, network quality, view switcher, report) stopped responding on macOS 27 beta. We have shipped an application-level workaround that re-dispatches the event to the control when window hit-testing terminates at an ancestor of it, but this requires every affected app to implement custom event routing around a private view's behavior. FB24375035
Topic: UI Frameworks SubTopic: AppKit
Replies
1
Boosts
0
Views
194
Activity
Aug ’26
How to get accurate Mouse/Trackpad deltas on macOS when using CGWarpMouseCursorPosition?
I am working on a remote control application for macOS where I need to maintain two "virtual" cursors: Remote Cursor: Follows the remote user's movements. Local Cursor: Follows the local user's physical mouse/trackpad movements. To move the system cursor (for the remote side), I use CGWarpMouseCursorPosition as follows: void DualCursorMac::UpdateSystemCursorPosition(int x, int y) { CGPoint point = CGPointMake(static_cast<CGFloat>(x), static_cast<CGFloat>(y)); // Warp the cursor to match remote coordinates CGWarpMouseCursorPosition(point); } Meanwhile, I use a CGEventTap to monitor local physical movements to update my local virtual cursor's UI: CGEventRef Mouse::MouseTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { if (remoteControlMode) { // We want to suppress system cursor movement but still read the delta const int deltaX = static_cast<int>(CGEventGetIntegerValueField(event, kCGMouseEventDeltaX)); const int deltaY = static_cast<int>(CGEventGetIntegerValueField(event, kCGMouseEventDeltaY)); NSLog(@"MouseTapCallback: delta:(%d, %d)", deltaX, deltaY); // Update local virtual cursor UI based on deltas... return nullptr; // Consume the event } return event; } The Problem: When CGWarpMouseCursorPosition is called frequently to update the system cursor, it interferes with the kCGMouseEventDeltaX/Y values in the Event Tap. Specifically, if the local user moves the trackpad slowly (expecting deltas of 1 or 2), but a "Warp" occurs simultaneously (e.g., jumping the cursor from (100, 100) to (300, 300)), the deltaX and deltaY in the callback suddenly spike to very large values. It seems the system calculates the delta based on the new warped position rather than the pure physical displacement of the trackpad. This makes the local virtual cursor "jump" erratically and makes it impossible to track smooth local movement during remote control. My Question: Is there a way to get the "raw" or "pure" physical relative movement (delta) from the trackpad/mouse that is independent of the system cursor's absolute position or warping? Are there alternative APIs (perhaps IOKit or different CGEvent fields) that would allow me to get consistent deltas even when the cursor is being warped programmatically?
Replies
0
Boosts
0
Views
1.3k
Activity
Feb ’26