ScrollSwitcher/ScrollSwitcher/AppDelegate.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")
}