Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
435439ecd2 | ||
|
|
bb0c81ea76 | ||
|
|
c022018ec4 | ||
|
|
e10eed17ad | ||
|
|
17e2362ebf | ||
|
|
dd97c706f9 | ||
|
|
002af40756 | ||
|
|
285fb1fb85 | ||
|
|
1e07deedae | ||
|
|
a86d31b0ac | ||
|
|
0a0b393fb7 |
@@ -18,6 +18,8 @@
|
||||
B082B25A205C7D8000BC04DC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B082B258205C7D8000BC04DC /* Main.storyboard */; };
|
||||
B082B266205C7D8000BC04DC /* MTMRTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B082B265205C7D8000BC04DC /* MTMRTests.swift */; };
|
||||
B082B271205C7D8000BC04DC /* MTMRUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B082B270205C7D8000BC04DC /* MTMRUITests.swift */; };
|
||||
B09EB1E4207C082000D5C1E0 /* HapticFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = B09EB1E3207C082000D5C1E0 /* HapticFeedback.swift */; };
|
||||
B09EB1E6207C0F8E00D5C1E0 /* MultitouchSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B09EB1E5207C0F8E00D5C1E0 /* MultitouchSupport.framework */; };
|
||||
B0A7E9AA205D6AA400EEF070 /* KeyPress.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0A7E9A9205D6AA400EEF070 /* KeyPress.swift */; };
|
||||
B0A8BF9E207B84160086F74D /* weather.scpt in Resources */ = {isa = PBXBuildFile; fileRef = B0A8BF9D207B84160086F74D /* weather.scpt */; };
|
||||
B0C1CFCA205C97D30021C862 /* WindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0C1CFC9205C97D30021C862 /* WindowController.swift */; };
|
||||
@@ -64,6 +66,8 @@
|
||||
B082B26C205C7D8000BC04DC /* MTMRUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MTMRUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B082B270205C7D8000BC04DC /* MTMRUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MTMRUITests.swift; sourceTree = "<group>"; };
|
||||
B082B272205C7D8000BC04DC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
B09EB1E3207C082000D5C1E0 /* HapticFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticFeedback.swift; sourceTree = "<group>"; };
|
||||
B09EB1E5207C0F8E00D5C1E0 /* MultitouchSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MultitouchSupport.framework; path = ../../../../../System/Library/PrivateFrameworks/MultitouchSupport.framework; sourceTree = "<group>"; };
|
||||
B0A7E9A9205D6AA400EEF070 /* KeyPress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPress.swift; sourceTree = "<group>"; };
|
||||
B0A8BF9D207B84160086F74D /* weather.scpt */ = {isa = PBXFileReference; lastKnownFileType = text; path = weather.scpt; sourceTree = "<group>"; };
|
||||
B0C1CFC9205C97D30021C862 /* WindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowController.swift; sourceTree = "<group>"; };
|
||||
@@ -78,6 +82,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B059D62D205F11E8006E6B86 /* DFRFoundation.framework in Frameworks */,
|
||||
B09EB1E6207C0F8E00D5C1E0 /* MultitouchSupport.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -101,6 +106,7 @@
|
||||
B059D62B205F11E8006E6B86 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B09EB1E5207C0F8E00D5C1E0 /* MultitouchSupport.framework */,
|
||||
B059D62C205F11E8006E6B86 /* DFRFoundation.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
@@ -149,6 +155,7 @@
|
||||
B0F8771B207AC92700D6E430 /* TouchBarSupport.h */,
|
||||
B0F8771C207AD35400D6E430 /* battery.scpt */,
|
||||
B0A8BF9D207B84160086F74D /* weather.scpt */,
|
||||
B09EB1E3207C082000D5C1E0 /* HapticFeedback.swift */,
|
||||
);
|
||||
path = MTMR;
|
||||
sourceTree = "<group>";
|
||||
@@ -318,6 +325,7 @@
|
||||
B0F8771A207AC1EA00D6E430 /* TouchBarSupport.m in Sources */,
|
||||
B082B253205C7D8000BC04DC /* AppDelegate.swift in Sources */,
|
||||
B059D624205E04F3006E6B86 /* TouchBarItems.swift in Sources */,
|
||||
B09EB1E4207C082000D5C1E0 /* HapticFeedback.swift in Sources */,
|
||||
B0A7E9AA205D6AA400EEF070 /* KeyPress.swift in Sources */,
|
||||
36C2ECD7207B6DAE003CDA33 /* TimeTouchBarItem.swift in Sources */,
|
||||
);
|
||||
|
||||
@@ -1,28 +1,46 @@
|
||||
import Foundation
|
||||
|
||||
class AppleScriptTouchBarItem: NSCustomTouchBarItem {
|
||||
let script: NSAppleScript
|
||||
private var timer: Timer!
|
||||
private let script: NSAppleScript!
|
||||
private let button = NSButton(title: "", target: nil, action: nil)
|
||||
private let interval: TimeInterval
|
||||
|
||||
init?(identifier: NSTouchBarItem.Identifier, appleScript: String, interval: TimeInterval) {
|
||||
guard let script = NSAppleScript(source: appleScript) else {
|
||||
return nil
|
||||
}
|
||||
self.script = script
|
||||
self.interval = interval
|
||||
super.init(identifier: identifier)
|
||||
timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
|
||||
self.view = button
|
||||
button.bezelColor = .clear
|
||||
refresh()
|
||||
button.title = "compile"
|
||||
DispatchQueue.main.async {
|
||||
var error: NSDictionary?
|
||||
guard script.compileAndReturnError(&error) else {
|
||||
print(error?.description ?? "unknown error")
|
||||
DispatchQueue.main.async {
|
||||
self.button.title = "compile error"
|
||||
}
|
||||
return
|
||||
}
|
||||
self.refreshAndSchedule()
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc func refresh() {
|
||||
self.button.title = self.execute()
|
||||
func refreshAndSchedule() {
|
||||
print("refresh happened")
|
||||
let scriptResult = self.execute()
|
||||
DispatchQueue.main.async {
|
||||
self.button.title = scriptResult
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + self.interval) { [weak self] in
|
||||
self?.refreshAndSchedule()
|
||||
}
|
||||
}
|
||||
|
||||
func execute() -> String {
|
||||
|
||||
@@ -1,53 +1,63 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "16x16",
|
||||
"idiom" : "mac",
|
||||
"filename" : "logo-16.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "16x16",
|
||||
"idiom" : "mac",
|
||||
"filename" : "logo-32.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "32x32",
|
||||
"idiom" : "mac",
|
||||
"filename" : "logo-32.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "32x32",
|
||||
"idiom" : "mac",
|
||||
"filename" : "logo-64.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "128x128",
|
||||
"idiom" : "mac",
|
||||
"filename" : "logo-128.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "128x128",
|
||||
"idiom" : "mac",
|
||||
"filename" : "logo-256.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "256x256",
|
||||
"idiom" : "mac",
|
||||
"filename" : "logo-256.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "256x256",
|
||||
"idiom" : "mac",
|
||||
"filename" : "logo-512.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "512x512",
|
||||
"idiom" : "mac",
|
||||
"filename" : "logo-512.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "512x512",
|
||||
"idiom" : "mac",
|
||||
"filename" : "logo-1024.png",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
|
||||
|
After Width: | Height: | Size: 151 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// HapticFeedback.swift
|
||||
// MTMR
|
||||
//
|
||||
// Created by Anton Palgunov on 09/04/2018.
|
||||
// Copyright © 2018 Anton Palgunov. All rights reserved.
|
||||
//
|
||||
|
||||
import IOKit
|
||||
|
||||
class HapticFeedback {
|
||||
private var actuatorRef: CFTypeRef?
|
||||
private var deviceID: UInt64 = 0x200000001000000
|
||||
private var error: IOReturn = 0
|
||||
|
||||
// Don't know how to do strong is enum one of
|
||||
// 1 like backClick
|
||||
// 2 (like Click)
|
||||
// 3 (week)
|
||||
// 4 (medium)
|
||||
// 5 (week medium)
|
||||
// 6 (strong)
|
||||
// 15 (nothing)
|
||||
// 16 (nothing)
|
||||
|
||||
func tap(strong:Int32) -> Void {
|
||||
let actuatorRef = MTActuatorCreateFromDeviceID(deviceID).takeRetainedValue()
|
||||
|
||||
// TODO: Need to fix warning
|
||||
guard actuatorRef != nil else {
|
||||
print("guard actuatorRef == nil")
|
||||
return
|
||||
}
|
||||
|
||||
error = MTActuatorOpen(actuatorRef)
|
||||
guard error == kIOReturnSuccess else {
|
||||
print("guard MTActuatorOpen")
|
||||
return
|
||||
}
|
||||
|
||||
error = MTActuatorActuate(actuatorRef, strong, 0, 0.0, 0.0)
|
||||
guard error == kIOReturnSuccess else {
|
||||
print("guard MTActuatorActuate")
|
||||
return
|
||||
}
|
||||
|
||||
error = MTActuatorClose(actuatorRef)
|
||||
guard error == kIOReturnSuccess else {
|
||||
print("guard MTActuatorClose")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,11 +30,11 @@ struct ESCKeyPress: KeyPress {
|
||||
}
|
||||
|
||||
struct BrightnessUpPress: KeyPress {
|
||||
let keyCode: CGKeyCode = 107
|
||||
let keyCode: CGKeyCode = 113
|
||||
}
|
||||
|
||||
struct BrightnessDownPress: KeyPress {
|
||||
let keyCode: CGKeyCode = 113
|
||||
let keyCode: CGKeyCode = 107
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -61,6 +61,13 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
NSTouchBar.minimizeSystemModalFunctionBar(touchBar)
|
||||
}
|
||||
|
||||
@objc func goToSleep() {
|
||||
let task = Process()
|
||||
task.launchPath = "/usr/bin/pmset"
|
||||
task.arguments = ["sleepnow"]
|
||||
task.launch()
|
||||
}
|
||||
|
||||
func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {
|
||||
switch identifier {
|
||||
case .escButton:
|
||||
@@ -84,6 +91,11 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
let url = Bundle.main.url(forResource: "weather", withExtension: "scpt")!
|
||||
let script = try! String.init(contentsOf: url)
|
||||
return AppleScriptTouchBarItem(identifier: identifier, appleScript: script, interval: 600)
|
||||
|
||||
case .sleep:
|
||||
let item = NSCustomTouchBarItem(identifier: identifier)
|
||||
item.view = NSButton(title: "☕️", target: self, action: #selector(goToSleep))
|
||||
return item
|
||||
|
||||
case .prev:
|
||||
return CustomButtonTouchBarItem(identifier: identifier, title: "⏪", HIDKeycode: NX_KEYTYPE_PREVIOUS)
|
||||
|
||||
@@ -11,45 +11,47 @@ import Cocoa
|
||||
extension NSTouchBarItem.Identifier {
|
||||
static let escButton = NSTouchBarItem.Identifier("com.toxblh.mtmr.escButton")
|
||||
static let dismissButton = NSTouchBarItem.Identifier("com.toxblh.mtmr.dismissButton")
|
||||
|
||||
|
||||
// Volume
|
||||
static let volumeUp = NSTouchBarItem.Identifier("com.toxblh.mtmr.volumeUp")
|
||||
static let volumeDown = NSTouchBarItem.Identifier("com.toxblh.mtmr.volumeDown")
|
||||
|
||||
|
||||
// Brightness
|
||||
static let brightUp = NSTouchBarItem.Identifier("com.toxblh.mtmr.brightUp")
|
||||
static let brightDown = NSTouchBarItem.Identifier("com.toxblh.mtmr.brightDown")
|
||||
|
||||
|
||||
// Music
|
||||
static let prev = NSTouchBarItem.Identifier("com.toxblh.mtmr.prev")
|
||||
static let next = NSTouchBarItem.Identifier("com.toxblh.mtmr.next")
|
||||
static let play = NSTouchBarItem.Identifier("com.toxblh.mtmr.play")
|
||||
|
||||
|
||||
// Plugins
|
||||
static let sleep = NSTouchBarItem.Identifier("com.toxblh.mtmr.sleep")
|
||||
static let weather = NSTouchBarItem.Identifier("com.toxblh.mtmr.weather")
|
||||
static let time = NSTouchBarItem.Identifier("com.toxblh.mtmr.time")
|
||||
static let battery = NSTouchBarItem.Identifier("com.toxblh.mtmr.battery")
|
||||
static let nowPlaying = NSTouchBarItem.Identifier("com.toxblh.mtmr.nowPlaying")
|
||||
|
||||
|
||||
static let controlStripItem = NSTouchBarItem.Identifier("com.toxblh.mtmr.controlStrip")
|
||||
}
|
||||
|
||||
class CustomButtonTouchBarItem: NSCustomTouchBarItem {
|
||||
let tapClosure: (NSCustomTouchBarItem) -> ()
|
||||
|
||||
|
||||
init(identifier: NSTouchBarItem.Identifier, title: String, onTap callback: @escaping (NSCustomTouchBarItem) -> ()) {
|
||||
self.tapClosure = callback
|
||||
super.init(identifier: identifier)
|
||||
self.view = NSButton(title: title, target: self, action: #selector(didTapped))
|
||||
}
|
||||
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
|
||||
@objc func didTapped() {
|
||||
self.tapClosure(self)
|
||||
let hf: HapticFeedback = HapticFeedback()
|
||||
hf.tap(strong: 6)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,3 +8,13 @@
|
||||
|
||||
#import "TouchBarPrivateApi.h"
|
||||
#import "TouchBarSupport.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
CF_EXPORT CFTypeRef MTActuatorCreateFromDeviceID(UInt64 deviceID);
|
||||
CF_EXPORT IOReturn MTActuatorOpen(CFTypeRef actuatorRef);
|
||||
CF_EXPORT IOReturn MTActuatorClose(CFTypeRef actuatorRef);
|
||||
CF_EXPORT IOReturn MTActuatorActuate(CFTypeRef actuatorRef, SInt32 actuationID, UInt32 arg1, Float32 arg2, Float32 arg3);
|
||||
CF_EXPORT bool MTActuatorIsOpen(CFTypeRef actuatorRef);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<img src="Resources/TouchBar-v0.3.png">
|
||||
</p>
|
||||
|
||||
My the idea is to create the program like a platform for plugins for customization TouchBar. I very like BTT and a full custom TouchBar. And I want to create it. And it's my the first Swift project for MacOS :)
|
||||
My the idea is to create the program like a platform for plugins for customization TouchBar. I very like BTT and a full custom TouchBar (my [BTT preset](https://github.com/Toxblh/btt-touchbar-preset)). And I want to create it. And it's my the first Swift project for MacOS :)
|
||||
|
||||
### Roadmap
|
||||
- [x] Create the first prototype with TouchBar in Storyboard
|
||||
@@ -17,6 +17,21 @@ My the idea is to create the program like a platform for plugins for customizati
|
||||
- [x] Time in touchbar!
|
||||
- [x] First the weather plugin
|
||||
- [x] Find how to open full-screen TouchBar without the cross and stripe menu
|
||||
- [ ] Create the same panel like in my [BTT preset](https://github.com/Toxblh/btt-touchbar-preset)
|
||||
- [ ] Find how to add haptic feedback
|
||||
- [ ] JSON or another approch for save preset and plugins maybe in `~/mtmr`
|
||||
- [ ] Layout: [always left, NSSliderView for center, always right]
|
||||
- [ ] Custom buttons size, actions by click in settings
|
||||
- [ ] Add icon and menu in StatusBar
|
||||
- [ ] Hide from Dock
|
||||
- [ ] Status menu: "preferences", "quit"
|
||||
- [ ] System for autoupdate (maybe https://sparkle-project.org/)
|
||||
|
||||
Settings:
|
||||
- [ ] Intarface for plugins and export like presets
|
||||
- [ ] Startup at login
|
||||
- [ ] Show on/off in Dock
|
||||
- [ ] Show on/off in StatusBar
|
||||
- [ ] On/off Haptic Feedback
|
||||
|
||||
Maybe:
|
||||
- [ ] Refactoring the application on packages (AppleScript, JavaScript? and Swift?)
|
||||
|
||||