mirror of
https://github.com/Toxblh/MTMR.git
synced 2026-01-10 17:08:39 +00:00
Implement double tap and new actions array in config
This commit is contained in:
parent
87141e381b
commit
420614b7ba
@ -9,17 +9,28 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
|
class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
|
||||||
var tapClosure: (() -> Void)?
|
var tapClosure: (() -> Void)? {
|
||||||
|
didSet {
|
||||||
|
actions[.singleTap] = tapClosure
|
||||||
|
}
|
||||||
|
}
|
||||||
var longTapClosure: (() -> Void)? {
|
var longTapClosure: (() -> Void)? {
|
||||||
didSet {
|
didSet {
|
||||||
longClick.isEnabled = longTapClosure != nil
|
actions[.longTap] = longTapClosure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typealias TriggerClosure = (() -> Void)?
|
||||||
|
var actions: [Action.Trigger: TriggerClosure] = [:] {
|
||||||
|
didSet {
|
||||||
|
singleAndDoubleClick.isDoubleClickEnabled = actions[.doubleTap] != nil
|
||||||
|
longClick.isEnabled = actions[.longTap] != nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var finishViewConfiguration: ()->() = {}
|
var finishViewConfiguration: ()->() = {}
|
||||||
|
|
||||||
private var button: NSButton!
|
private var button: NSButton!
|
||||||
private var singleClick: HapticClickGestureRecognizer!
|
|
||||||
private var longClick: LongPressGestureRecognizer!
|
private var longClick: LongPressGestureRecognizer!
|
||||||
|
private var singleAndDoubleClick: DoubleClickGestureRecognizer!
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, title: String) {
|
init(identifier: NSTouchBarItem.Identifier, title: String) {
|
||||||
attributedTitle = title.defaultTouchbarAttributedString
|
attributedTitle = title.defaultTouchbarAttributedString
|
||||||
@ -31,10 +42,11 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
|
|||||||
longClick.isEnabled = false
|
longClick.isEnabled = false
|
||||||
longClick.allowedTouchTypes = .direct
|
longClick.allowedTouchTypes = .direct
|
||||||
longClick.delegate = self
|
longClick.delegate = self
|
||||||
|
|
||||||
singleClick = HapticClickGestureRecognizer(target: self, action: #selector(handleGestureSingle))
|
singleAndDoubleClick = DoubleClickGestureRecognizer(target: self, action: #selector(handleGestureSingleTap), doubleAction: #selector(handleGestureDoubleTap))
|
||||||
singleClick.allowedTouchTypes = .direct
|
singleAndDoubleClick.allowedTouchTypes = .direct
|
||||||
singleClick.delegate = self
|
singleAndDoubleClick.delegate = self
|
||||||
|
singleAndDoubleClick.isDoubleClickEnabled = false
|
||||||
|
|
||||||
reinstallButton()
|
reinstallButton()
|
||||||
button.attributedTitle = attributedTitle
|
button.attributedTitle = attributedTitle
|
||||||
@ -100,33 +112,35 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
|
|||||||
view = button
|
view = button
|
||||||
|
|
||||||
view.addGestureRecognizer(longClick)
|
view.addGestureRecognizer(longClick)
|
||||||
view.addGestureRecognizer(singleClick)
|
// view.addGestureRecognizer(singleClick)
|
||||||
|
view.addGestureRecognizer(singleAndDoubleClick)
|
||||||
finishViewConfiguration()
|
finishViewConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: NSGestureRecognizer) -> Bool {
|
func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: NSGestureRecognizer) -> Bool {
|
||||||
if gestureRecognizer == singleClick && otherGestureRecognizer == longClick
|
if gestureRecognizer == singleAndDoubleClick && otherGestureRecognizer == longClick
|
||||||
|| gestureRecognizer == longClick && otherGestureRecognizer == singleClick // need it
|
|| gestureRecognizer == longClick && otherGestureRecognizer == singleAndDoubleClick // need it
|
||||||
{
|
{
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func handleGestureSingle(gr: NSClickGestureRecognizer) {
|
@objc func handleGestureSingleTap() {
|
||||||
switch gr.state {
|
guard let singleTap = self.actions[.singleTap] else { return }
|
||||||
case .ended:
|
singleTap?()
|
||||||
tapClosure?()
|
}
|
||||||
break
|
|
||||||
default:
|
@objc func handleGestureDoubleTap() {
|
||||||
break
|
guard let doubleTap = self.actions[.doubleTap] else { return }
|
||||||
}
|
doubleTap?()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func handleGestureLong(gr: NSPressGestureRecognizer) {
|
@objc func handleGestureLong(gr: NSPressGestureRecognizer) {
|
||||||
switch gr.state {
|
switch gr.state {
|
||||||
case .possible: // tiny hack because we're calling action manually
|
case .possible: // tiny hack because we're calling action manually
|
||||||
(self.longTapClosure ?? self.tapClosure)?()
|
guard let longTap = self.actions[.longTap] else { return }
|
||||||
|
longTap?()
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
@ -176,15 +190,62 @@ class CustomButtonCell: NSButtonCell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HapticClickGestureRecognizer: NSClickGestureRecognizer {
|
// Thanks to https://stackoverflow.com/a/49843893
|
||||||
|
final class DoubleClickGestureRecognizer: NSClickGestureRecognizer {
|
||||||
|
|
||||||
|
private let _action: Selector
|
||||||
|
private let _doubleAction: Selector
|
||||||
|
private var _clickCount: Int = 0
|
||||||
|
|
||||||
|
public var isDoubleClickEnabled = true
|
||||||
|
|
||||||
|
override var action: Selector? {
|
||||||
|
get {
|
||||||
|
return nil /// prevent base class from performing any actions
|
||||||
|
} set {
|
||||||
|
if newValue != nil { // if they are trying to assign an actual action
|
||||||
|
fatalError("Only use init(target:action:doubleAction) for assigning actions")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(target: AnyObject, action: Selector, doubleAction: Selector) {
|
||||||
|
_action = action
|
||||||
|
_doubleAction = doubleAction
|
||||||
|
super.init(target: target, action: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(target:action:doubleAction) is only support atm")
|
||||||
|
}
|
||||||
|
|
||||||
override func touchesBegan(with event: NSEvent) {
|
override func touchesBegan(with event: NSEvent) {
|
||||||
HapticFeedback.shared?.tap(strong: 2)
|
HapticFeedback.shared?.tap(strong: 2)
|
||||||
super.touchesBegan(with: event)
|
super.touchesBegan(with: event)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func touchesEnded(with event: NSEvent) {
|
override func touchesEnded(with event: NSEvent) {
|
||||||
HapticFeedback.shared?.tap(strong: 1)
|
HapticFeedback.shared?.tap(strong: 1)
|
||||||
super.touchesEnded(with: event)
|
super.touchesEnded(with: event)
|
||||||
|
_clickCount += 1
|
||||||
|
|
||||||
|
guard isDoubleClickEnabled else {
|
||||||
|
_ = target?.perform(_action)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let delayThreshold = 0.20 // fine tune this as needed
|
||||||
|
perform(#selector(_resetAndPerformActionIfNecessary), with: nil, afterDelay: delayThreshold)
|
||||||
|
if _clickCount == 2 {
|
||||||
|
_ = target?.perform(_doubleAction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func _resetAndPerformActionIfNecessary() {
|
||||||
|
if _clickCount == 1 {
|
||||||
|
_ = target?.perform(_action)
|
||||||
|
}
|
||||||
|
_clickCount = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import Foundation
|
|||||||
|
|
||||||
extension Data {
|
extension Data {
|
||||||
func barItemDefinitions() -> [BarItemDefinition]? {
|
func barItemDefinitions() -> [BarItemDefinition]? {
|
||||||
return try? JSONDecoder().decode([BarItemDefinition].self, from: utf8string!.stripComments().data(using: .utf8)!)
|
return try! JSONDecoder().decode([BarItemDefinition].self, from: utf8string!.stripComments().data(using: .utf8)!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,25 +51,31 @@ class SupportedTypesHolder {
|
|||||||
private var supportedTypes: [String: ParametersDecoder] = [
|
private var supportedTypes: [String: ParametersDecoder] = [
|
||||||
"escape": { _ in (
|
"escape": { _ in (
|
||||||
item: .staticButton(title: "esc"),
|
item: .staticButton(title: "esc"),
|
||||||
action: .keyPress(keycode: 53),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [.align: .align(.left)]
|
parameters: [.align: .align(.left), .actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .keyPress(keycode: 53))
|
||||||
|
])]
|
||||||
) },
|
) },
|
||||||
|
|
||||||
"delete": { _ in (
|
"delete": { _ in (
|
||||||
item: .staticButton(title: "del"),
|
item: .staticButton(title: "del"),
|
||||||
action: .keyPress(keycode: 117),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [:]
|
parameters: [.actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .keyPress(keycode: 117))
|
||||||
|
])]
|
||||||
) },
|
) },
|
||||||
|
|
||||||
"brightnessUp": { _ in
|
"brightnessUp": { _ in
|
||||||
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessUp"))
|
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessUp"))
|
||||||
return (
|
return (
|
||||||
item: .staticButton(title: ""),
|
item: .staticButton(title: ""),
|
||||||
action: .keyPress(keycode: 144),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [.image: imageParameter]
|
parameters: [.image: imageParameter, .actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .keyPress(keycode: 144))
|
||||||
|
])]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -77,9 +83,11 @@ class SupportedTypesHolder {
|
|||||||
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessDown"))
|
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessDown"))
|
||||||
return (
|
return (
|
||||||
item: .staticButton(title: ""),
|
item: .staticButton(title: ""),
|
||||||
action: .keyPress(keycode: 145),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [.image: imageParameter]
|
parameters: [.image: imageParameter, .actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .keyPress(keycode: 145))
|
||||||
|
])]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -87,9 +95,11 @@ class SupportedTypesHolder {
|
|||||||
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "ill_up"))
|
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "ill_up"))
|
||||||
return (
|
return (
|
||||||
item: .staticButton(title: ""),
|
item: .staticButton(title: ""),
|
||||||
action: .hidKey(keycode: NX_KEYTYPE_ILLUMINATION_UP),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [.image: imageParameter]
|
parameters: [.image: imageParameter, .actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .hidKey(keycode: NX_KEYTYPE_ILLUMINATION_UP))
|
||||||
|
])]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -97,9 +107,11 @@ class SupportedTypesHolder {
|
|||||||
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "ill_down"))
|
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "ill_down"))
|
||||||
return (
|
return (
|
||||||
item: .staticButton(title: ""),
|
item: .staticButton(title: ""),
|
||||||
action: .hidKey(keycode: NX_KEYTYPE_ILLUMINATION_DOWN),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [.image: imageParameter]
|
parameters: [.image: imageParameter, .actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .hidKey(keycode: NX_KEYTYPE_ILLUMINATION_DOWN))
|
||||||
|
])]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -107,9 +119,11 @@ class SupportedTypesHolder {
|
|||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarVolumeDownTemplateName)!)
|
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarVolumeDownTemplateName)!)
|
||||||
return (
|
return (
|
||||||
item: .staticButton(title: ""),
|
item: .staticButton(title: ""),
|
||||||
action: .hidKey(keycode: NX_KEYTYPE_SOUND_DOWN),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [.image: imageParameter]
|
parameters: [.image: imageParameter, .actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .hidKey(keycode: NX_KEYTYPE_SOUND_DOWN))
|
||||||
|
])]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -117,9 +131,11 @@ class SupportedTypesHolder {
|
|||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarVolumeUpTemplateName)!)
|
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarVolumeUpTemplateName)!)
|
||||||
return (
|
return (
|
||||||
item: .staticButton(title: ""),
|
item: .staticButton(title: ""),
|
||||||
action: .hidKey(keycode: NX_KEYTYPE_SOUND_UP),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [.image: imageParameter]
|
parameters: [.image: imageParameter, .actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .hidKey(keycode: NX_KEYTYPE_SOUND_UP))
|
||||||
|
])]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -127,9 +143,11 @@ class SupportedTypesHolder {
|
|||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarAudioOutputMuteTemplateName)!)
|
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarAudioOutputMuteTemplateName)!)
|
||||||
return (
|
return (
|
||||||
item: .staticButton(title: ""),
|
item: .staticButton(title: ""),
|
||||||
action: .hidKey(keycode: NX_KEYTYPE_MUTE),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [.image: imageParameter]
|
parameters: [.image: imageParameter, .actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .hidKey(keycode: NX_KEYTYPE_MUTE))
|
||||||
|
])]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -137,9 +155,11 @@ class SupportedTypesHolder {
|
|||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarRewindTemplateName)!)
|
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarRewindTemplateName)!)
|
||||||
return (
|
return (
|
||||||
item: .staticButton(title: ""),
|
item: .staticButton(title: ""),
|
||||||
action: .hidKey(keycode: NX_KEYTYPE_PREVIOUS),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [.image: imageParameter]
|
parameters: [.image: imageParameter, .actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .hidKey(keycode: NX_KEYTYPE_PREVIOUS))
|
||||||
|
])]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -147,9 +167,11 @@ class SupportedTypesHolder {
|
|||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarPlayPauseTemplateName)!)
|
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarPlayPauseTemplateName)!)
|
||||||
return (
|
return (
|
||||||
item: .staticButton(title: ""),
|
item: .staticButton(title: ""),
|
||||||
action: .hidKey(keycode: NX_KEYTYPE_PLAY),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [.image: imageParameter]
|
parameters: [.image: imageParameter, .actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .hidKey(keycode: NX_KEYTYPE_PLAY))
|
||||||
|
])]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -157,24 +179,30 @@ class SupportedTypesHolder {
|
|||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarFastForwardTemplateName)!)
|
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarFastForwardTemplateName)!)
|
||||||
return (
|
return (
|
||||||
item: .staticButton(title: ""),
|
item: .staticButton(title: ""),
|
||||||
action: .hidKey(keycode: NX_KEYTYPE_NEXT),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [.image: imageParameter]
|
parameters: [.image: imageParameter, .actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .hidKey(keycode: NX_KEYTYPE_NEXT))
|
||||||
|
])]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"sleep": { _ in (
|
"sleep": { _ in (
|
||||||
item: .staticButton(title: "☕️"),
|
item: .staticButton(title: "☕️"),
|
||||||
action: .shellScript(executable: "/usr/bin/pmset", parameters: ["sleepnow"]),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [:]
|
parameters: [.actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .shellScript(executable: "/usr/bin/pmset", parameters: ["sleepnow"]))
|
||||||
|
])]
|
||||||
) },
|
) },
|
||||||
|
|
||||||
"displaySleep": { _ in (
|
"displaySleep": { _ in (
|
||||||
item: .staticButton(title: "☕️"),
|
item: .staticButton(title: "☕️"),
|
||||||
action: .shellScript(executable: "/usr/bin/pmset", parameters: ["displaysleepnow"]),
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [:]
|
parameters: [.actions: .actions([
|
||||||
|
Action(trigger: .singleTap, value: .shellScript(executable: "/usr/bin/pmset", parameters: ["displaysleepnow"]))
|
||||||
|
])]
|
||||||
) },
|
) },
|
||||||
|
|
||||||
]
|
]
|
||||||
@ -393,6 +421,92 @@ enum ItemType: Decodable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct FailableDecodable<Base : Decodable> : Decodable {
|
||||||
|
|
||||||
|
let base: Base?
|
||||||
|
|
||||||
|
init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.singleValueContainer()
|
||||||
|
self.base = try? container.decode(Base.self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Action: Decodable {
|
||||||
|
enum Trigger: String, Decodable {
|
||||||
|
case singleTap
|
||||||
|
case doubleTap
|
||||||
|
case longTap
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Value {
|
||||||
|
case none
|
||||||
|
case hidKey(keycode: Int32)
|
||||||
|
case keyPress(keycode: Int)
|
||||||
|
case appleScript(source: SourceProtocol)
|
||||||
|
case shellScript(executable: String, parameters: [String])
|
||||||
|
case custom(closure: () -> Void)
|
||||||
|
case openUrl(url: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum ActionTypeRaw: String, Decodable {
|
||||||
|
case hidKey
|
||||||
|
case keyPress
|
||||||
|
case appleScript
|
||||||
|
case shellScript
|
||||||
|
case openUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case trigger
|
||||||
|
case action
|
||||||
|
case keycode
|
||||||
|
case actionAppleScript
|
||||||
|
case executablePath
|
||||||
|
case shellArguments
|
||||||
|
case url
|
||||||
|
}
|
||||||
|
|
||||||
|
let trigger: Trigger
|
||||||
|
let value: Value
|
||||||
|
|
||||||
|
init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
trigger = try container.decode(Trigger.self, forKey: .trigger)
|
||||||
|
let type = try container.decodeIfPresent(ActionTypeRaw.self, forKey: .action)
|
||||||
|
|
||||||
|
switch type {
|
||||||
|
case .some(.hidKey):
|
||||||
|
let keycode = try container.decode(Int32.self, forKey: .keycode)
|
||||||
|
value = .hidKey(keycode: keycode)
|
||||||
|
|
||||||
|
case .some(.keyPress):
|
||||||
|
let keycode = try container.decode(Int.self, forKey: .keycode)
|
||||||
|
value = .keyPress(keycode: keycode)
|
||||||
|
|
||||||
|
case .some(.appleScript):
|
||||||
|
let source = try container.decode(Source.self, forKey: .actionAppleScript)
|
||||||
|
value = .appleScript(source: source)
|
||||||
|
|
||||||
|
case .some(.shellScript):
|
||||||
|
let executable = try container.decode(String.self, forKey: .executablePath)
|
||||||
|
let parameters = try container.decodeIfPresent([String].self, forKey: .shellArguments) ?? []
|
||||||
|
value = .shellScript(executable: executable, parameters: parameters)
|
||||||
|
|
||||||
|
case .some(.openUrl):
|
||||||
|
let url = try container.decode(String.self, forKey: .url)
|
||||||
|
value = .openUrl(url: url)
|
||||||
|
case .none:
|
||||||
|
value = .none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(trigger: Trigger, value: Value) {
|
||||||
|
self.trigger = trigger
|
||||||
|
self.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum ActionType: Decodable {
|
enum ActionType: Decodable {
|
||||||
case none
|
case none
|
||||||
case hidKey(keycode: Int32)
|
case hidKey(keycode: Int32)
|
||||||
@ -516,6 +630,7 @@ enum GeneralParameter {
|
|||||||
case bordered(_: Bool)
|
case bordered(_: Bool)
|
||||||
case background(_: NSColor)
|
case background(_: NSColor)
|
||||||
case title(_: String)
|
case title(_: String)
|
||||||
|
case actions(_: [Action])
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GeneralParameters: Decodable {
|
struct GeneralParameters: Decodable {
|
||||||
@ -528,6 +643,7 @@ struct GeneralParameters: Decodable {
|
|||||||
case bordered
|
case bordered
|
||||||
case background
|
case background
|
||||||
case title
|
case title
|
||||||
|
case actions
|
||||||
}
|
}
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
init(from decoder: Decoder) throws {
|
||||||
@ -556,6 +672,10 @@ struct GeneralParameters: Decodable {
|
|||||||
if let title = try container.decodeIfPresent(String.self, forKey: .title) {
|
if let title = try container.decodeIfPresent(String.self, forKey: .title) {
|
||||||
result[.title] = .title(title)
|
result[.title] = .title(title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let actions = try container.decodeIfPresent([Action].self, forKey: .actions) {
|
||||||
|
result[.actions] = .actions(actions)//.compactMap { $0.base })
|
||||||
|
}
|
||||||
|
|
||||||
parameters = result
|
parameters = result
|
||||||
}
|
}
|
||||||
|
|||||||
@ -313,6 +313,11 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
|||||||
if let longAction = self.longAction(forItem: item), let item = barItem as? CustomButtonTouchBarItem {
|
if let longAction = self.longAction(forItem: item), let item = barItem as? CustomButtonTouchBarItem {
|
||||||
item.longTapClosure = longAction
|
item.longTapClosure = longAction
|
||||||
}
|
}
|
||||||
|
if case let .actions(actions)? = item.additionalParameters[.actions], let item = barItem as? CustomButtonTouchBarItem {
|
||||||
|
for action in actions {
|
||||||
|
item.actions[action.trigger] = self.action(for: action)
|
||||||
|
}
|
||||||
|
}
|
||||||
if case let .bordered(bordered)? = item.additionalParameters[.bordered], let item = barItem as? CustomButtonTouchBarItem {
|
if case let .bordered(bordered)? = item.additionalParameters[.bordered], let item = barItem as? CustomButtonTouchBarItem {
|
||||||
item.isBordered = bordered
|
item.isBordered = bordered
|
||||||
}
|
}
|
||||||
@ -334,6 +339,50 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
|||||||
}
|
}
|
||||||
return barItem
|
return barItem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func action(for action: Action) -> (() -> Void)? {
|
||||||
|
switch action.value {
|
||||||
|
case let .hidKey(keycode: keycode):
|
||||||
|
return { HIDPostAuxKey(keycode) }
|
||||||
|
case let .keyPress(keycode: keycode):
|
||||||
|
return { GenericKeyPress(keyCode: CGKeyCode(keycode)).send() }
|
||||||
|
case let .appleScript(source: source):
|
||||||
|
guard let appleScript = source.appleScript else {
|
||||||
|
print("cannot create apple script for item \(action)")
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
DispatchQueue.appleScriptQueue.async {
|
||||||
|
var error: NSDictionary?
|
||||||
|
appleScript.executeAndReturnError(&error)
|
||||||
|
if let error = error {
|
||||||
|
print("error \(error) when handling \(action) ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case let .shellScript(executable: executable, parameters: parameters):
|
||||||
|
return {
|
||||||
|
let task = Process()
|
||||||
|
task.launchPath = executable
|
||||||
|
task.arguments = parameters
|
||||||
|
task.launch()
|
||||||
|
}
|
||||||
|
case let .openUrl(url: url):
|
||||||
|
return {
|
||||||
|
if let url = URL(string: url), NSWorkspace.shared.open(url) {
|
||||||
|
#if DEBUG
|
||||||
|
print("URL was successfully opened")
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
print("error", url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case let .custom(closure: closure):
|
||||||
|
return closure
|
||||||
|
case .none:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func action(forItem item: BarItemDefinition) -> (() -> Void)? {
|
func action(forItem item: BarItemDefinition) -> (() -> Void)? {
|
||||||
switch item.action {
|
switch item.action {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user