Estoy tratando de evitar que el cursor del mouse abandone un área específica de la pantalla. No puedo encontrar un método nativo para hacer esto, así que estoy tratando de hacerlo manualmente.
Hasta ahora tengo esto:
NSEvent.addGlobalMonitorForEvents(matching: [.mouseMoved, .leftMouseDragged], handler: {(event: NSEvent) in let x = event.locationInWindow.flipped.x; let y = event.locationInWindow.flipped.y; if (x <= 100) { CGWarpMouseCursorPosition(CGPoint(x: 100, y: y)) } }) // elsewhere to flip y coordinates extension NSPoint { var flipped: NSPoint { let screenFrame = (NSScreen.main?.frame)! let screenY = screenFrame.size.height - self.y return NSPoint(x: self.x, y: screenY) } }Esto evita que el cursor se salga del eje X. Genial. Pero también evita que el cursor se deslice a lo largo del eje y en X=100.
Así que traté de agregar el delta:
NSEvent.addGlobalMonitorForEvents(matching: [.mouseMoved, .leftMouseDragged], handler: {(event: NSEvent) in let x = event.locationInWindow.flipped.x; let y = event.locationInWindow.flipped.y; let deltaY = event.deltaY; if (x <= 100) { CGWarpMouseCursorPosition(CGPoint(x: 100, y: y + deltaY)) } }) Ahora se desliza a lo largo del eje Y. Pero la aceleración está muy lejos, es demasiado rápido. Lo que no entiendo es que si trato de hacer y - deltaY se desliza como esperaba, pero al revés :
NSEvent.addGlobalMonitorForEvents(matching: [.mouseMoved, .leftMouseDragged], handler: {(event: NSEvent) in let x = event.locationInWindow.flipped.x; let y = event.locationInWindow.flipped.y; let deltaY = event.deltaY; if (x <= 100) { CGWarpMouseCursorPosition(CGPoint(x: 100, y: y - deltaY)) } })Ahora el cursor se desliza a lo largo del eje Y en X=100 con la aceleración adecuada (como deslizar el cursor contra el borde de la pantalla), pero al revés. Moviendo el mouse hacia arriba, mueve el cursor hacia abajo.
¿Cómo obtengo un deslizamiento suave y adecuado del cursor, en la dirección correcta, en el borde de mi área personalizada?
¿O hay una mejor manera de lograr lo que estoy tratando de hacer?
Me lo imaginé. Necesito restar los deltas anteriores.
Así que ahora tengo esto en su lugar:
var oldDeltaX: CGFloat = 0; var oldDeltaY: CGFloat = 0; NSEvent.addGlobalMonitorForEvents(matching: [.mouseMoved, .leftMouseDragged, .rightMouseDragged], handler: {(event: NSEvent) in let deltaX = event.deltaX - oldDeltaX; let deltaY = event.deltaY - oldDeltaY; let x = event.locationInWindow.flipped.x; let y = event.locationInWindow.flipped.y; let window = (NSScreen.main?.frame.size)!; let width = CGFloat(1920); let height = CGFloat(1080); let widthCut = (window.width - width) / 2; let heightCut = (window.height - height) / 2; let xPoint = clamp(x + deltaX, minValue: widthCut, maxValue: window.width - widthCut); let yPoint = clamp(y + deltaY, minValue: heightCut, maxValue: window.height - heightCut); oldDeltaX = xPoint - x; oldDeltaY = yPoint - y; CGWarpMouseCursorPosition(CGPoint(x: xPoint, y: yPoint)); }); public func clamp<T>(_ value: T, minValue: T, maxValue: T) -> T where T : Comparable { return min(max(value, minValue), maxValue) } extension NSPoint { var flipped: NSPoint { let screenFrame = (NSScreen.main?.frame)! let screenY = screenFrame.size.height - self.y return NSPoint(x: self.x, y: screenY) } }Esto restringirá el mouse en un cuadrado de 1920x1080 de la pantalla.
Encontré que el código fuente de Godot es un buen recurso: https://github.com/godotengine/godot/blob/51a00c2855009ce4cd6475c09209ebd22641f448/platform/osx/display_server_osx.mm#L1087
¿Es esta la mejor o la forma más eficaz de hacerlo? No sé, pero funciona.