DRY and make sliders snap to multiples of 25

This commit is contained in:
Asger Hautop Drewsen 2017-01-12 08:09:00 +01:00
parent 8edd2471fe
commit 0f66aad47e

View file

@ -15,7 +15,42 @@ struct Display {
var serial: String
}
var app : AppDelegate! = nil
var app: AppDelegate! = nil
let prefs = UserDefaults.standard
func ddcctl(monitor: CGDirectDisplayID, command: Int32, value: Int) {
var wrcmd = DDCWriteCommand(control_id: UInt8(command), new_value: UInt8(value))
DDCWrite(monitor, &wrcmd)
print(value)
}
class SliderHandler : NSObject {
var display : Display
var command : Int32 = 0
public init(display: Display, command: Int32) {
self.display = display
self.command = command
}
func valueChanged(slider: NSSlider) {
let snapInterval = 25
let snapThreshold = 3
var value = slider.integerValue
let closest = (value + snapInterval / 2) / snapInterval * snapInterval
if abs(closest - value) <= snapThreshold {
value = closest
slider.integerValue = value
}
ddcctl(monitor: display.id, command: command, value: value)
prefs.setValue(value, forKey: "\(command)-\(display.serial)")
prefs.synchronize()
}
}
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@ -23,54 +58,15 @@ class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var statusMenu: NSMenu!
@IBOutlet weak var window: NSWindow!
let prefs = UserDefaults.standard
let statusItem = NSStatusBar.system().statusItem(withLength: NSVariableStatusItemLength)
let keycode = UInt16(0x07)
var monitorItems : [NSMenuItem] = []
var displays : [Display] = []
var monitorItems: [NSMenuItem] = []
var displays: [Display] = []
var sliderHandlers: [SliderHandler] = []
@IBAction func quitClicked(_ sender: AnyObject) {
NSApplication.shared().terminate(self)
}
func setBrightness( slider: NSSlider ){
let command = "-b"
let value = slider.integerValue
let i = slider.tag
let d = displays[i]
ddcctl(monitor: d.id, command: command, value: value)
prefs.setValue(value, forKey: "\(command)-\(d.serial)")
prefs.synchronize()
}
func setVolume(slider: NSSlider ){
let command = "-v"
let value = slider.integerValue
let i = slider.tag
let d = displays[i]
ddcctl(monitor: d.id, command: command, value: value)
prefs.setValue(value, forKey: "\(command)-\(d.serial)")
prefs.synchronize()
}
func setContrast(slider: NSSlider ){
let command = "-c"
let value = slider.integerValue
let i = slider.tag
let d = displays[i]
ddcctl(monitor: d.id, command: command, value: value)
prefs.setValue(value, forKey: "\(command)-\(d.serial)")
prefs.synchronize()
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
app = self
@ -84,16 +80,62 @@ class AppDelegate: NSObject, NSApplicationDelegate {
updateDisplays()
}
func makeLabel(text: String, frame: NSRect) -> NSTextField {
let label = NSTextField(frame: frame)
label.stringValue = text
label.isBordered = false
label.isBezeled = false
label.isEditable = false
label.drawsBackground = false
return label
}
func addSliderItem(menu: NSMenu, defaultDisplay: Bool, display: Display, command: Int32, title: String, shortcut: String) -> NSSlider {
let item = NSMenuItem()
let view = NSView(frame: NSRect(x: 0, y: 5, width: 250, height: 40))
let label = makeLabel(text: title, frame: NSRect(x: 20, y: 19, width: 130, height: 20))
let labelKeyCode = makeLabel(text: shortcut, frame: NSRect(x: 120, y: 19, width: 100, height: 20))
labelKeyCode.isHidden = !defaultDisplay
labelKeyCode.alignment = NSTextAlignment.right
let handler = SliderHandler(display: display, command: command)
sliderHandlers.append(handler)
let slider = NSSlider(frame: NSRect(x: 20, y: 0, width: 200, height: 19))
slider.target = handler
slider.minValue = 0
slider.maxValue = 100
slider.integerValue = prefs.integer(forKey: "\(command)-\(display.serial)")
slider.action = #selector(SliderHandler.valueChanged)
view.addSubview(label)
view.addSubview(labelKeyCode)
view.addSubview(slider)
item.view = view
menu.addItem(item)
menu.addItem(NSMenuItem.separator())
return slider
}
func updateDisplays() {
for m in monitorItems {
statusMenu.removeItem(m)
}
monitorItems = []
displays = []
sliderHandlers = []
sleep(1)
var firstDisplay : Display? = nil
var firstDisplay: Display? = nil
var firstBrightnessSlider: NSSlider! = nil
var firstVolumeSlider: NSSlider! = nil
for s in NSScreen.screens()! {
let id = s.deviceDescription["NSScreenNumber"] as! CGDirectDisplayID
@ -109,131 +151,43 @@ class AppDelegate: NSObject, NSApplicationDelegate {
let name = getDisplayName(edid)
let serial = getDisplaySerial(edid)
let defaultDisplay = firstDisplay == nil
let d = Display(id: id, name: name, serial: serial)
displays.append(d)
let i = displays.count - 1
let monitorMenuItem = NSMenuItem()
let monitorSubMenu = NSMenu()
let brightnessItem = NSMenuItem()
let contrastItem = NSMenuItem()
let volumeItem = NSMenuItem()
let brightnessSlider = addSliderItem(menu: monitorSubMenu, defaultDisplay: defaultDisplay, display: d, command: BRIGHTNESS, title: "Brightness", shortcut: "⇧⌘- / ⇧⌘+")
let _ = addSliderItem(menu: monitorSubMenu, defaultDisplay: defaultDisplay, display: d, command: CONTRAST, title: "Contrast", shortcut: "")
let volumeSlider = addSliderItem(menu: monitorSubMenu, defaultDisplay: defaultDisplay, display: d, command: AUDIO_SPEAKER_VOLUME, title: "Volume", shortcut: "⌥⌘- / ⌥⌘+")
let defaultMonitorItem = NSMenuItem()
let brightnessSlider = NSSlider(frame: NSRect(x: 20, y: 0, width: 200, height: 19))
brightnessSlider.target = self
brightnessSlider.minValue = 0
brightnessSlider.maxValue = 100
brightnessSlider.integerValue = prefs.integer(forKey: "-b-\(serial)")
brightnessSlider.action = #selector(AppDelegate.setBrightness)
brightnessSlider.tag = i
let contrastSlider = NSSlider(frame: NSRect(x: 20, y: 0, width: 200, height: 19))
contrastSlider.target = self
contrastSlider.minValue = 0
contrastSlider.maxValue = 100
contrastSlider.integerValue = prefs.integer(forKey: "-c-\(serial)")
contrastSlider.action = #selector(AppDelegate.setContrast)
contrastSlider.tag = i
let volumeSlider = NSSlider(frame: NSRect(x: 20, y: 3, width: 200, height: 19))
volumeSlider.target = self
volumeSlider.minValue = 0
volumeSlider.maxValue = 100
volumeSlider.integerValue = prefs.integer(forKey: "-v-\(serial)")
volumeSlider.action = #selector(AppDelegate.setVolume)
volumeSlider.tag = i
let brightnesSliderView = NSView(frame: NSRect(x: 0, y: 5, width: 250, height: 40))
let contrastSliderView = NSView(frame: NSRect(x: 0, y: 5, width: 250, height: 40))
let volumeSliderView = NSView(frame: NSRect(x: 0, y: 5, width: 250, height: 40))
let defaultMonitorView = NSView(frame: NSRect(x: 0, y: 5, width: 250, height: 25))
let brightnessLabel = NSTextField(frame: NSRect(x: 20, y: 16, width: 130, height: 20))
brightnessLabel.stringValue = "Brightness"
brightnessLabel.isBordered = false
brightnessLabel.isBezeled = false
brightnessLabel.isEditable = false
brightnessLabel.drawsBackground = false
let brightnessLabelKeyCode = NSTextField(frame: NSRect(x: 120, y: 16, width: 100, height: 20))
brightnessLabelKeyCode.stringValue = "⇧⌘- / ⇧⌘+"
brightnessLabelKeyCode.isBordered = false
brightnessLabelKeyCode.isBezeled = false
brightnessLabelKeyCode.isEditable = false
brightnessLabelKeyCode.drawsBackground = false
brightnessLabelKeyCode.isHidden = firstDisplay != nil
brightnessLabelKeyCode.alignment = NSTextAlignment.right
let constrastLabel = NSTextField(frame: NSRect(x: 20, y: 16, width: 130, height: 20))
constrastLabel.stringValue = "Contrast"
constrastLabel.isBordered = false
constrastLabel.isBezeled = false
constrastLabel.isEditable = false
constrastLabel.drawsBackground = false
let volumeLabel = NSTextField(frame: NSRect(x: 20, y: 19, width: 130, height: 20))
volumeLabel.stringValue = "Volume"
volumeLabel.isBordered = false
volumeLabel.isBezeled = false
volumeLabel.isEditable = false
volumeLabel.drawsBackground = false
let volumeLabelKeyCode = NSTextField(frame: NSRect(x: 120, y: 19, width: 100, height: 20))
volumeLabelKeyCode.stringValue = "⌥⌘- / ⌥⌘+"
volumeLabelKeyCode.isBordered = false
volumeLabelKeyCode.isBezeled = false
volumeLabelKeyCode.isEditable = false
volumeLabelKeyCode.drawsBackground = false
volumeLabelKeyCode.isHidden = firstDisplay != nil
volumeLabelKeyCode.alignment = NSTextAlignment.right
brightnesSliderView.addSubview(brightnessLabel)
brightnesSliderView.addSubview(brightnessLabelKeyCode)
brightnesSliderView.addSubview(brightnessSlider)
contrastSliderView.addSubview(constrastLabel)
contrastSliderView.addSubview(contrastSlider)
volumeSliderView.addSubview(volumeLabel)
volumeSliderView.addSubview(volumeLabelKeyCode)
volumeSliderView.addSubview(volumeSlider)
brightnessItem.view = brightnesSliderView
contrastItem.view = contrastSliderView
volumeItem.view = volumeSliderView
let defaultMonitorSelectButtom = NSButton(frame: NSRect(x: 25, y: 0, width: 200, height: 25))
defaultMonitorSelectButtom.title = firstDisplay == nil ? "Default" : "Set as default"
defaultMonitorSelectButtom.title = defaultDisplay ? "Default" : "Set as default"
defaultMonitorSelectButtom.bezelStyle = NSRoundRectBezelStyle
defaultMonitorSelectButtom.isEnabled = firstDisplay != nil
defaultMonitorSelectButtom.tag = i
defaultMonitorSelectButtom.isEnabled = !defaultDisplay
defaultMonitorView.addSubview(defaultMonitorSelectButtom)
defaultMonitorItem.view = defaultMonitorView
monitorSubMenu.addItem(brightnessItem)
monitorSubMenu.addItem(NSMenuItem.separator())
monitorSubMenu.addItem(contrastItem)
monitorSubMenu.addItem(NSMenuItem.separator())
monitorSubMenu.addItem(volumeItem)
monitorSubMenu.addItem(NSMenuItem.separator())
monitorSubMenu.addItem(defaultMonitorItem)
monitorMenuItem.title = "\(name)"
monitorMenuItem.submenu = monitorSubMenu
monitorItems.append(monitorMenuItem)
statusMenu.insertItem(monitorMenuItem, at: i)
statusMenu.insertItem(monitorMenuItem, at: displays.count - 1)
if firstDisplay == nil {
firstDisplay = d
firstBrightnessSlider = brightnessSlider
firstVolumeSlider = volumeSlider
}
}
@ -245,45 +199,51 @@ class AppDelegate: NSObject, NSApplicationDelegate {
NSEvent.addGlobalMonitorForEvents(
matching: NSEventMask.keyDown, handler: {(event: NSEvent) in
if (event.keyCode == 27 &&
(event.modifierFlags.contains(NSEventModifierFlags.control)) &&
(event.modifierFlags.contains(NSEventModifierFlags.command))) {
let value = abs(self.prefs.integer(forKey: "-v-\(d.serial)") - 1)
let modifiers = NSEventModifierFlags.init(rawValue: NSEventModifierFlags.command.rawValue |
NSEventModifierFlags.control.rawValue |
NSEventModifierFlags.option.rawValue |
NSEventModifierFlags.shift.rawValue)
var flags = event.modifierFlags.intersection(modifiers)
self.prefs.setValue(value, forKey: "-v-\(d.serial)")
self.ddcctl(monitor: d.id, command: "-v", value: value)
} else if (event.keyCode == 24 &&
(event.modifierFlags.contains(NSEventModifierFlags.control)) &&
(event.modifierFlags.contains(NSEventModifierFlags.command))) {
let value = abs(self.prefs.integer(forKey: "-v-\(d.serial)") + 1)
self.prefs.setValue(value, forKey: "-v-\(d.serial)")
self.ddcctl(monitor: d.id, command: "-v", value: value)
} else if (event.keyCode == 27 &&
(event.modifierFlags.contains(NSEventModifierFlags.option)) &&
(event.modifierFlags.contains(NSEventModifierFlags.command))) {
let value = abs(self.prefs.integer(forKey: "-b-\(d.serial)") - 1)
self.prefs.setValue(value, forKey: "-b-\(d.serial))")
self.ddcctl(monitor: d.id, command: "-b", value: value)
} else if (event.keyCode == 24 &&
(event.modifierFlags.contains(NSEventModifierFlags.option)) &&
(event.modifierFlags.contains(NSEventModifierFlags.command))) {
let value = abs(self.prefs.integer(forKey: "-b-\(d.serial)") + 1)
self.prefs.setValue(value, forKey: "-b-\(d.serial)")
self.ddcctl(monitor: d.id, command: "-b", value: value)
if !flags.contains(NSEventModifierFlags.command) {
return
}
flags.subtract(NSEventModifierFlags.command)
var rel = 0
if event.keyCode == 27 {
rel = -5
} else if event.keyCode == 24 {
rel = +5
} else {
return
}
var command = Int32()
var slider: NSSlider! = nil
if flags == NSEventModifierFlags.option {
command = AUDIO_SPEAKER_VOLUME
slider = firstVolumeSlider
} else if flags == NSEventModifierFlags.shift {
command = BRIGHTNESS
slider = firstBrightnessSlider
} else {
return
}
let k = "\(command)-\(d.serial)"
let value = max(0, min(100, prefs.integer(forKey: k) + rel))
prefs.setValue(value, forKey: k)
prefs.synchronize()
slider.intValue = Int32(value)
ddcctl(monitor: d.id, command: command, value: value)
})
}
func acquirePrivileges() {
let options : NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: true]
let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: true]
let accessibilityEnabled = AXIsProcessTrustedWithOptions(options)
if !accessibilityEnabled {
@ -293,27 +253,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
return
}
func ddcctl(monitor: CGDirectDisplayID, command: String, value: Int) {
var cmd : Int32! = nil
switch command {
case "-b":
cmd = BRIGHTNESS
break
case "-v":
cmd = AUDIO_SPEAKER_VOLUME
break
case "-c":
cmd = CONTRAST
break
default:
precondition(false, "Unknown command: \(command)")
}
var wrcmd = DDCWriteCommand(control_id: UInt8(cmd), new_value: UInt8(value))
DDCWrite(monitor, &wrcmd)
print(value)
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}