mpv/video/out/cocoa-cb/events_view.swift

272 lines
8.6 KiB
Swift

/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
import Cocoa
class EventsView: NSView {
weak var cocoaCB: CocoaCB!
var mpv: MPVHelper! {
get { return cocoaCB == nil ? nil : cocoaCB.mpv }
}
var tracker: NSTrackingArea?
var hasMouseDown: Bool = false
override var isFlipped: Bool { return true }
override var acceptsFirstResponder: Bool { return true }
init(frame frameRect: NSRect, cocoaCB ccb: CocoaCB) {
cocoaCB = ccb
super.init(frame: frameRect)
autoresizingMask = [.viewWidthSizable, .viewHeightSizable]
wantsBestResolutionOpenGLSurface = true
register(forDraggedTypes: [NSFilenamesPboardType, NSURLPboardType])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func updateTrackingAreas() {
if tracker != nil {
removeTrackingArea(tracker!)
}
if mpv != nil && !mpv.getBoolProperty("input-cursor") {
return
}
tracker = NSTrackingArea(rect: bounds,
options: [.activeAlways, .mouseEnteredAndExited, .mouseMoved, .enabledDuringMouseDrag],
owner: self, userInfo: nil)
addTrackingArea(tracker!)
if containsMouseLocation() {
cocoa_put_key_with_modifiers(SWIFT_KEY_MOUSE_LEAVE, 0)
}
}
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
guard let types = sender.draggingPasteboard().types else { return [] }
if types.contains(NSFilenamesPboardType) || types.contains(NSURLPboardType) {
return .copy
}
return []
}
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
let pb = sender.draggingPasteboard()
guard let types = sender.draggingPasteboard().types else { return false }
if types.contains(NSFilenamesPboardType) {
if let files = pb.propertyList(forType: NSFilenamesPboardType) as? [Any] {
EventsResponder.sharedInstance().handleFilesArray(files)
return true
}
} else if types.contains(NSURLPboardType) {
if let url = pb.propertyList(forType: NSURLPboardType) as? [Any] {
EventsResponder.sharedInstance().handleFilesArray(url)
return true
}
}
return false
}
override func acceptsFirstMouse(for event: NSEvent?) -> Bool {
return mpv.getBoolProperty("input-cursor")
}
override func becomeFirstResponder() -> Bool {
return mpv.getBoolProperty("input-cursor") ||
mpv.getBoolProperty("input-vo-keyboard")
}
override func resignFirstResponder() -> Bool {
return true
}
override func mouseEntered(with event: NSEvent) {
if mpv.getBoolProperty("input-cursor") {
cocoa_put_key_with_modifiers(SWIFT_KEY_MOUSE_ENTER, 0)
}
}
override func mouseExited(with event: NSEvent) {
if mpv.getBoolProperty("input-cursor") {
cocoa_put_key_with_modifiers(SWIFT_KEY_MOUSE_LEAVE, 0)
}
cocoaCB.window.hideTitleBar()
}
override func mouseMoved(with event: NSEvent) {
if mpv != nil && mpv.getBoolProperty("input-cursor") {
signalMouseMovement(event)
}
cocoaCB.window.showTitleBar()
}
override func mouseDragged(with event: NSEvent) {
if mpv.getBoolProperty("input-cursor") {
signalMouseMovement(event)
}
}
override func mouseDown(with event: NSEvent) {
if mpv.getBoolProperty("input-cursor") {
signalMouseDown(event)
}
}
override func mouseUp(with event: NSEvent) {
if mpv.getBoolProperty("input-cursor") {
signalMouseUp(event)
}
cocoaCB.window.isMoving = false
}
override func rightMouseDown(with event: NSEvent) {
if mpv.getBoolProperty("input-cursor") {
signalMouseDown(event)
}
}
override func rightMouseUp(with event: NSEvent) {
if mpv.getBoolProperty("input-cursor") {
signalMouseUp(event)
}
}
override func otherMouseDown(with event: NSEvent) {
if mpv.getBoolProperty("input-cursor") {
signalMouseDown(event)
}
}
override func otherMouseUp(with event: NSEvent) {
if mpv.getBoolProperty("input-cursor") {
signalMouseUp(event)
}
}
func signalMouseDown(_ event: NSEvent) {
signalMouseEvent(event, SWIFT_KEY_STATE_DOWN)
if event.clickCount > 1 {
signalMouseEvent(event, SWIFT_KEY_STATE_UP)
}
}
func signalMouseUp(_ event: NSEvent) {
signalMouseEvent(event, SWIFT_KEY_STATE_UP)
}
func signalMouseEvent(_ event: NSEvent, _ state: Int32) {
hasMouseDown = state == SWIFT_KEY_STATE_DOWN
let mpkey = getMpvButton(event)
cocoa_put_key_with_modifiers((mpkey | state), Int32(event.modifierFlags.rawValue));
}
func signalMouseMovement(_ event: NSEvent) {
var point = convert(event.locationInWindow, from: nil)
point = convertToBacking(point)
point.y = -point.y
cocoaCB.window.updateMovableBackground(point)
if !cocoaCB.window.isMoving {
mpv.setMousePosition(point)
}
}
func preciseScroll(_ event: NSEvent) {
var delta: Double
var cmd: Int32
if fabs(event.deltaY) >= fabs(event.deltaX) {
delta = Double(event.deltaY) * 0.1;
cmd = delta > 0 ? SWIFT_WHEEL_UP : SWIFT_WHEEL_DOWN;
} else {
delta = Double(event.deltaX) * 0.1;
cmd = delta > 0 ? SWIFT_WHEEL_RIGHT : SWIFT_WHEEL_LEFT;
}
mpv.putAxis(cmd, delta: fabs(delta))
}
override func scrollWheel(with event: NSEvent) {
if !mpv.getBoolProperty("input-cursor") {
return
}
if event.hasPreciseScrollingDeltas {
preciseScroll(event)
} else {
let modifiers = event.modifierFlags
let deltaX = modifiers.contains(.shift) ? event.scrollingDeltaY : event.scrollingDeltaX
let deltaY = modifiers.contains(.shift) ? event.scrollingDeltaX : event.scrollingDeltaY
var mpkey: Int32
if fabs(deltaY) >= fabs(deltaX) {
mpkey = deltaY > 0 ? SWIFT_WHEEL_UP : SWIFT_WHEEL_DOWN;
} else {
mpkey = deltaX > 0 ? SWIFT_WHEEL_RIGHT : SWIFT_WHEEL_LEFT;
}
cocoa_put_key_with_modifiers(mpkey, Int32(modifiers.rawValue))
}
}
func containsMouseLocation() -> Bool {
if cocoaCB == nil { return false }
var topMargin: CGFloat = 0.0
let menuBarHeight = NSApp.mainMenu!.menuBarHeight
if cocoaCB.window.isInFullscreen && (menuBarHeight > 0) {
topMargin = cocoaCB.window.titleBarHeight + 1 + menuBarHeight
}
var vF = window!.screen!.frame
vF.size.height -= topMargin
let vFW = window!.convertFromScreen(vF)
let vFV = convert(vFW, from: nil)
let pt = convert(window!.mouseLocationOutsideOfEventStream, from: nil)
var clippedBounds = bounds.intersection(vFV)
if !cocoaCB.window.isInFullscreen {
clippedBounds.origin.y += cocoaCB.window.titleBarHeight
clippedBounds.size.height -= cocoaCB.window.titleBarHeight
}
return clippedBounds.contains(pt)
}
func canHideCursor() -> Bool {
return !hasMouseDown && containsMouseLocation() && window!.isKeyWindow
}
func getMpvButton(_ event: NSEvent) -> Int32 {
let buttonNumber = event.buttonNumber
switch (buttonNumber) {
case 0: return SWIFT_MBTN_LEFT;
case 1: return SWIFT_MBTN_RIGHT;
case 2: return SWIFT_MBTN_MID;
case 3: return SWIFT_MBTN_BACK;
case 4: return SWIFT_MBTN_FORWARD;
default: return SWIFT_MBTN9 + Int32(buttonNumber - 5);
}
}
}