Skip to content

Commit

Permalink
优化性能 | Performance optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
Caldis committed Jun 3, 2018
1 parent c2864fa commit f623f6d
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Mos/MonitorWindow/MonitorViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class MonitorViewController: NSViewController, ChartViewDelegate {
NotificationCenter.default.removeObserver(self)
NotificationCenter.default.addObserver(self, selector: #selector(updateMonitorData), name:NSNotification.Name(rawValue: "ScrollEvent"), object: nil)
// 开始截取事件
eventTap = Interception.start(event: mask, to: eventCallBack, at: .cgAnnotatedSessionEventTap, where: .tailAppendEventTap, for: .listenOnly)
eventTap = Interception.start(event: mask, handleBy: eventCallBack, at: .cgAnnotatedSessionEventTap, where: .tailAppendEventTap, for: .listenOnly)
}
func uninitObserver() {
// 停止截取
Expand Down
2 changes: 1 addition & 1 deletion Mos/ScrollCore/Interception.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Foundation
class Interception {

// 开始截取
class func start(event mask: CGEventMask, to eventHandler: @escaping CGEventTapCallBack, at eventTap: CGEventTapLocation, where eventPlace: CGEventTapPlacement, for behaver: CGEventTapOptions) -> CFMachPort {
class func start(event mask: CGEventMask, handleBy eventHandler: @escaping CGEventTapCallBack, at eventTap: CGEventTapLocation, where eventPlace: CGEventTapPlacement, for behaver: CGEventTapOptions) -> CFMachPort {
guard let eventTap = CGEvent.tapCreate(tap: eventTap, place: eventPlace, options: behaver, eventsOfInterest: mask, callback: eventHandler, userInfo: nil) else {
fatalError("Failed to create event tap")
}
Expand Down
21 changes: 10 additions & 11 deletions Mos/ScrollCore/ScrollCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,15 @@ class ScrollCore {
// 事件发送器
var scrollEventPoster: CVDisplayLink?
// 拦截层
var scrollEventTap:CFMachPort?
var hotkeyEventTap:CFMachPort?
var scrollEventTap: CFMachPort?
var hotkeyEventTap: CFMachPort?
var tapKeeperTimer: Timer?
// 拦截掩码
let scrollEventMask = CGEventMask(1 << CGEventType.scrollWheel.rawValue)
let hotkeyEventMask = CGEventMask(1 << CGEventType.flagsChanged.rawValue)

// 滚动处理
let scrollEventCallBack: CGEventTapCallBack = {
(proxy, type, event, refcon) in
let scrollEventCallBack: CGEventTapCallBack = { (proxy, type, event, refcon) in
// 是否返回原始事件 (不启用平滑时)
var returnOriginalEvent = true
// 判断输入源 (无法区分黑苹果, 因为黑苹果的触控板驱动直接模拟鼠标输入)
Expand Down Expand Up @@ -115,15 +114,15 @@ class ScrollCore {
ScrollCore.shared.blockSmooth = !ScrollCore.shared.blockSmooth
ScrollCore.shared.scrollBuffer = ScrollCore.shared.scrollCurr
}
return Unmanaged.passRetained(event)
return nil
}


// 启动滚动处理
func startHandlingScroll() {
// 开始截取事件
scrollEventTap = Interception.start(event: scrollEventMask, to: scrollEventCallBack, at: .cghidEventTap, where: .tailAppendEventTap, for: .defaultTap)
hotkeyEventTap = Interception.start(event: hotkeyEventMask, to: hotkeyEventCallBack, at: .cghidEventTap, where: .tailAppendEventTap, for: .listenOnly)
scrollEventTap = Interception.start(event: scrollEventMask, handleBy: scrollEventCallBack, at: .cghidEventTap, where: .tailAppendEventTap, for: .defaultTap)
hotkeyEventTap = Interception.start(event: hotkeyEventMask, handleBy: hotkeyEventCallBack, at: .cghidEventTap, where: .tailAppendEventTap, for: .listenOnly)
// 初始化滚动事件发送器
initScrollEventPoster()
// 初始化守护进程
Expand All @@ -133,11 +132,11 @@ class ScrollCore {
func endHandlingScroll() {
// 停止守护进程
tapKeeperTimer?.invalidate()
// 停止发送滚动事件
// 停止滚动事件发送器
disableScrollEventPoster()
// 停止截取事件
Interception.stop(tap: scrollEventTap)
Interception.stop(tap: hotkeyEventTap)
Interception.stop(tap: scrollEventTap)
}
// 守护进程
// 在某些高压环境下 eventTap 会挂掉
Expand Down Expand Up @@ -166,7 +165,7 @@ class ScrollCore {
scrollCurr.y = 0.0
}
// 更新 X 轴数据
if x*scrollDelta.x>0 {
if x*scrollDelta.x > 0 {
scrollBuffer.x += speed * x
} else {
scrollBuffer.x = speed * x
Expand Down Expand Up @@ -232,7 +231,7 @@ class ScrollCore {
// 发送滚动结果
MouseEvent.scroll(axis.YX, yScroll: Int32(swapedValue.y), xScroll: Int32(swapedValue.x))
// 如果临近目标距离小于精确度门限则停止滚动
if abs(scrollPulse.y)<=Options.shared.advanced.precision && abs(scrollPulse.x)<=Options.shared.advanced.precision {
if scrollPulse.y.magnitude<=Options.shared.advanced.precision && scrollPulse.x.magnitude<=Options.shared.advanced.precision {
disableScrollEventPoster()
scrollFiller.clean()
}
Expand Down
7 changes: 3 additions & 4 deletions Mos/ScrollCore/ScrollEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,17 @@ class ScrollEventUtils {
return {
(scrollEvent: ScrollEvent, threshold: Double) in
let usableValue = scrollEvent.Y.usableValue
let absUsableValue = abs(usableValue)
scrollEvent.Y.usableValue = usableValue>0.0 ? max(absUsableValue, threshold) : -max(absUsableValue, threshold)
scrollEvent.Y.usableValue = usableValue>0.0 ? max(usableValue.magnitude, threshold) : -max(usableValue.magnitude, threshold)
}
} else {
return {
(scrollEvent: ScrollEvent, threshold: Double) in
let usableValue = scrollEvent.X.usableValue
let absUsableValue = abs(usableValue)
scrollEvent.X.usableValue = usableValue>0.0 ? max(absUsableValue, threshold) : -max(absUsableValue, threshold)
scrollEvent.X.usableValue = usableValue>0.0 ? max(usableValue.magnitude, threshold) : -max(usableValue.magnitude, threshold)
}
}
}
static let normalizeX = normalize(axis: axisType.X)
static let normalizeY = normalize(axis: axisType.Y)

}
20 changes: 15 additions & 5 deletions Mos/ScrollCore/ScrollUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ class ScrollUtils {

// 从 PID 获取进程名称
private func getApplicationBundleIdFrom(pid: pid_t) -> String? {
if let runningApps = NSRunningApplication.init(processIdentifier: pid) {
return runningApps.bundleIdentifier
} else {
return nil
}
}
private func oldGetApplicationBundleIdFrom(pid: pid_t) -> String? {
// 更新列表
let runningApps = NSWorkspace.shared.runningApplications
if let matchApp = runningApps.filter({$0.processIdentifier == pid}).first {
Expand All @@ -31,18 +38,18 @@ class ScrollUtils {
}
}

// 从 CGEvent 中获取事件目标的 BundleId
// 从 CGEvent 中携带的 PID 获取目标窗口的 BundleId
// 已知问题: 如果鼠标滚轮事件由 cghidEventTap 层截取, 则获取到的目标窗口 PID 为当前的激活窗口, 而不是悬停窗口
private var lastEventTargetPID:pid_t = 1 // 目标进程 PID (先前)
private var currEventTargetPID:pid_t = 1 // 事件的目标进程 PID (当前)
private var currEventTargetBID:String! // 事件的目标进程 BID (当前)
func getCurrentEventTargetBundleId(from event: CGEvent) -> String {
private var currEventTargetBID:String? // 事件的目标进程 BID (当前)
func getCurrentEventTargetBundleId(from event: CGEvent) -> String? {
// 保存上次 PID
lastEventTargetPID = currEventTargetPID
// 更新当前 PID
currEventTargetPID = pid_t(event.getIntegerValueField(.eventTargetUnixProcessID))
// 使用 PID 获取 BID
// 如果目标 PID 变化, 则重新获取一次窗口 BID (更新 BID 消耗较高)
// 如果目标 PID 变化, 则重新获取一次窗口 BID (查找 BID 效率较低)
if lastEventTargetPID != currEventTargetPID {
if let bundleId = getApplicationBundleIdFrom(pid: currEventTargetPID) {
currEventTargetBID = bundleId
Expand All @@ -51,8 +58,11 @@ class ScrollUtils {
}
return currEventTargetBID
}
func getCurrentEventTargetBundleIdFromCache() -> String? {
return currEventTargetBID
}

// 获取指针悬停位置的窗口 BundleId
// 从指针悬停位置获取窗口 BundleId
// 原理: 获取指针坐标下的 AXUIElement 信息, 从而获取 BundleID
// 来自: https://stackoverflow.com/questions/27584963/get-window-values-under-mouse
// 已知问题: 外置屏幕获取到的 PID 有大约 30PX 在垂直方向上的偏移, 但内置屏幕无此问题
Expand Down

0 comments on commit f623f6d

Please sign in to comment.