Parcourir la source

display(macOS): fix simultaneous mouse buttons

Fixes #7068
osy il y a 4 jours
Parent
commit
fa8daa1b77

+ 2 - 2
Intents/UTMInputIntent.swift

@@ -217,9 +217,9 @@ struct UTMMouseClickIntent: UTMIntent {
         try await vm.changeInputTablet(true)
         input.sendMousePosition(mouseButton.toSpiceButton(), absolutePoint: CGPoint(x: xPosition, y: yPosition), forMonitorID: monitorNumber-1)
         try await Task.sleep(nanoseconds: kDelayNs)
-        input.sendMouseButton(mouseButton.toSpiceButton(), pressed: true)
+        input.sendMouseButton(mouseButton.toSpiceButton(), mask: [], pressed: true)
         try await Task.sleep(nanoseconds: kDelayNs)
-        input.sendMouseButton(mouseButton.toSpiceButton(), pressed: false)
+        input.sendMouseButton(mouseButton.toSpiceButton(), mask: [], pressed: false)
         return .result()
     }
 }

+ 10 - 10
Platform/macOS/Display/VMDisplayQemuMetalWindowController.swift

@@ -537,7 +537,7 @@ extension VMDisplayQemuMetalWindowController: VMMetalViewInputDelegate {
         self.window?.subtitle = defaultSubtitle
     }
     
-    func mouseMove(absolutePoint: CGPoint, button: CSInputButton) {
+    func mouseMove(absolutePoint: CGPoint, buttonMask: CSInputButton) {
         guard let window = self.window else { return }
         guard let vmInput = vmInput, !vmInput.serverModeCursor else {
             logger.trace("requesting client mode cursor")
@@ -551,18 +551,18 @@ extension VMDisplayQemuMetalWindowController: VMMetalViewInputDelegate {
         let newY = (frameSize.height - absolutePoint.y) * currentScreenScale / viewportScale
         let point = CGPoint(x: newX, y: newY)
         logger.trace("move cursor: cocoa (\(absolutePoint.x), \(absolutePoint.y)), native (\(newX), \(newY))")
-        vmInput.sendMousePosition(button, absolutePoint: point, forMonitorID: vmDisplay?.monitorID ?? 0)
+        vmInput.sendMousePosition(buttonMask, absolutePoint: point, forMonitorID: vmDisplay?.monitorID ?? 0)
         vmDisplay?.cursor?.move(to: point) // required to show cursor on screen
     }
     
-    func mouseMove(relativePoint: CGPoint, button: CSInputButton) {
+    func mouseMove(relativePoint: CGPoint, buttonMask: CSInputButton) {
         guard let vmInput = vmInput, vmInput.serverModeCursor else {
             logger.trace("requesting server mode cursor")
             qemuVM.requestInputTablet(false)
             return
         }
         let translated = CGPoint(x: relativePoint.x, y: -relativePoint.y)
-        vmInput.sendMouseMotion(button, relativePoint: translated, forMonitorID: vmDisplay?.monitorID ?? 0)
+        vmInput.sendMouseMotion(buttonMask, relativePoint: translated, forMonitorID: vmDisplay?.monitorID ?? 0)
     }
     
     private func modifyMouseButton(_ button: CSInputButton) -> CSInputButton {
@@ -575,17 +575,17 @@ extension VMDisplayQemuMetalWindowController: VMMetalViewInputDelegate {
         return buttonMod
     }
     
-    func mouseDown(button: CSInputButton) {
-        vmInput?.sendMouseButton(modifyMouseButton(button), pressed: true)
+    func mouseDown(button: CSInputButton, mask: CSInputButton) {
+        vmInput?.sendMouseButton(modifyMouseButton(button), mask: modifyMouseButton(mask), pressed: true)
     }
     
-    func mouseUp(button: CSInputButton) {
-        vmInput?.sendMouseButton(modifyMouseButton(button), pressed: false)
+    func mouseUp(button: CSInputButton, mask: CSInputButton) {
+        vmInput?.sendMouseButton(modifyMouseButton(button), mask: modifyMouseButton(mask), pressed: false)
     }
     
-    func mouseScroll(dy: CGFloat, button: CSInputButton) {
+    func mouseScroll(dy: CGFloat, buttonMask: CSInputButton) {
         let scrollDy = isInvertScroll ? -dy : dy
-        vmInput?.sendMouseScroll(.smooth, button: button, dy: scrollDy)
+        vmInput?.sendMouseScroll(.smooth, buttonMask: buttonMask, dy: scrollDy)
     }
     
     private func sendExtendedKey(_ button: CSInputKey, keyCode: Int) {

+ 20 - 14
Platform/macOS/Display/VMMetalView.swift

@@ -107,40 +107,40 @@ class VMMetalView: MTKView {
     
     override func mouseDown(with event: NSEvent) {
         logger.trace("mouse down: \(event.buttonNumber)")
-        inputDelegate?.mouseDown(button: .left)
+        inputDelegate?.mouseDown(button: .left, mask: NSEvent.pressedMouseButtons.inputButtons())
     }
     
     override func rightMouseDown(with event: NSEvent) {
         logger.trace("right mouse down: \(event.buttonNumber)")
-        inputDelegate?.mouseDown(button: .right)
+        inputDelegate?.mouseDown(button: .right, mask: NSEvent.pressedMouseButtons.inputButtons())
     }
     
     override func otherMouseDown(with event: NSEvent) {
         logger.trace("other mouse down: \(event.buttonNumber)")
         switch event.buttonNumber {
-        case 2: inputDelegate?.mouseDown(button: .middle)
-        case 3: inputDelegate?.mouseDown(button: .side)
-        case 4: inputDelegate?.mouseDown(button: .extra)
+        case 2: inputDelegate?.mouseDown(button: .middle, mask: NSEvent.pressedMouseButtons.inputButtons())
+        case 3: inputDelegate?.mouseDown(button: .side, mask: NSEvent.pressedMouseButtons.inputButtons())
+        case 4: inputDelegate?.mouseDown(button: .extra, mask: NSEvent.pressedMouseButtons.inputButtons())
         default: break
         }
     }
     
     override func mouseUp(with event: NSEvent) {
         logger.trace("mouse up: \(event.buttonNumber)")
-        inputDelegate?.mouseUp(button: .left)
+        inputDelegate?.mouseUp(button: .left, mask: NSEvent.pressedMouseButtons.inputButtons())
     }
     
     override func rightMouseUp(with event: NSEvent) {
         logger.trace("right mouse up: \(event.buttonNumber)")
-        inputDelegate?.mouseUp(button: .right)
+        inputDelegate?.mouseUp(button: .right, mask: NSEvent.pressedMouseButtons.inputButtons())
     }
     
     override func otherMouseUp(with event: NSEvent) {
         logger.trace("other mouse up: \(event.buttonNumber)")
         switch event.buttonNumber {
-        case 2: inputDelegate?.mouseUp(button: .middle)
-        case 3: inputDelegate?.mouseUp(button: .side)
-        case 4: inputDelegate?.mouseUp(button: .extra)
+        case 2: inputDelegate?.mouseUp(button: .middle, mask: NSEvent.pressedMouseButtons.inputButtons())
+        case 3: inputDelegate?.mouseUp(button: .side, mask: NSEvent.pressedMouseButtons.inputButtons())
+        case 4: inputDelegate?.mouseUp(button: .extra, mask: NSEvent.pressedMouseButtons.inputButtons())
         default: break
         }
     }
@@ -261,12 +261,12 @@ class VMMetalView: MTKView {
         logger.trace("mouse moved: \(event.deltaX), \(event.deltaY)")
         if isMouseCaptured {
             inputDelegate?.mouseMove(relativePoint: CGPoint(x: event.deltaX, y: -event.deltaY),
-                                     button: NSEvent.pressedMouseButtons.inputButtons())
+                                     buttonMask: NSEvent.pressedMouseButtons.inputButtons())
         } else {
             let location = event.locationInWindow
             let converted = convert(location, from: nil)
             inputDelegate?.mouseMove(absolutePoint: converted,
-                                     button: NSEvent.pressedMouseButtons.inputButtons())
+                                     buttonMask: NSEvent.pressedMouseButtons.inputButtons())
         }
     }
     
@@ -274,7 +274,7 @@ class VMMetalView: MTKView {
         guard event.deltaY != 0 else { return }
         logger.trace("scroll: \(event.deltaY)")
         inputDelegate?.mouseScroll(dy: event.deltaY,
-                                   button: NSEvent.pressedMouseButtons.inputButtons())
+                                   buttonMask: NSEvent.pressedMouseButtons.inputButtons())
     }
 
     override func acceptsFirstMouse(for event: NSEvent?) -> Bool {
@@ -284,7 +284,7 @@ class VMMetalView: MTKView {
         if let location = event?.locationInWindow {
             let converted = convert(location, from: nil)
             inputDelegate?.mouseMove(absolutePoint: converted,
-                                     button: NSEvent.pressedMouseButtons.inputButtons())
+                                     buttonMask: NSEvent.pressedMouseButtons.inputButtons())
         }
         return true
     }
@@ -385,6 +385,12 @@ private extension Int {
         if self & (1 << 2) != 0 {
             pressed.formUnion(.middle)
         }
+        if self & (1 << 3) != 0 {
+            pressed.formUnion(.side)
+        }
+        if self & (1 << 4) != 0 {
+            pressed.formUnion(.extra)
+        }
         return pressed
     }
 }

+ 5 - 5
Platform/macOS/Display/VMMetalViewInputDelegate.swift

@@ -16,11 +16,11 @@
 
 protocol VMMetalViewInputDelegate: AnyObject {
     var shouldUseCmdOptForCapture: Bool { get }
-    func mouseMove(absolutePoint: CGPoint, button: CSInputButton)
-    func mouseMove(relativePoint: CGPoint, button: CSInputButton)
-    func mouseDown(button: CSInputButton)
-    func mouseUp(button: CSInputButton)
-    func mouseScroll(dy: CGFloat, button: CSInputButton)
+    func mouseMove(absolutePoint: CGPoint, buttonMask: CSInputButton)
+    func mouseMove(relativePoint: CGPoint, buttonMask: CSInputButton)
+    func mouseDown(button: CSInputButton, mask: CSInputButton)
+    func mouseUp(button: CSInputButton, mask: CSInputButton)
+    func mouseScroll(dy: CGFloat, buttonMask: CSInputButton)
     func keyDown(scanCode: Int)
     func keyUp(scanCode: Int)
     func syncCapsLock(with modifier: NSEvent.ModifierFlags?)

+ 2 - 2
Scripting/UTMScriptingInputImpl.swift

@@ -107,9 +107,9 @@ private let kDelayNs: UInt64 = 20000000
             try await (vm as! UTMQemuVirtualMachine).changeInputTablet(true)
             input.sendMousePosition(mouseButton.toSpiceButton(), absolutePoint: CGPoint(x: xPosition, y: yPosition), forMonitorID: monitorNumber-1)
             try await Task.sleep(nanoseconds: kDelayNs)
-            input.sendMouseButton(mouseButton.toSpiceButton(), pressed: true)
+            input.sendMouseButton(mouseButton.toSpiceButton(), mask: [], pressed: true)
             try await Task.sleep(nanoseconds: kDelayNs)
-            input.sendMouseButton(mouseButton.toSpiceButton(), pressed: false)
+            input.sendMouseButton(mouseButton.toSpiceButton(), mask: [], pressed: false)
         }
     }
 }

+ 1 - 1
UTM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

@@ -16,7 +16,7 @@
       "location" : "https://github.com/utmapp/CocoaSpice.git",
       "state" : {
         "branch" : "main",
-        "revision" : "5e8a39421221cafaadf05f4e2f0155b1a540fc7f"
+        "revision" : "227c31ed30df1b5ea2b534d71ca8007f8571d660"
       }
     },
     {