fix: improve mouse event handling and cursor visibility in player window

This commit is contained in:
tapframe 2026-05-13 00:17:23 +05:30
parent 57ada58667
commit f8320433d0

View file

@ -11,6 +11,8 @@ final class NuvioPlayerWindow {
private var keyMonitor: Any? private var keyMonitor: Any?
private var mouseMonitor: Any? private var mouseMonitor: Any?
private var gestureDismissWork: DispatchWorkItem? private var gestureDismissWork: DispatchWorkItem?
private let mouseWakeThreshold: CGFloat = 8
private var lastControlMousePoint: NSPoint?
func show() { func show() {
DispatchQueue.main.async { [self] in DispatchQueue.main.async { [self] in
@ -115,7 +117,14 @@ final class NuvioPlayerWindow {
} }
mouseMonitor = NSEvent.addLocalMonitorForEvents(matching: [.mouseMoved, .leftMouseDragged]) { [weak self] event in mouseMonitor = NSEvent.addLocalMonitorForEvents(matching: [.mouseMoved, .leftMouseDragged]) { [weak self] event in
self?.handleMouseMoved() guard let self else { return event }
if self.isMouseEventInsidePlayer(event) {
self.handleMouseMoved(event)
} else if self.state.cursorHidden {
NSCursor.unhide()
self.state.cursorHidden = false
self.lastControlMousePoint = nil
}
return event return event
} }
} }
@ -140,19 +149,29 @@ final class NuvioPlayerWindow {
mpvView?.destroyPlayer() mpvView?.destroyPlayer()
containerView?.removeFromSuperview() containerView?.removeFromSuperview()
containerView = nil containerView = nil
lastControlMousePoint = nil
state.isClosed = true state.isClosed = true
NSCursor.unhide() NSCursor.unhide()
} }
} }
func handleMouseMoved() { func handleMouseMoved(_ event: NSEvent? = nil) {
if state.controlsLocked { if state.controlsLocked {
return return
} }
guard let point = currentMousePointInPlayer(event), hasMeaningfulMouseMovement(to: point) else { return }
showControls() showControls()
scheduleHideControls() scheduleHideControls()
} }
func handleMouseExited() {
lastControlMousePoint = nil
if state.cursorHidden {
NSCursor.unhide()
state.cursorHidden = false
}
}
func handleMouseClicked() { func handleMouseClicked() {
if state.controlsLocked { if state.controlsLocked {
state.lockedOverlayVisible = true state.lockedOverlayVisible = true
@ -276,7 +295,8 @@ final class NuvioPlayerWindow {
return return
} }
state.controlsVisible = false state.controlsVisible = false
if !state.cursorHidden { lastControlMousePoint = currentMousePointInPlayer()
if !state.cursorHidden && isCurrentMouseInsidePlayer() {
NSCursor.hide() NSCursor.hide()
state.cursorHidden = true state.cursorHidden = true
} }
@ -291,12 +311,48 @@ final class NuvioPlayerWindow {
guard let self, self.state.isPlaying else { return } guard let self, self.state.isPlaying else { return }
if self.state.showSubtitlePanel || self.state.showAudioPanel || self.state.showSourcesPanel || self.state.showEpisodesPanel || self.state.showSubmitIntroPanel { return } if self.state.showSubtitlePanel || self.state.showAudioPanel || self.state.showSourcesPanel || self.state.showEpisodesPanel || self.state.showSubmitIntroPanel { return }
self.state.controlsVisible = false self.state.controlsVisible = false
if !self.state.cursorHidden { self.lastControlMousePoint = self.currentMousePointInPlayer()
if !self.state.cursorHidden && self.isCurrentMouseInsidePlayer() {
NSCursor.hide() NSCursor.hide()
self.state.cursorHidden = true self.state.cursorHidden = true
} }
} }
} }
private func isMouseEventInsidePlayer(_ event: NSEvent) -> Bool {
currentMousePointInPlayer(event) != nil
}
private func isCurrentMouseInsidePlayer() -> Bool {
currentMousePointInPlayer() != nil
}
private func currentMousePointInPlayer(_ event: NSEvent? = nil) -> NSPoint? {
guard let containerView else { return nil }
if let event {
guard event.window === containerView.window else { return nil }
let point = containerView.convert(event.locationInWindow, from: nil)
return containerView.bounds.contains(point) ? point : nil
}
guard let window = containerView.window else { return nil }
let windowPoint = window.convertPoint(fromScreen: NSEvent.mouseLocation)
let point = containerView.convert(windowPoint, from: nil)
return containerView.bounds.contains(point) ? point : nil
}
private func hasMeaningfulMouseMovement(to point: NSPoint) -> Bool {
guard let lastPoint = lastControlMousePoint else {
lastControlMousePoint = point
return state.controlsVisible
}
let dx = point.x - lastPoint.x
let dy = point.y - lastPoint.y
if dx * dx + dy * dy < mouseWakeThreshold * mouseWakeThreshold {
return false
}
lastControlMousePoint = point
return true
}
} }
final class PlayerContainerView: NSView { final class PlayerContainerView: NSView {
@ -313,7 +369,11 @@ final class PlayerContainerView: NSView {
} }
override func mouseMoved(with event: NSEvent) { override func mouseMoved(with event: NSEvent) {
playerWindow?.handleMouseMoved() playerWindow?.handleMouseMoved(event)
}
override func mouseExited(with event: NSEvent) {
playerWindow?.handleMouseExited()
} }
override func mouseDown(with event: NSEvent) { override func mouseDown(with event: NSEvent) {