95 lines
3.2 KiB
Swift
95 lines
3.2 KiB
Swift
//
|
|
// AppDelegate.swift
|
|
// ScrollSwitcher
|
|
//
|
|
// Created by Shadowfacts on 8/31/21.
|
|
//
|
|
|
|
import Cocoa
|
|
|
|
let defaultsKey = "com.apple.swipescrolldirection"
|
|
|
|
class AppDelegate: NSObject, NSApplicationDelegate {
|
|
|
|
// things that need to be retained to keep them from disappearing
|
|
private var prefPanesSupport: Bundle!
|
|
private var item: NSStatusItem!
|
|
private var observation: NSKeyValueObservation?
|
|
|
|
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
|
|
|
// this is where _setSwipeScrollDirection is defined
|
|
prefPanesSupport = Bundle(path: "/System/Library/PrivateFrameworks/PreferencePanesSupport.framework")
|
|
try! prefPanesSupport!.loadAndReturnError()
|
|
|
|
item = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
|
|
item.button!.target = self
|
|
item.button!.action = #selector(toggleScrollDirection)
|
|
updateIcon()
|
|
|
|
// update the icon when system prefs changes
|
|
DistributedNotificationCenter.default().addObserver(self, selector: #selector(updateIcon), name: .swipeScrollDirectionDidChangeNotification, object: nil)
|
|
}
|
|
|
|
@objc private func updateIcon() {
|
|
item.button!.image = Direction.current.image
|
|
}
|
|
|
|
@objc private func toggleScrollDirection() {
|
|
setDirection(.current == Direction.natural ? .normal : .natural)
|
|
updateIcon()
|
|
}
|
|
|
|
private func setDirection(_ new: Direction) {
|
|
// can't construct a UserDefaults with NSGlobalDomain, so set it via the command line
|
|
let proc = Process()
|
|
// let out = Pipe()
|
|
// let err = Pipe()
|
|
proc.launchPath = "/usr/bin/env"
|
|
let newVal = new == .normal ? "NO" : "YES"
|
|
proc.arguments = ["defaults", "write", "-g", "com.apple.swipescrolldirection", "-bool", newVal]
|
|
// proc.standardOutput = out
|
|
// proc.standardError = err
|
|
proc.launch()
|
|
proc.waitUntilExit()
|
|
|
|
// let outData = out.fileHandleForReading.readDataToEndOfFile()
|
|
// let errData = err.fileHandleForReading.readDataToEndOfFile()
|
|
if proc.terminationStatus != 0 {
|
|
fatalError("uh oh, exit code: \(proc.terminationStatus)")
|
|
}
|
|
|
|
// makes system preferences update
|
|
DistributedNotificationCenter.default().postNotificationName(.swipeScrollDirectionDidChangeNotification, object: nil, userInfo: nil, deliverImmediately: false)
|
|
// make the actual input behavior update
|
|
setSwipeScrollDirection(Int32(new.rawValue))
|
|
}
|
|
|
|
}
|
|
|
|
enum Direction: Int, Equatable {
|
|
case normal, natural
|
|
|
|
static var current: Direction {
|
|
let value = UserDefaults.standard.bool(forKey: defaultsKey)
|
|
if value {
|
|
return .natural
|
|
} else {
|
|
return .normal
|
|
}
|
|
}
|
|
|
|
var image: NSImage {
|
|
switch self {
|
|
case .normal:
|
|
return NSImage(systemSymbolName: "scroll", accessibilityDescription: nil)!
|
|
case .natural:
|
|
return NSImage(systemSymbolName: "scroll.fill", accessibilityDescription: nil)!
|
|
}
|
|
}
|
|
}
|
|
|
|
extension Notification.Name {
|
|
static let swipeScrollDirectionDidChangeNotification = Notification.Name(rawValue: "SwipeScrollDirectionDidChangeNotification")
|
|
}
|