【问题标题】:Cocoa application: scroll programmatically?Cocoa 应用程序:以编程方式滚动?
【发布时间】:2017-03-15 14:53:34
【问题描述】:

我目前正在为 iOS 和 macOS 开发一个跨平台应用程序,它可以让您的 iOS 设备充当触控板。

使用CGDisplayMoveCursorToPoint,我可以在屏幕上移动光标。奇迹般有效。 使用“主机”应用程序中的这段代码(即在 macOS 上运行),我可以点击鼠标:

let currentPosition = foo() // call to my helper function
                            // that translates NSEvent.mouseLocation()
let downEvent = CGEvent(
    mouseEventSource: nil,
    mouseType: .leftMouseDown, 
    mouseCursorPosition: currentPosition,
    mouseButton: .left
)
let upEvent = CGEvent(
    mouseEventSource: nil,
    mouseType: .leftMouseUp,
    mouseCursorPosition: currentPosition,
    mouseButton: .left
)
downEvent?.post(tap: CGEventTapLocation.cghidEventTap)
upEvent?.post(tap: CGEventTapLocation.cghidEventTap)

到目前为止,一切都很好。

现在我想在 iOS 设备上用两根手指实现滚动。问题不在于 iOS 和 macOS 之间的通信(顺便说一句,PeerTalk 很棒),而是我似乎无法在主机上触发滚动事件。

起初,我尝试过这样的事情:

let eventSource = CGEventSource(stateID: .hidSystemState)
let event = CGEvent(
    mouseEventSource: eventSource,
    mouseType: .scrollWheel,
    mouseCursorPosition: currentPosition,
    mouseButton: .left
)

不幸的是,event 始终是nil,我不知道为什么。我想尝试的另一种方法是(是的,我正在使用从全局事件侦听器获得的硬编码值,用于测试目的):

NSEvent.mouseEvent(
    with: NSEventType.scrollWheel,
    location: NSPoint(x: 671.0, y: 568.0),
    modifierFlags: .init(rawValue: 0),
    timestamp: 198223.19430632601,
    windowNumber: 14389,
    context: nil,
    eventNumber: 0,
    clickCount: 1,
    pressure: 1.0
)

但是我的应用程序在创建事件时崩溃了:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: _NSEventMask64FromType(type) & (MouseMask|NSEventMaskMouseMoved)'

有没有人知道如何实现我的滚动功能?提前致谢!

【问题讨论】:

    标签: cocoa nsevent


    【解决方案1】:

    从 MacOS 10.13 开始,有一个用于创建滚动事件的 CGEvent 的新初始化程序:https://developer.apple.com/documentation/coregraphics/cgevent/2919739-init

    我设法像下面这样使用它:

    func PostMouseScrollEvent(up: Bool){
        var wheel1: Int32 = -100
        if up { wheel1 = 100 }
        let event = CGEvent(scrollWheelEvent2Source: nil, units: .pixel, wheelCount: 1, wheel1: wheel1, wheel2: 0, wheel3: 0)
        event?.post(tap: CGEventTapLocation.cghidEventTap)
    }
    

    【讨论】:

      【解决方案2】:

      我解决了

      a) 使用桥接头:

      #ifndef Header_h
      #define Header_h
      void createScrollWheelEvent();
      #endif /* Header_h */
      

      b) 用普通的 C 语言编写一个函数来创建事件:

      #include <stdio.h>
      #include <ApplicationServices/ApplicationServices.h>
      
      void createScrollWheelEvent() {
          CGEventRef upEvent = CGEventCreateScrollWheelEvent(
              NULL, 
              kCGScrollEventUnitPixel, 
              2, 1, 1 );
          CGEventPost(kCGHIDEventTap, upEvent);
          CFRelease(upEvent);
      }
      

      c) 并直接从我的 Swift 代码中调用它:

      createScrollWheelEvent()
      

      在 Swift 中使用 CGEventCreateScrollWheelEvent 是不可能的,因为函数是可变参数的。代码显然需要调整,但它应该让偶然发现这篇文章的人知道如何解决它。

      // 编辑

      我还注意到CGDisplayMoveCursorToPoint 不是“正确的”。是的,它会移动光标,但是当我将光标放在 Dock 中的图标上时,应用程序名称没有弹出窗口。因此,我切换到CGEvent来移动光标。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-02-22
        • 2011-01-16
        • 2011-01-15
        • 2010-11-13
        • 2014-05-22
        • 2013-07-09
        相关资源
        最近更新 更多