Same issue here! Just upgraded to macOS 27, dragging with mouse dragging window not longer working (when using mac through chrome remote desktop connection)
Claude Code just solved it for me:
Workaround: windows can't be dragged by the title bar over Chrome Remote Desktop on macOS 27
Cause: The Chrome Remote Desktop host (version 156 and earlier) sends drag events whose mouse event number doesn't match the mouse-down that started the drag. macOS 27 ignores those drags, so title-bar moves fail while clicks, resizing and tab dragging still work. Google has fixed this in the host for version 157 (Chromium issue 564169077), but until that ships, the small helper below applies the same correction locally: it copies the mouse-down's event number onto the drag/up events that follow. Physical mouse input already matches and passes through untouched. It only sees mouse button events (no keyboard, no network, no logging of what you click). Check your host version in Finder at /Library/PrivilegedHelperTools/ChromeRemoteDesktopHost (Get Info); remove this helper once it's 157 or later.
Prompt (paste into an AI assistant with access to your Mac, or follow the steps yourself):
Set up a helper on my Mac (macOS 27) that fixes title-bar window dragging over Chrome Remote Desktop. Do exactly the following:
Create the folder ~/crd-dragfix and save this file in it as crd-dragfix.swift, unchanged:
// crd-dragfix: local stopgap for Chromium issue 564169077.
// Copies the mouse-down's event number onto the drag and up events that follow,
// the same correction Google made in the Chrome Remote Desktop host for v157.
// Sees only mouse button events: no keyboard, no logging of clicks, no network.
import Foundation
import ApplicationServices
import CoreGraphics
let verbose = CommandLine.arguments.contains("--verbose")
func log(_ message: String) {
let stamp = ISO8601DateFormatter().string(from: Date())
FileHandle.standardError.write("\(stamp) crd-dragfix: \(message)\n".data(using: .utf8)!)
}
enum Phase { case down, drag, up }
func classify(_ type: CGEventType) -> (button: Int, phase: Phase)? {
switch type {
case .leftMouseDown: return (0, .down)
case .leftMouseDragged: return (0, .drag)
case .leftMouseUp: return (0, .up)
case .rightMouseDown: return (1, .down)
case .rightMouseDragged: return (1, .drag)
case .rightMouseUp: return (1, .up)
case .otherMouseDown: return (2, .down)
case .otherMouseDragged: return (2, .drag)
case .otherMouseUp: return (2, .up)
default: return nil
}
}
var pressNumber: [Int64] = [0, 0, 0]
var pressed: [Bool] = [false, false, false]
var correctedTotal = 0
var tapPort: CFMachPort?
let callback: CGEventTapCallBack = { _, type, event, _ in
if type == .tapDisabledByTimeout || type == .tapDisabledByUserInput {
if let tapPort { CGEvent.tapEnable(tap: tapPort, enable: true) }
log("the system paused the event tap; re-enabled it")
return Unmanaged.passUnretained(event)
}
guard let kind = classify(type) else { return Unmanaged.passUnretained(event) }
let button = kind.button
let number = event.getIntegerValueField(.mouseEventNumber)
switch kind.phase {
case .down:
pressNumber[button] = number
pressed[button] = true
case .drag, .up:
if pressed[button] && number != pressNumber[button] {
event.setIntegerValueField(.mouseEventNumber, value: pressNumber[button])
correctedTotal += 1
if correctedTotal == 1 {
log("corrected the first mismatched drag event; the fix is working")
}
if verbose {
log("event type \(type.rawValue): number \(number) -> \(pressNumber[button])")
}
}
if kind.phase == .up { pressed[button] = false }
}
return Unmanaged.passUnretained(event)
}
var mask: CGEventMask = 0
let watched: [CGEventType] = [
.leftMouseDown, .leftMouseDragged, .leftMouseUp,
.rightMouseDown, .rightMouseDragged, .rightMouseUp,
.otherMouseDown, .otherMouseDragged, .otherMouseUp,
]
for t in watched { mask |= CGEventMask(1) << CGEventMask(t.rawValue) }
if !AXIsProcessTrusted() {
let options = [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String: true] as CFDictionary
_ = AXIsProcessTrustedWithOptions(options)
log("waiting for permission: System Settings > Privacy & Security > Accessibility > crd-dragfix")
while !AXIsProcessTrusted() { sleep(2) }
log("Accessibility permission granted")
}
guard let tap = CGEvent.tapCreate(tap: .cgSessionEventTap, place: .headInsertEventTap,
options: .defaultTap, eventsOfInterest: mask,
callback: callback, userInfo: nil) else {
log("could not create the event tap even though Accessibility is granted")
exit(1)
}
tapPort = tap
let source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0)
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, .commonModes)
CGEvent.tapEnable(tap: tap, enable: true)
log("active on \(ProcessInfo.processInfo.operatingSystemVersionString)")
CFRunLoopRun()In Terminal, build and sign it (if swiftc is missing, run xcode-select --install first):
cd ~/crd-dragfix
xcrun swiftc -O -swift-version 5 -o crd-dragfix crd-dragfix.swift \
-framework ApplicationServices -framework CoreGraphics
codesign --force --sign - --identifier local.crd-dragfix crd-dragfixMake it run now and at every login:
mkdir -p ~/Library/LaunchAgents ~/Library/Logs
cat > ~/Library/LaunchAgents/local.crd-dragfix.plist <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>local.crd-dragfix</string>
<key>ProgramArguments</key><array><string>$HOME/crd-dragfix/crd-dragfix</string></array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>ThrottleInterval</key><integer>10</integer>
<key>ProcessType</key><string>Interactive</string>
<key>StandardErrorPath</key><string>$HOME/Library/Logs/crd-dragfix.log</string>
</dict>
</plist>
EOF
launchctl bootout gui/$(id -u)/local.crd-dragfix 2>/dev/null
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/local.crd-dragfix.plistWhen macOS asks, allow crd-dragfix in System Settings > Privacy & Security > Accessibility. (If rebuilding later, remove the old crd-dragfix entry with the minus button first, then enable the new one.)
Drag a window by its title bar over Chrome Remote Desktop. tail ~/Library/Logs/crd-dragfix.log should show "corrected the first mismatched drag event; the fix is working".
To remove it once the host is version 157 or later:
launchctl bootout gui/$(id -u)/local.crd-dragfix
rm ~/Library/LaunchAgents/local.crd-dragfix.plist
rm -r ~/crd-dragfixThen remove crd-dragfix from the Accessibility list.
Topic:
Community
SubTopic:
Apple Developers
Tags: