Cocoa应用程序:以编程方式滚动?

时间:2017-03-15 14:53:35

标签: cocoa nsevent

我目前正在开发适用于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)'

有没有人知道如何完成我的滚动功能?提前谢谢!

2 个答案:

答案 0 :(得分: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)
}

答案 1 :(得分:0)

我通过

解决了这个问题

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不是&#34;正确&#34;。是的,它会移动光标,但是当我将光标放在Dock中的图标上时,没有应用程序名称的弹出窗口。因此,我切换到CGEvent移动光标。