【问题标题】:Draw shape around cursor on macOS using Swift [duplicate]使用 Swift 在 macOS 上围绕光标绘制形状 [重复]
【发布时间】:2021-09-27 16:02:26
【问题描述】:

我对 macOS 和快速开发非常陌生,我一直在观看一些教程来解决这个问题。我还观看了 udemy 课程,该课程适用于 18 个 macOS 项目,但我一无所获

我想要做的只是一个 macOS 菜单栏应用程序,它将添加一个光标突出显示,看起来应该像这样:

我可以将光标更改为执行以下操作的图像

import SpriteKit

class CursorView: SKView {
    override func resetCursorRects() {
        if let targetImage = NSImage(named: "cursor") {
            let cursor = NSCursor(image: targetImage, 
                                  hotSpot: CGPoint(x: targetImage.size.width / 2, 
                                                   y: targetImage.size.height / 2))
            addCursorRect(frame, cursor: cursor)
        }
    }
}

这有三个问题:

  1. SKView 是 SpriteKit 中的一个类,我认为我不应该在我的用例中使用它
  2. 这会调用 addCursorRect 将更改添加到窗口框架(无论框架如何,我都需要一直这样做)
  3. 我不能为将来为突出显示颜色、大小或不透明度设置的每种样式设置 100 张图片

所以,我在这里试图了解如何为应该在所有屏幕上可用的菜单栏应用程序执行此操作,并实现上图中的突出显示

不确定这是否重要,但我正在使用 storyboard 并且不介意切换到 SwiftUI

我真的可以从社区获得一些帮助。谢谢

【问题讨论】:

  • 你打算在哪里显示光标周围的蓝色圆形边框?
  • 您是否只想对光标进行注释(例如,通过在屏幕截图中添加一个圆圈)?还是要完全替换它?
  • 我只想注释我的光标。我不打算更换它
  • 无论打开什么应用程序或窗口,我都打算在用户的屏幕上一直显示这个蓝色圆形边框。我也打算在未来添加点击动画

标签: swift macos cocoa


【解决方案1】:

您可以通过在系统鼠标周围绘制一些东西来对其进行注释。这可以通过

  • 添加 CGEvent 点击以捕获鼠标事件
  • 使用自定义窗口在光标周围绘制注释

这是一个简单的示例应用程序

import SwiftUI

@main
class AppDelegate: NSObject, NSApplicationDelegate {

    var mouseTap: CFMachPort?
    private var window: NSWindow = {
        // Create the SwiftUI view that provides the window contents.
        let contentView = Circle()
            .stroke(lineWidth: 2)
            .foregroundColor(.blue)
            .frame(width: 30, height: 30)
            .padding(2)

        // Create the window and set the content view.
        let window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 34, height: 34),
            styleMask: [.borderless],
            backing: .buffered,
            defer: false
        )
        window.contentView = NSHostingView(rootView: contentView)
        window.backgroundColor = .clear
        window.level = NSWindow.Level.statusBar
        window.makeKeyAndOrderFront(nil)
        return window
    }()

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        if let tap = createMouseTap() {
            if CGEvent.tapIsEnabled(tap: tap) {
                let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0)
                CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, CFRunLoopMode.commonModes)
                mouseTap = tap
            } else {
                print("tap not enabled")
                mouseTap = nil
            }
        } else {
            print("tap not enabled")
        }
    }

    func createMouseTap() -> CFMachPort? {
        withUnsafeMutableBytes(of: &window) { pointer in
            CGEvent.tapCreate(
                tap: .cgSessionEventTap,
                place: .headInsertEventTap,
                options: CGEventTapOptions.listenOnly,
                eventsOfInterest: (1 << CGEventType.mouseMoved.rawValue | 1 << CGEventType.leftMouseDragged.rawValue),
                callback: mouseMoved,
                userInfo: pointer.baseAddress
            )
        }
    }
}

func mouseMoved(proxy: CGEventTapProxy, type: CGEventType, event: CGEvent, context: UnsafeMutableRawPointer?) -> Unmanaged<CGEvent>? {
    let window = context!.assumingMemoryBound(to: NSWindow.self).pointee
    // using CGPoint+SIMD extension from https://gist.github.com/Dev1an/7973cee9d960479b35b705f88b7f38c4
    window.setFrameOrigin(event.unflippedLocation - 17)
    return nil
}

缺点

请注意,此实现确实需要用户在“系统偏好设置”的“通用访问”中允许键盘输入选项。

【讨论】:

  • 感激不尽
  • 如果我必须停止/开始突出显示,那么首选的方法是什么?
  • 我会在 SwiftUI 中使用条件视图来做到这一点。
猜你喜欢
  • 1970-01-01
  • 2018-08-12
  • 1970-01-01
  • 2017-10-29
  • 2020-06-18
  • 1970-01-01
  • 2018-06-13
  • 1970-01-01
  • 2011-12-13
相关资源
最近更新 更多