From d632bd3ee77da27cb5ba0a43351f073f332e9599 Mon Sep 17 00:00:00 2001 From: ad Date: Sun, 22 Apr 2018 17:55:20 +0300 Subject: [PATCH 1/2] + show input source --- MTMR.xcodeproj/project.pbxproj | 4 ++ MTMR/InputSourceBarItem.swift | 76 ++++++++++++++++++++++++++++++++++ MTMR/ItemsParsing.swift | 7 ++++ MTMR/TouchBarController.swift | 4 ++ 4 files changed, 91 insertions(+) create mode 100644 MTMR/InputSourceBarItem.swift diff --git a/MTMR.xcodeproj/project.pbxproj b/MTMR.xcodeproj/project.pbxproj index 80192d8..3dd0984 100644 --- a/MTMR.xcodeproj/project.pbxproj +++ b/MTMR.xcodeproj/project.pbxproj @@ -20,6 +20,7 @@ 6042B6AA2083E27000C525C8 /* DeprecatedCarbonAPI.c in Sources */ = {isa = PBXBuildFile; fileRef = 6042B6A92083E27000C525C8 /* DeprecatedCarbonAPI.c */; }; 607EEA4B2087835F009DA5F0 /* WeatherBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607EEA4A2087835F009DA5F0 /* WeatherBarItem.swift */; }; 607EEA4D2087A8DA009DA5F0 /* CurrencyBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607EEA4C2087A8DA009DA5F0 /* CurrencyBarItem.swift */; }; + 60F7D454208CC31400ABF5D2 /* InputSourceBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60F7D453208CC31400ABF5D2 /* InputSourceBarItem.swift */; }; B0008E552080286C003AD4DD /* SupportHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0008E542080286C003AD4DD /* SupportHelpers.swift */; }; B04B7BB72087398C00C835D0 /* BatteryBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B04B7BB62087398C00C835D0 /* BatteryBarItem.swift */; }; B05600D32083E9BB00EB218D /* CustomSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B05600D22083E9BB00EB218D /* CustomSlider.swift */; }; @@ -71,6 +72,7 @@ 6042B6A92083E27000C525C8 /* DeprecatedCarbonAPI.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = DeprecatedCarbonAPI.c; sourceTree = ""; }; 607EEA4A2087835F009DA5F0 /* WeatherBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherBarItem.swift; sourceTree = ""; }; 607EEA4C2087A8DA009DA5F0 /* CurrencyBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyBarItem.swift; sourceTree = ""; }; + 60F7D453208CC31400ABF5D2 /* InputSourceBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputSourceBarItem.swift; sourceTree = ""; }; B0008E542080286C003AD4DD /* SupportHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportHelpers.swift; sourceTree = ""; }; B04B7BB62087398C00C835D0 /* BatteryBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryBarItem.swift; sourceTree = ""; }; B05600D22083E9BB00EB218D /* CustomSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSlider.swift; sourceTree = ""; }; @@ -181,6 +183,7 @@ B04B7BB62087398C00C835D0 /* BatteryBarItem.swift */, 607EEA4A2087835F009DA5F0 /* WeatherBarItem.swift */, 607EEA4C2087A8DA009DA5F0 /* CurrencyBarItem.swift */, + 60F7D453208CC31400ABF5D2 /* InputSourceBarItem.swift */, ); path = MTMR; sourceTree = ""; @@ -352,6 +355,7 @@ 607EEA4B2087835F009DA5F0 /* WeatherBarItem.swift in Sources */, 6042B6AA2083E27000C525C8 /* DeprecatedCarbonAPI.c in Sources */, B09EB1E4207C082000D5C1E0 /* HapticFeedback.swift in Sources */, + 60F7D454208CC31400ABF5D2 /* InputSourceBarItem.swift in Sources */, 36C2ECDB207C3FE7003CDA33 /* ItemsParsing.swift in Sources */, B0A7E9AA205D6AA400EEF070 /* KeyPress.swift in Sources */, 36C2ECD7207B6DAE003CDA33 /* TimeTouchBarItem.swift in Sources */, diff --git a/MTMR/InputSourceBarItem.swift b/MTMR/InputSourceBarItem.swift new file mode 100644 index 0000000..a17f972 --- /dev/null +++ b/MTMR/InputSourceBarItem.swift @@ -0,0 +1,76 @@ +// +// InputSourceBarItem.swift +// MTMR +// +// Created by Daniel Apatin on 22.04.2018. +// Copyright © 2018 Anton Palgunov. All rights reserved. +// + +import Cocoa + +class InputSourceBarItem: NSCustomTouchBarItem { + private(set) var button: NSButton! + fileprivate var notificationCenter: CFNotificationCenter + var lastLang: String! + + override init(identifier: NSTouchBarItem.Identifier) { + notificationCenter = CFNotificationCenterGetDistributedCenter(); + super.init(identifier: identifier) + + button = NSButton(title: " ", target: self, action: nil) + + self.view = button + + observeIputSourceChangedNotification(); + + textInputSourceDidChange() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc public func textInputSourceDidChange() { + let currentSource = TISCopyCurrentKeyboardInputSource().takeUnretainedValue() + let ptrID = TISGetInputSourceProperty(currentSource as TISInputSource, kTISPropertyInputSourceID) + let ID = unsafeBitCast(ptrID, to: CFString.self) + + switch String(ID) { + case "com.apple.keylayout.RussianWin": + self.button.title = "RU" + break + case "com.apple.keylayout.US": + self.button.title = "US" + break + default: + self.button.title = String(ID) + } +// print(ID) + } + +// private func getInputSource() -> String { +// let keyboard = TISCopyCurrentKeyboardInputSource().takeRetainedValue() +// let keyboardString = String(describing: keyboard) +// let range = keyboardString.range(of: "KB Layout: ", options: .literal, range: keyboardString.startIndex...fromOpaque(observer!).takeUnretainedValue() + mySelf.textInputSourceDidChange() + } + + CFNotificationCenterAddObserver(notificationCenter, + UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque()), + callback, + kTISNotifySelectedKeyboardInputSourceChanged, + nil, + .deliverImmediately) + } +} + + diff --git a/MTMR/ItemsParsing.swift b/MTMR/ItemsParsing.swift index dedc5af..68d8600 100644 --- a/MTMR/ItemsParsing.swift +++ b/MTMR/ItemsParsing.swift @@ -100,6 +100,9 @@ class SupportedTypesHolder { "dock": { decoder in return (item: .dock(), action: .none, longAction: .none, parameters: [:]) }, + "inputsource": { decoder in + return (item: .inputsource(), action: .none, longAction: .none, parameters: [:]) + }, "volume": { decoder in enum CodingKeys: String, CodingKey { case image } let container = try decoder.container(keyedBy: CodingKeys.self) @@ -152,6 +155,7 @@ enum ItemType: Decodable { case brightness(refreshInterval: Double) case weather(interval: Double, units: String, api_key: String, icon_type: String) case currency(interval: Double, from: String, to: String) + case inputsource() private enum CodingKeys: String, CodingKey { case type @@ -179,6 +183,7 @@ enum ItemType: Decodable { case brightness case weather case currency + case inputsource } init(from decoder: Decoder) throws { @@ -215,6 +220,8 @@ enum ItemType: Decodable { let from = try container.decodeIfPresent(String.self, forKey: .from) ?? "RUB" let to = try container.decodeIfPresent(String.self, forKey: .to) ?? "USD" self = .currency(interval: interval, from: from, to: to) + case .inputsource: + self = .inputsource() } } } diff --git a/MTMR/TouchBarController.swift b/MTMR/TouchBarController.swift index b4f7f4f..df188c3 100644 --- a/MTMR/TouchBarController.swift +++ b/MTMR/TouchBarController.swift @@ -35,6 +35,8 @@ extension ItemType { return "com.toxblh.mtmr.weather" case .currency(interval: _, from: _, to: _): return "com.toxblh.mtmr.currency" + case .inputsource(): + return "com.toxblh.mtmr.inputsource." } } @@ -190,6 +192,8 @@ class TouchBarController: NSObject, NSTouchBarDelegate { barItem = WeatherBarItem(identifier: identifier, interval: interval, units: units, api_key: api_key, icon_type: icon_type, onTap: action, onLongTap: longAction) case .currency(interval: let interval, from: let from, to: let to): barItem = CurrencyBarItem(identifier: identifier, interval: interval, from: from, to: to, onTap: action, onLongTap: longAction) + case .inputsource(): + barItem = InputSourceBarItem(identifier: identifier) } if case .width(let value)? = item.additionalParameters[.width], let widthBarItem = barItem as? CanSetWidth { From 04b821510bc87418ace5a80e3004d82ce4a616a3 Mon Sep 17 00:00:00 2001 From: ad Date: Sun, 22 Apr 2018 19:22:45 +0300 Subject: [PATCH 2/2] + switch input source by tap --- MTMR/InputSourceBarItem.swift | 119 ++++++++++++++++++++++++---------- MTMR/TouchBarController.swift | 2 +- 2 files changed, 87 insertions(+), 34 deletions(-) diff --git a/MTMR/InputSourceBarItem.swift b/MTMR/InputSourceBarItem.swift index a17f972..fbce9db 100644 --- a/MTMR/InputSourceBarItem.swift +++ b/MTMR/InputSourceBarItem.swift @@ -8,22 +8,18 @@ import Cocoa -class InputSourceBarItem: NSCustomTouchBarItem { - private(set) var button: NSButton! - fileprivate var notificationCenter: CFNotificationCenter - var lastLang: String! - - override init(identifier: NSTouchBarItem.Identifier) { - notificationCenter = CFNotificationCenterGetDistributedCenter(); - super.init(identifier: identifier) - - button = NSButton(title: " ", target: self, action: nil) +class InputSourceBarItem: CustomButtonTouchBarItem { - self.view = button + fileprivate var notificationCenter: CFNotificationCenter + + init(identifier: NSTouchBarItem.Identifier, onTap: @escaping () -> (), onLongTap: @escaping () -> ()) { + notificationCenter = CFNotificationCenterGetDistributedCenter(); + super.init(identifier: identifier, title: "⏳", onTap: onTap, onLongTap: onLongTap) observeIputSourceChangedNotification(); - textInputSourceDidChange() + + self.button.action = #selector(switchInputSource) } required init?(coder: NSCoder) { @@ -32,31 +28,44 @@ class InputSourceBarItem: NSCustomTouchBarItem { @objc public func textInputSourceDidChange() { let currentSource = TISCopyCurrentKeyboardInputSource().takeUnretainedValue() - let ptrID = TISGetInputSourceProperty(currentSource as TISInputSource, kTISPropertyInputSourceID) - let ID = unsafeBitCast(ptrID, to: CFString.self) + + var iconImage: NSImage? = nil - switch String(ID) { - case "com.apple.keylayout.RussianWin": - self.button.title = "RU" - break - case "com.apple.keylayout.US": - self.button.title = "US" - break - default: - self.button.title = String(ID) + if let imageURL = currentSource.iconImageURL { + if let image = NSImage(contentsOf: imageURL) { + iconImage = image + } + } + + if iconImage == nil, let iconRef = currentSource.iconRef { + iconImage = NSImage(iconRef: iconRef) + } + + if (iconImage != nil) { + self.button.image = iconImage + } else { + self.button.title = currentSource.name } -// print(ID) } -// private func getInputSource() -> String { -// let keyboard = TISCopyCurrentKeyboardInputSource().takeRetainedValue() -// let keyboardString = String(describing: keyboard) -// let range = keyboardString.range(of: "KB Layout: ", options: .literal, range: keyboardString.startIndex.. AnyObject? { + let cfType = TISGetInputSourceProperty(self, key) + if (cfType != nil) { + return Unmanaged.fromOpaque(cfType!).takeUnretainedValue() + } else { + return nil + } + } + + var id: String { + return getProperty(kTISPropertyInputSourceID) as! String + } + + var name: String { + return getProperty(kTISPropertyLocalizedName) as! String + } + + var category: String { + return getProperty(kTISPropertyInputSourceCategory) as! String + } + + var isSelectable: Bool { + return getProperty(kTISPropertyInputSourceIsSelectCapable) as! Bool + } + + var sourceLanguages: [String] { + return getProperty(kTISPropertyInputSourceLanguages) as! [String] + } + + var iconImageURL: URL? { + return getProperty(kTISPropertyIconImageURL) as! URL? + } + + var iconRef: IconRef? { + return OpaquePointer(TISGetInputSourceProperty(self, kTISPropertyIconRef)) as IconRef? + } +} diff --git a/MTMR/TouchBarController.swift b/MTMR/TouchBarController.swift index df188c3..20c22d5 100644 --- a/MTMR/TouchBarController.swift +++ b/MTMR/TouchBarController.swift @@ -193,7 +193,7 @@ class TouchBarController: NSObject, NSTouchBarDelegate { case .currency(interval: let interval, from: let from, to: let to): barItem = CurrencyBarItem(identifier: identifier, interval: interval, from: from, to: to, onTap: action, onLongTap: longAction) case .inputsource(): - barItem = InputSourceBarItem(identifier: identifier) + barItem = InputSourceBarItem(identifier: identifier, onTap: action, onLongTap: longAction) } if case .width(let value)? = item.additionalParameters[.width], let widthBarItem = barItem as? CanSetWidth {