mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-14 00:04:15 +09:00
feat: added feature to set keyboard shortcut to open/close popup window (#1976)
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import Carbon
|
||||
|
||||
extension String: @retroactive LocalizedError {
|
||||
public var errorDescription: String? { return self }
|
||||
@@ -312,9 +313,9 @@ public extension NSView {
|
||||
return s
|
||||
}
|
||||
|
||||
func buttonIconView(_ action: Selector, icon: NSImage) -> NSButton {
|
||||
func buttonIconView(_ action: Selector, icon: NSImage, height: CGFloat = 22) -> NSButton {
|
||||
let button = NSButton()
|
||||
button.heightAnchor.constraint(equalToConstant: 22).isActive = true
|
||||
button.heightAnchor.constraint(equalToConstant: height).isActive = true
|
||||
button.bezelStyle = .regularSquare
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
button.imageScaling = .scaleNone
|
||||
@@ -564,3 +565,150 @@ extension CGFloat {
|
||||
return ceil(self / 10) * 10
|
||||
}
|
||||
}
|
||||
|
||||
public class KeyboardShartcutView: NSStackView {
|
||||
private let callback: (_ value: [UInt16]) -> Void
|
||||
|
||||
private var startIcon: NSImage {
|
||||
if #available(macOS 12.0, *), let icon = iconFromSymbol(name: "record.circle", scale: .large) {
|
||||
return icon
|
||||
}
|
||||
return NSImage(named: NSImage.Name("record"))!
|
||||
}
|
||||
private var stopIcon: NSImage {
|
||||
if #available(macOS 12.0, *), let icon = iconFromSymbol(name: "stop.circle.fill", scale: .large) {
|
||||
return icon
|
||||
}
|
||||
return NSImage(named: NSImage.Name("stop"))!
|
||||
}
|
||||
|
||||
private var valueField: NSTextField? = nil
|
||||
private var startButton: NSButton? = nil
|
||||
private var stopButton: NSButton? = nil
|
||||
|
||||
private var recording: Bool = false
|
||||
private var keyCodes: [UInt16] = []
|
||||
private var value: [UInt16] = []
|
||||
private var interaction: Bool = false
|
||||
|
||||
public init(callback: @escaping (_ value: [UInt16]) -> Void, value: [UInt16]) {
|
||||
self.callback = callback
|
||||
self.value = value
|
||||
|
||||
super.init(frame: NSRect.zero)
|
||||
self.orientation = .horizontal
|
||||
|
||||
let stringValue = value.isEmpty ? localizedString("Disabled") : self.parseValue(value)
|
||||
let valueField: NSTextField = LabelField(stringValue)
|
||||
valueField.font = NSFont.systemFont(ofSize: 13, weight: .regular)
|
||||
valueField.textColor = .textColor
|
||||
valueField.alignment = .center
|
||||
|
||||
let startButton = buttonIconView(#selector(self.startListening), icon: self.startIcon, height: 15)
|
||||
let stopButton = buttonIconView(#selector(self.stopListening), icon: self.stopIcon, height: 15)
|
||||
|
||||
self.addArrangedSubview(valueField)
|
||||
self.addArrangedSubview(startButton)
|
||||
|
||||
self.valueField = valueField
|
||||
self.startButton = startButton
|
||||
self.stopButton = stopButton
|
||||
|
||||
NSEvent.addLocalMonitorForEvents(matching: [.keyDown, .flagsChanged]) { [weak self] event in
|
||||
self?.handleKeyEvent(event)
|
||||
return event
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc private func startListening() {
|
||||
guard AXIsProcessTrustedWithOptions([kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String: true] as CFDictionary) else { return }
|
||||
if let btn = self.stopButton {
|
||||
self.startButton?.removeFromSuperview()
|
||||
self.addArrangedSubview(btn)
|
||||
}
|
||||
self.valueField?.stringValue = localizedString("Listening...")
|
||||
self.keyCodes = []
|
||||
self.recording = true
|
||||
}
|
||||
|
||||
@objc private func stopListening() {
|
||||
if let btn = self.startButton {
|
||||
self.stopButton?.removeFromSuperview()
|
||||
self.addArrangedSubview(btn)
|
||||
}
|
||||
|
||||
if self.keyCodes.isEmpty && !self.interaction {
|
||||
self.value = []
|
||||
self.valueField?.stringValue = localizedString("Disabled")
|
||||
}
|
||||
|
||||
self.recording = false
|
||||
self.interaction = false
|
||||
self.callback(self.value)
|
||||
}
|
||||
|
||||
private func handleKeyEvent(_ event: NSEvent) {
|
||||
guard self.recording else { return }
|
||||
self.interaction = true
|
||||
|
||||
if event.type == .flagsChanged {
|
||||
self.keyCodes = []
|
||||
if event.modifierFlags.contains(.control) { self.keyCodes.append(59) }
|
||||
if event.modifierFlags.contains(.shift) { self.keyCodes.append(60) }
|
||||
if event.modifierFlags.contains(.command) { self.keyCodes.append(55) }
|
||||
if event.modifierFlags.contains(.option) { self.keyCodes.append(58) }
|
||||
} else if event.type == .keyDown {
|
||||
self.keyCodes.append(event.keyCode)
|
||||
self.value = self.keyCodes
|
||||
}
|
||||
|
||||
let list = self.keyCodes.isEmpty ? self.value : self.keyCodes
|
||||
self.valueField?.stringValue = self.parseValue(list)
|
||||
}
|
||||
|
||||
private func parseValue(_ list: [UInt16]) -> String {
|
||||
return list.compactMap { self.keyName(virtualKeyCode: $0) }.joined(separator: " + ")
|
||||
}
|
||||
|
||||
private func keyName(virtualKeyCode: UInt16) -> String? {
|
||||
if virtualKeyCode == 59 {
|
||||
return "Control"
|
||||
} else if virtualKeyCode == 60 {
|
||||
return "Shift"
|
||||
} else if virtualKeyCode == 55 {
|
||||
return "Command"
|
||||
} else if virtualKeyCode == 58 {
|
||||
return "Option"
|
||||
}
|
||||
|
||||
let maxNameLength = 4
|
||||
var nameBuffer = [UniChar](repeating: 0, count: maxNameLength)
|
||||
var nameLength = 0
|
||||
|
||||
let modifierKeys = UInt32(alphaLock >> 8) & 0xFF // Caps Lock
|
||||
var deadKeys: UInt32 = 0
|
||||
let keyboardType = UInt32(LMGetKbdType())
|
||||
|
||||
let source = TISCopyCurrentKeyboardLayoutInputSource().takeRetainedValue()
|
||||
guard let ptr = TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData) else {
|
||||
NSLog("Could not get keyboard layout data")
|
||||
return nil
|
||||
}
|
||||
let layoutData = Unmanaged<CFData>.fromOpaque(ptr).takeUnretainedValue() as Data
|
||||
let osStatus = layoutData.withUnsafeBytes {
|
||||
UCKeyTranslate($0.bindMemory(to: UCKeyboardLayout.self).baseAddress, virtualKeyCode, UInt16(kUCKeyActionDown),
|
||||
modifierKeys, keyboardType, UInt32(kUCKeyTranslateNoDeadKeysMask),
|
||||
&deadKeys, maxNameLength, &nameLength, &nameBuffer)
|
||||
}
|
||||
guard osStatus == noErr else {
|
||||
NSLog("Code: 0x%04X Status: %+i", virtualKeyCode, osStatus)
|
||||
return nil
|
||||
}
|
||||
|
||||
return String(utf16CodeUnits: nameBuffer, count: nameLength)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,10 +78,14 @@ open class Module {
|
||||
}
|
||||
public var combinedPosition: Int {
|
||||
get { Store.shared.int(key: "\(self.name)_position", defaultValue: 0) }
|
||||
set { Store.shared.set(key: "\(self.name)_position", value: newValue) }
|
||||
set { Store.shared.set(key: "\(self.name)_position", value: newValue) }
|
||||
}
|
||||
public var userDefaults: UserDefaults? = UserDefaults(suiteName: "\(Bundle.main.object(forInfoDictionaryKey: "TeamId") as! String).eu.exelban.Stats.widgets")
|
||||
|
||||
public var popupKeyboardShortcut: [UInt16] {
|
||||
return self.popupView?.keyboardShortcut ?? []
|
||||
}
|
||||
|
||||
private var moduleType: ModuleType
|
||||
|
||||
private var settingsView: Settings_v? = nil
|
||||
|
||||
@@ -12,18 +12,40 @@
|
||||
import Cocoa
|
||||
|
||||
public protocol Popup_p: NSView {
|
||||
var keyboardShortcut: [UInt16] { get }
|
||||
var sizeCallback: ((NSSize) -> Void)? { get set }
|
||||
|
||||
func settings() -> NSView?
|
||||
|
||||
func appear()
|
||||
func disappear()
|
||||
func setKeyboardShortcut(_ binding: [UInt16])
|
||||
}
|
||||
|
||||
open class PopupWrapper: NSStackView, Popup_p {
|
||||
public var title: String
|
||||
public var keyboardShortcut: [UInt16] = []
|
||||
open var sizeCallback: ((NSSize) -> Void)? = nil
|
||||
|
||||
public init(_ typ: ModuleType, frame: NSRect) {
|
||||
self.title = typ.rawValue
|
||||
self.keyboardShortcut = Store.shared.array(key: "\(typ.rawValue)_popup_keyboardShortcut", defaultValue: []) as? [UInt16] ?? []
|
||||
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
open func settings() -> NSView? { return nil }
|
||||
open func appear() {}
|
||||
open func disappear() {}
|
||||
|
||||
open func setKeyboardShortcut(_ binding: [UInt16]) {
|
||||
self.keyboardShortcut = binding
|
||||
Store.shared.set(key: "\(self.title)_popup_keyboardShortcut", value: binding)
|
||||
}
|
||||
}
|
||||
|
||||
public class PopupWindow: NSWindow, NSWindowDelegate {
|
||||
|
||||
@@ -37,6 +37,10 @@ public class Store {
|
||||
return (!self.exist(key: key) ? value : defaults.integer(forKey: key))
|
||||
}
|
||||
|
||||
public func array(key: String, defaultValue value: [Any]) -> [Any] {
|
||||
return (!self.exist(key: key) ? value : defaults.array(forKey: key)!)
|
||||
}
|
||||
|
||||
public func data(key: String) -> Data? {
|
||||
return defaults.data(forKey: key)
|
||||
}
|
||||
@@ -57,6 +61,10 @@ public class Store {
|
||||
self.defaults.set(value, forKey: key)
|
||||
}
|
||||
|
||||
public func set(key: String, value: [Any]) {
|
||||
self.defaults.set(value, forKey: key)
|
||||
}
|
||||
|
||||
public func reset() {
|
||||
self.defaults.dictionaryRepresentation().keys.forEach { key in
|
||||
self.defaults.removeObject(forKey: key)
|
||||
|
||||
@@ -13,8 +13,6 @@ import Cocoa
|
||||
import Kit
|
||||
|
||||
internal class Popup: PopupWrapper {
|
||||
private var title: String
|
||||
|
||||
private var grid: NSGridView? = nil
|
||||
|
||||
private let dashboardHeight: CGFloat = 90
|
||||
@@ -65,9 +63,7 @@ internal class Popup: PopupWrapper {
|
||||
}
|
||||
|
||||
public init(_ module: ModuleType) {
|
||||
self.title = module.rawValue
|
||||
|
||||
super.init(frame: NSRect(
|
||||
super.init(module, frame: NSRect(
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: Constants.Popup.width,
|
||||
@@ -337,6 +333,13 @@ internal class Popup: PopupWrapper {
|
||||
public override func settings() -> NSView? {
|
||||
let view = SettingsContainerView()
|
||||
|
||||
view.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("Keyboard shortcut"), component: KeyboardShartcutView(
|
||||
callback: self.setKeyboardShortcut,
|
||||
value: self.keyboardShortcut
|
||||
))
|
||||
]))
|
||||
|
||||
view.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("Colorize battery"), component: switchView(
|
||||
action: #selector(self.toggleColor),
|
||||
|
||||
@@ -16,7 +16,7 @@ internal class Popup: PopupWrapper {
|
||||
private let emptyView: EmptyView = EmptyView(height: 30, isHidden: false, msg: localizedString("No Bluetooth devices are available"))
|
||||
|
||||
public init() {
|
||||
super.init(frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 30))
|
||||
super.init(ModuleType.bluetooth, frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 30))
|
||||
|
||||
self.orientation = .vertical
|
||||
self.spacing = Constants.Popup.margins
|
||||
|
||||
@@ -13,8 +13,6 @@ import Cocoa
|
||||
import Kit
|
||||
|
||||
internal class Popup: PopupWrapper {
|
||||
private var title: String
|
||||
|
||||
private let dashboardHeight: CGFloat = 90
|
||||
private let chartHeight: CGFloat = 120 + Constants.Popup.separatorHeight
|
||||
private var detailsHeight: CGFloat {
|
||||
@@ -125,14 +123,10 @@ internal class Popup: PopupWrapper {
|
||||
}
|
||||
|
||||
public init(_ module: ModuleType) {
|
||||
self.title = module.rawValue
|
||||
|
||||
super.init(frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
super.init(module, frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
|
||||
self.spacing = 0
|
||||
self.orientation = .vertical
|
||||
// self.setAccessibilityElement(true)
|
||||
// self.toolTip = self.title
|
||||
|
||||
self.systemColorState = SColor.fromString(Store.shared.string(key: "\(self.title)_systemColor", defaultValue: self.systemColorState.key))
|
||||
self.userColorState = SColor.fromString(Store.shared.string(key: "\(self.title)_userColor", defaultValue: self.userColorState.key))
|
||||
@@ -546,6 +540,13 @@ internal class Popup: PopupWrapper {
|
||||
public override func settings() -> NSView? {
|
||||
let view = SettingsContainerView()
|
||||
|
||||
view.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("Keyboard shortcut"), component: KeyboardShartcutView(
|
||||
callback: self.setKeyboardShortcut,
|
||||
value: self.keyboardShortcut
|
||||
))
|
||||
]))
|
||||
|
||||
view.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("System color"), component: selectView(
|
||||
action: #selector(self.toggleSystemColor),
|
||||
|
||||
@@ -13,8 +13,6 @@ import Cocoa
|
||||
import Kit
|
||||
|
||||
internal class Popup: PopupWrapper {
|
||||
private var title: String
|
||||
|
||||
private let orderTableView: OrderTableView = OrderTableView()
|
||||
private var list: [Clock_t] = []
|
||||
|
||||
@@ -22,9 +20,7 @@ internal class Popup: PopupWrapper {
|
||||
private var calendarState: Bool = true
|
||||
|
||||
public init(_ module: ModuleType) {
|
||||
self.title = module.rawValue
|
||||
|
||||
super.init(frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
super.init(module, frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
|
||||
self.orientation = .vertical
|
||||
self.spacing = Constants.Popup.margins
|
||||
@@ -87,6 +83,13 @@ internal class Popup: PopupWrapper {
|
||||
public override func settings() -> NSView? {
|
||||
let view = SettingsContainerView()
|
||||
|
||||
view.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("Keyboard shortcut"), component: KeyboardShartcutView(
|
||||
callback: self.setKeyboardShortcut,
|
||||
value: self.keyboardShortcut
|
||||
))
|
||||
]))
|
||||
|
||||
view.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("Calendar"), component: switchView(
|
||||
action: #selector(self.toggleCalendarState),
|
||||
|
||||
@@ -13,8 +13,6 @@ import Cocoa
|
||||
import Kit
|
||||
|
||||
internal class Popup: PopupWrapper {
|
||||
private var title: String
|
||||
|
||||
private var readColorState: SColor = .secondBlue
|
||||
private var readColor: NSColor { self.readColorState.additional as? NSColor ?? NSColor.systemRed }
|
||||
private var writeColorState: SColor = .secondRed
|
||||
@@ -43,9 +41,7 @@ internal class Popup: PopupWrapper {
|
||||
private var lastList: [String] = []
|
||||
|
||||
public init(_ module: ModuleType) {
|
||||
self.title = module.rawValue
|
||||
|
||||
super.init(frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
super.init(module, frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
|
||||
self.readColorState = SColor.fromString(Store.shared.string(key: "\(self.title)_readColor", defaultValue: self.readColorState.key))
|
||||
self.writeColorState = SColor.fromString(Store.shared.string(key: "\(self.title)_writeColor", defaultValue: self.writeColorState.key))
|
||||
@@ -193,6 +189,13 @@ internal class Popup: PopupWrapper {
|
||||
public override func settings() -> NSView? {
|
||||
let view = SettingsContainerView()
|
||||
|
||||
view.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("Keyboard shortcut"), component: KeyboardShartcutView(
|
||||
callback: self.setKeyboardShortcut,
|
||||
value: self.keyboardShortcut
|
||||
))
|
||||
]))
|
||||
|
||||
view.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("Write color"), component: selectView(
|
||||
action: #selector(self.toggleWriteColor),
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<key>Settings</key>
|
||||
<dict>
|
||||
<key>popup</key>
|
||||
<false/>
|
||||
<true/>
|
||||
<key>notifications</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
||||
@@ -14,7 +14,7 @@ import Kit
|
||||
|
||||
internal class Popup: PopupWrapper {
|
||||
public init() {
|
||||
super.init(frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
super.init(ModuleType.GPU, frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
|
||||
self.orientation = .vertical
|
||||
self.spacing = Constants.Popup.margins
|
||||
@@ -51,6 +51,21 @@ internal class Popup: PopupWrapper {
|
||||
self.sizeCallback?(self.frame.size)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Settings
|
||||
|
||||
public override func settings() -> NSView? {
|
||||
let view = SettingsContainerView()
|
||||
|
||||
view.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("Keyboard shortcut"), component: KeyboardShartcutView(
|
||||
callback: self.setKeyboardShortcut,
|
||||
value: self.keyboardShortcut
|
||||
))
|
||||
]))
|
||||
|
||||
return view
|
||||
}
|
||||
}
|
||||
|
||||
private class GPUView: NSStackView {
|
||||
|
||||
@@ -13,8 +13,6 @@ import Cocoa
|
||||
import Kit
|
||||
|
||||
internal class Popup: PopupWrapper {
|
||||
private var title: String
|
||||
|
||||
private var uploadContainerView: NSView? = nil
|
||||
private var uploadView: NSView? = nil
|
||||
private var uploadValue: Int64 = 0
|
||||
@@ -105,9 +103,7 @@ internal class Popup: PopupWrapper {
|
||||
}
|
||||
|
||||
public init(_ module: ModuleType) {
|
||||
self.title = module.rawValue
|
||||
|
||||
super.init(frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
super.init(module, frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
|
||||
self.spacing = 0
|
||||
self.orientation = .vertical
|
||||
@@ -563,6 +559,13 @@ internal class Popup: PopupWrapper {
|
||||
public override func settings() -> NSView? {
|
||||
let view = SettingsContainerView()
|
||||
|
||||
view.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("Keyboard shortcut"), component: KeyboardShartcutView(
|
||||
callback: self.setKeyboardShortcut,
|
||||
value: self.keyboardShortcut
|
||||
))
|
||||
]))
|
||||
|
||||
view.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("Color of download"), component: selectView(
|
||||
action: #selector(self.toggleDownloadColor),
|
||||
|
||||
@@ -13,8 +13,6 @@ import Cocoa
|
||||
import Kit
|
||||
|
||||
internal class Popup: PopupWrapper {
|
||||
private var title: String
|
||||
|
||||
private var grid: NSGridView? = nil
|
||||
|
||||
private let dashboardHeight: CGFloat = 90
|
||||
@@ -69,9 +67,7 @@ internal class Popup: PopupWrapper {
|
||||
private var chartColor: NSColor { self.chartColorState.additional as? NSColor ?? NSColor.systemBlue }
|
||||
|
||||
public init(_ module: ModuleType) {
|
||||
self.title = module.rawValue
|
||||
|
||||
super.init(frame: NSRect(
|
||||
super.init(module, frame: NSRect(
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: Constants.Popup.width,
|
||||
@@ -289,6 +285,13 @@ internal class Popup: PopupWrapper {
|
||||
public override func settings() -> NSView? {
|
||||
let view = SettingsContainerView()
|
||||
|
||||
view.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("Keyboard shortcut"), component: KeyboardShartcutView(
|
||||
callback: self.setKeyboardShortcut,
|
||||
value: self.keyboardShortcut
|
||||
))
|
||||
]))
|
||||
|
||||
view.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("App color"), component: selectView(
|
||||
action: #selector(toggleAppColor),
|
||||
|
||||
@@ -46,7 +46,7 @@ internal class Popup: PopupWrapper {
|
||||
}
|
||||
|
||||
public init() {
|
||||
super.init(frame: NSRect( x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
super.init(ModuleType.sensors, frame: NSRect( x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
|
||||
self.fanValueState = FanValue(rawValue: Store.shared.string(key: "Sensors_popup_fanValue", defaultValue: self.fanValueState.rawValue)) ?? .percentage
|
||||
|
||||
@@ -57,6 +57,13 @@ internal class Popup: PopupWrapper {
|
||||
self.settingsView.orientation = .vertical
|
||||
self.settingsView.spacing = Constants.Settings.margin
|
||||
|
||||
self.settingsView.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("Keyboard shortcut"), component: KeyboardShartcutView(
|
||||
callback: self.setKeyboardShortcut,
|
||||
value: self.keyboardShortcut
|
||||
))
|
||||
]))
|
||||
|
||||
self.settingsView.addArrangedSubview(PreferencesSection([
|
||||
PreferencesRow(localizedString("Fan value"), component: selectView(
|
||||
action: #selector(self.toggleFanValue),
|
||||
|
||||
@@ -74,6 +74,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
self.icon()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(listenForAppPause), name: .pause, object: nil)
|
||||
NSEvent.addGlobalMonitorForEvents(matching: [.keyDown, .flagsChanged]) { [weak self] event in
|
||||
self?.handleKeyEvent(event)
|
||||
}
|
||||
NSEvent.addLocalMonitorForEvents(matching: [.keyDown, .flagsChanged]) { [weak self] event in
|
||||
self?.handleKeyEvent(event)
|
||||
return event
|
||||
}
|
||||
|
||||
info("Stats started in \((startingPoint.timeIntervalSinceNow * -1).rounded(toPlaces: 4)) seconds")
|
||||
self.startTS = Date()
|
||||
|
||||
26
Stats/Supporting Files/Assets.xcassets/record.imageset/Contents.json
vendored
Normal file
26
Stats/Supporting Files/Assets.xcassets/record.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "baseline_radio_button_checked_black_20pt_1x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "baseline_radio_button_checked_black_20pt_2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "baseline_radio_button_checked_black_20pt_3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 233 B |
Binary file not shown.
|
After Width: | Height: | Size: 450 B |
Binary file not shown.
|
After Width: | Height: | Size: 636 B |
26
Stats/Supporting Files/Assets.xcassets/stop.imageset/Contents.json
vendored
Normal file
26
Stats/Supporting Files/Assets.xcassets/stop.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "baseline_stop_circle_black_20pt_1x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "baseline_stop_circle_black_20pt_2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "baseline_stop_circle_black_20pt_3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
BIN
Stats/Supporting Files/Assets.xcassets/stop.imageset/baseline_stop_circle_black_20pt_1x.png
vendored
Normal file
BIN
Stats/Supporting Files/Assets.xcassets/stop.imageset/baseline_stop_circle_black_20pt_1x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 153 B |
BIN
Stats/Supporting Files/Assets.xcassets/stop.imageset/baseline_stop_circle_black_20pt_2x.png
vendored
Normal file
BIN
Stats/Supporting Files/Assets.xcassets/stop.imageset/baseline_stop_circle_black_20pt_2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 248 B |
BIN
Stats/Supporting Files/Assets.xcassets/stop.imageset/baseline_stop_circle_black_20pt_3x.png
vendored
Normal file
BIN
Stats/Supporting Files/Assets.xcassets/stop.imageset/baseline_stop_circle_black_20pt_3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 343 B |
@@ -208,9 +208,12 @@ internal class CombinedView: NSObject, NSGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
private class Popup: NSStackView, Popup_p {
|
||||
fileprivate var keyboardShortcut: [UInt16] = []
|
||||
fileprivate var sizeCallback: ((NSSize) -> Void)? = nil
|
||||
|
||||
init() {
|
||||
self.keyboardShortcut = Store.shared.array(key: "CombinedModules_popup_keyboardShortcut", defaultValue: []) as? [UInt16] ?? []
|
||||
|
||||
super.init(frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
|
||||
self.orientation = .vertical
|
||||
@@ -234,6 +237,10 @@ private class Popup: NSStackView, Popup_p {
|
||||
fileprivate func settings() -> NSView? { return nil }
|
||||
fileprivate func appear() {}
|
||||
fileprivate func disappear() {}
|
||||
fileprivate func setKeyboardShortcut(_ binding: [UInt16]) {
|
||||
self.keyboardShortcut = binding
|
||||
Store.shared.set(key: "CombinedModules_popup_keyboardShortcut", value: binding)
|
||||
}
|
||||
|
||||
@objc private func reinit() {
|
||||
self.subviews.forEach({ $0.removeFromSuperview() })
|
||||
|
||||
@@ -265,4 +265,25 @@ extension AppDelegate {
|
||||
@objc internal func openSettings() {
|
||||
NotificationCenter.default.post(name: .toggleSettings, object: nil, userInfo: ["module": "Dashboard"])
|
||||
}
|
||||
|
||||
internal func handleKeyEvent(_ event: NSEvent) {
|
||||
var keyCodes: [UInt16] = []
|
||||
if event.modifierFlags.contains(.control) { keyCodes.append(59) }
|
||||
if event.modifierFlags.contains(.shift) { keyCodes.append(60) }
|
||||
if event.modifierFlags.contains(.command) { keyCodes.append(55) }
|
||||
if event.modifierFlags.contains(.option) { keyCodes.append(58) }
|
||||
keyCodes.append(event.keyCode)
|
||||
|
||||
guard !keyCodes.isEmpty,
|
||||
let module = modules.first(where: { $0.enabled && $0.popupKeyboardShortcut == keyCodes }),
|
||||
let widget = module.menuBar.widgets.filter({ $0.isActive }).first,
|
||||
let window = widget.item.window else { return }
|
||||
|
||||
NotificationCenter.default.post(name: .togglePopup, object: nil, userInfo: [
|
||||
"module": module.name,
|
||||
"widget": widget.type,
|
||||
"origin": window.frame.origin,
|
||||
"center": window.frame.width/2
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user