Cocoa 应用程序:以编程方式滚动?
Cocoa application: scroll programmatically?
我目前正在为 iOS 和 macOS 开发跨平台应用程序,使您的 iOS 设备可以用作触控板。
使用CGDisplayMoveCursorToPoint
,我可以在屏幕上移动光标。奇迹般有效。
在 "host" 应用程序(即 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)'
有人知道我如何实现滚动功能吗?提前致谢!
我通过
解决了
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
。代码显然需要调整,但它应该能让遇到此问题的人 post 了解如何解决它。
// 编辑
我也注意到 CGDisplayMoveCursorToPoint
不是 "correct"。是的,它移动了光标,但是当我将光标放在停靠栏中的图标上时,应用程序名称没有弹出窗口。因此,我切换到 CGEvent
来移动光标。
从 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)
}
我目前正在为 iOS 和 macOS 开发跨平台应用程序,使您的 iOS 设备可以用作触控板。
使用CGDisplayMoveCursorToPoint
,我可以在屏幕上移动光标。奇迹般有效。
在 "host" 应用程序(即 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)'
有人知道我如何实现滚动功能吗?提前致谢!
我通过
解决了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
。代码显然需要调整,但它应该能让遇到此问题的人 post 了解如何解决它。
// 编辑
我也注意到 CGDisplayMoveCursorToPoint
不是 "correct"。是的,它移动了光标,但是当我将光标放在停靠栏中的图标上时,应用程序名称没有弹出窗口。因此,我切换到 CGEvent
来移动光标。
从 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)
}