Compare commits
2
Commits
178ef4b2bd
...
606b617d19
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
606b617d19 | ||
|
|
70a1c17e03 |
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
Razer Pro Click V2 (vendor 5426, product 209)의 휠 좌우 틸트를 각각 `Command+[` / `Command+]`로 보냅니다. 제공한 HID 보고서의 첫 바이트와 비트 마스크를 그대로 사용합니다.
|
Razer Pro Click V2 (vendor 5426, product 209)의 휠 좌우 틸트를 각각 `Command+[` / `Command+]`로 보냅니다. 제공한 HID 보고서의 첫 바이트와 비트 마스크를 그대로 사용합니다.
|
||||||
|
|
||||||
|
마우스 휠의 세로 스크롤 방향도 반전합니다. 트랙패드와 Magic Mouse처럼 제스처로 스크롤하는 장치와 가로 스크롤은 바꾸지 않습니다.
|
||||||
|
|
||||||
## 설치 / 업데이트
|
## 설치 / 업데이트
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
@@ -147,4 +147,61 @@ let accessTimer: Timer? = accessGranted() ? nil : {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Invert vertical mouse-wheel scrolling. Trackpads and Magic Mouse send gesture phases;
|
||||||
|
// wheels do not, even when their high-resolution scrolling is marked continuous.
|
||||||
|
var scrollTap: CFMachPort?
|
||||||
|
var lastScrollKind = ""
|
||||||
|
// Marks the replacement events this app posts so the tap lets them through untouched.
|
||||||
|
let invertedScrollMarker: Int64 = 0x52544D31
|
||||||
|
let scrollCallback: CGEventTapCallBack = { proxy, type, event, _ in
|
||||||
|
if type == .tapDisabledByTimeout || type == .tapDisabledByUserInput {
|
||||||
|
if let tap = scrollTap { CGEvent.tapEnable(tap: tap, enable: true) }
|
||||||
|
return Unmanaged.passUnretained(event)
|
||||||
|
}
|
||||||
|
guard type == .scrollWheel,
|
||||||
|
event.getIntegerValueField(.eventSourceUserData) != invertedScrollMarker
|
||||||
|
else { return Unmanaged.passUnretained(event) }
|
||||||
|
let phase = event.getIntegerValueField(.scrollWheelEventScrollPhase)
|
||||||
|
let momentum = event.getIntegerValueField(.scrollWheelEventMomentumPhase)
|
||||||
|
let isWheel = phase == 0 && momentum == 0
|
||||||
|
let kind = "continuous=\(event.getIntegerValueField(.scrollWheelEventIsContinuous)) wheel=\(isWheel)"
|
||||||
|
if kind != lastScrollKind {
|
||||||
|
log("Scroll events: \(kind)")
|
||||||
|
lastScrollKind = kind
|
||||||
|
}
|
||||||
|
let lineY = event.getIntegerValueField(.scrollWheelEventDeltaAxis1)
|
||||||
|
let pointY = event.getIntegerValueField(.scrollWheelEventPointDeltaAxis1)
|
||||||
|
let fixedY = event.getDoubleValueField(.scrollWheelEventFixedPtDeltaAxis1)
|
||||||
|
guard isWheel, lineY != 0 || pointY != 0 || fixedY != 0 else { return Unmanaged.passUnretained(event) }
|
||||||
|
let lineX = event.getIntegerValueField(.scrollWheelEventDeltaAxis2)
|
||||||
|
let pointX = event.getIntegerValueField(.scrollWheelEventPointDeltaAxis2)
|
||||||
|
let fixedX = event.getDoubleValueField(.scrollWheelEventFixedPtDeltaAxis2)
|
||||||
|
// Apps read the hardware data attached to the original event, so editing its delta
|
||||||
|
// fields has no visible effect. Post a fresh line-based event (like a real wheel, so
|
||||||
|
// apps keep their per-line scroll distance) carrying the original deltas, Y flipped.
|
||||||
|
guard let replacement = CGEvent(scrollWheelEvent2Source: nil, units: .line, wheelCount: 2,
|
||||||
|
wheel1: Int32(clamping: -lineY), wheel2: Int32(clamping: lineX), wheel3: 0)
|
||||||
|
else { return Unmanaged.passUnretained(event) }
|
||||||
|
replacement.setIntegerValueField(.scrollWheelEventPointDeltaAxis1, value: -pointY)
|
||||||
|
replacement.setIntegerValueField(.scrollWheelEventPointDeltaAxis2, value: pointX)
|
||||||
|
replacement.setDoubleValueField(.scrollWheelEventFixedPtDeltaAxis1, value: -fixedY)
|
||||||
|
replacement.setDoubleValueField(.scrollWheelEventFixedPtDeltaAxis2, value: fixedX)
|
||||||
|
replacement.location = event.location
|
||||||
|
replacement.flags = event.flags
|
||||||
|
replacement.setIntegerValueField(.eventSourceUserData, value: invertedScrollMarker)
|
||||||
|
replacement.tapPostEvent(proxy)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if accessGranted() {
|
||||||
|
scrollTap = CGEvent.tapCreate(tap: .cgSessionEventTap, place: .headInsertEventTap, options: .defaultTap,
|
||||||
|
eventsOfInterest: CGEventMask(1 << CGEventType.scrollWheel.rawValue),
|
||||||
|
callback: scrollCallback, userInfo: nil)
|
||||||
|
if let tap = scrollTap {
|
||||||
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0), .commonModes)
|
||||||
|
log("Mouse wheel inversion running")
|
||||||
|
} else {
|
||||||
|
log("Mouse wheel inversion failed: could not create event tap")
|
||||||
|
}
|
||||||
|
}
|
||||||
CFRunLoopRun()
|
CFRunLoopRun()
|
||||||
|
|||||||
Reference in New Issue
Block a user