1
0
mirror of https://github.com/Toxblh/MTMR.git synced 2026-01-11 09:28:38 +00:00

Compare commits

...

3 Commits

Author SHA1 Message Date
Wiktor Latanowicz
36bf749a46
App id matching (#432)
* Add app id matching for buttons

* Hide MT button from  control strip when touch bar is empty

Co-authored-by: Wiktor Latanowicz <wiktor@latanowicz.com>
Co-authored-by: Anton Palgunov <Toxblh@users.noreply.github.com>
2022-02-16 19:01:09 +00:00
Piss Man
ac0e44db4d
Modified the way shell script are called (#430)
* Added shell detection

* Replaced deprecated object to supported version

* Updated haptic feedback.swift to support for newer mac

Added support for m1 mac
2022-02-16 19:00:28 +00:00
Dennis Wurster
26ad83be70
fixed grammar and clarity of README (#427)
* fixed grammar and clarity of README

* Update README.md

Co-authored-by: Anton Palgunov <Toxblh@users.noreply.github.com>
2022-02-16 18:59:41 +00:00
8 changed files with 130 additions and 34 deletions

View File

@ -19,6 +19,7 @@ class HapticFeedback {
0x200_0000_0100_0000, // MacBook Pro 2016/2017 0x200_0000_0100_0000, // MacBook Pro 2016/2017
0x300_0000_8050_0000, // MacBook Pro 2019/2018 0x300_0000_8050_0000, // MacBook Pro 2019/2018
0x200_0000_0000_0024, // MacBook Pro (13-inch, M1, 2020) 0x200_0000_0000_0024, // MacBook Pro (13-inch, M1, 2020)
0x200_0000_0000_0023 // MacBook Pro M1 13-Inch 2020 with 1tb
] ]
// you can get a plist `otool -s __TEXT __tpad_act_plist /System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/Current/MultitouchSupport|tail -n +3|awk -F'\t' '{print $2}'|xxd -r -p` // you can get a plist `otool -s __TEXT __tpad_act_plist /System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/Current/MultitouchSupport|tail -n +3|awk -F'\t' '{print $2}'|xxd -r -p`

View File

@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.27</string> <string>0.27</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>434</string> <string>448</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string> <string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>

View File

@ -658,6 +658,7 @@ enum GeneralParameter {
case bordered(_: Bool) case bordered(_: Bool)
case background(_: NSColor) case background(_: NSColor)
case title(_: String) case title(_: String)
case matchAppId(_: String)
} }
struct GeneralParameters: Decodable { struct GeneralParameters: Decodable {
@ -670,6 +671,7 @@ struct GeneralParameters: Decodable {
case bordered case bordered
case background case background
case title case title
case matchAppId
} }
init(from decoder: Decoder) throws { init(from decoder: Decoder) throws {
@ -699,6 +701,10 @@ struct GeneralParameters: Decodable {
result[.title] = .title(title) result[.title] = .title(title)
} }
if let matchAppId = try container.decodeIfPresent(String.self, forKey: .matchAppId) {
result[.matchAppId] = .matchAppId(matchAppId)
}
parameters = result parameters = result
} }
} }

View File

@ -78,7 +78,11 @@ class ShellScriptTouchBarItem: CustomButtonTouchBarItem {
func execute(_ command: String) -> String { func execute(_ command: String) -> String {
let task = Process() let task = Process()
task.launchPath = "/bin/bash" if let shell = getenv("SHELL") {
task.launchPath = String.init(cString: shell)
} else {
task.launchPath = "/bin/bash"
}
task.arguments = ["-c", command] task.arguments = ["-c", command]
let pipe = Pipe() let pipe = Pipe()

View File

@ -51,7 +51,11 @@ class SwipeItem: NSCustomTouchBarItem {
if scriptBash != nil { if scriptBash != nil {
DispatchQueue.shellScriptQueue.async { DispatchQueue.shellScriptQueue.async {
let task = Process() let task = Process()
task.launchPath = "/bin/bash" if let shell = getenv("SHELL") {
task.launchPath = String.init(cString: shell)
} else {
task.launchPath = "/bin/bash"
}
task.arguments = ["-c", self.scriptBash!] task.arguments = ["-c", self.scriptBash!]
task.launch() task.launch()
task.waitUntilExit() task.waitUntilExit()
@ -63,4 +67,12 @@ class SwipeItem: NSCustomTouchBarItem {
} }
} }
} }
func isEqual(_ object: AnyObject?) -> Bool {
if let object = object as? SwipeItem {
return self.scriptApple?.source as String? == object.scriptApple?.source as String? && self.scriptBash == object.scriptBash && self.direction == object.direction && self.fingers == object.fingers && self.minOffset == object.minOffset
} else {
return false
}
}
} }

View File

@ -134,17 +134,56 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
touchBar = NSTouchBar() touchBar = NSTouchBar()
jsonItems = newJsonItems jsonItems = newJsonItems
itemDefinitions = [:] itemDefinitions = [:]
items = [:]
loadItemDefinitions(jsonItems: jsonItems) loadItemDefinitions(jsonItems: jsonItems)
updateActiveApp()
}
func didItemsChange(prevItems: [NSTouchBarItem.Identifier: NSTouchBarItem], prevSwipeItems: [SwipeItem]) -> Bool {
var changed = items.count != prevItems.count || swipeItems.count != prevSwipeItems.count
if !changed {
for (item, prevItem) in zip(items, prevItems) {
if item.key != prevItem.key {
changed = true
break
}
}
}
if !changed {
for (swipeItem, prevSwipeItem) in zip(swipeItems, prevSwipeItems) {
if !swipeItem.isEqual(prevSwipeItem) {
changed = true
break
}
}
}
return changed
}
func prepareTouchBar() {
let prevItems = items
let prevSwipeItems = swipeItems
createItems() createItems()
let changed = didItemsChange(prevItems: prevItems, prevSwipeItems: prevSwipeItems)
if !changed {
return
}
let centerItems = centerIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in let centerItems = centerIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
items[identifier] items[identifier]
}) })
let centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString)) let centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
let scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems) let scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
basicViewIdentifier = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollView.".appending(UUID().uuidString))
touchBar.delegate = self touchBar.delegate = self
touchBar.defaultItemIdentifiers = [basicViewIdentifier] touchBar.defaultItemIdentifiers = [basicViewIdentifier]
@ -158,8 +197,6 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
basicView = BasicView(identifier: basicViewIdentifier, items:leftItems + [scrollArea] + rightItems, swipeItems: swipeItems) basicView = BasicView(identifier: basicViewIdentifier, items:leftItems + [scrollArea] + rightItems, swipeItems: swipeItems)
basicView?.legacyGesturesEnabled = AppSettings.multitouchGestures basicView?.legacyGesturesEnabled = AppSettings.multitouchGestures
updateActiveApp()
} }
@objc func activeApplicationChanged(_: Notification) { @objc func activeApplicationChanged(_: Notification) {
@ -170,9 +207,18 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
if frontmostApplicationIdentifier != nil && blacklistAppIdentifiers.firstIndex(of: frontmostApplicationIdentifier!) != nil { if frontmostApplicationIdentifier != nil && blacklistAppIdentifiers.firstIndex(of: frontmostApplicationIdentifier!) != nil {
dismissTouchBar() dismissTouchBar()
} else { } else {
presentTouchBar() prepareTouchBar()
if touchBarContainsAnyItems() {
presentTouchBar()
} else {
dismissTouchBar()
}
} }
} }
func touchBarContainsAnyItems() -> Bool {
return items.count != 0 || swipeItems.count != 0
}
func reloadStandardConfig() { func reloadStandardConfig() {
let presetPath = standardConfigPath let presetPath = standardConfigPath
@ -212,12 +258,29 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
} }
func createItems() { func createItems() {
items = [:]
swipeItems = []
for (identifier, definition) in itemDefinitions { for (identifier, definition) in itemDefinitions {
let item = createItem(forIdentifier: identifier, definition: definition) var show = true
if item is SwipeItem {
swipeItems.append(item as! SwipeItem) if let frontApp = frontmostApplicationIdentifier {
} else { if case let .matchAppId(regexString)? = definition.additionalParameters[.matchAppId] {
items[identifier] = item let regex = try! NSRegularExpression(pattern: regexString)
let range = NSRange(location: 0, length: frontApp.count)
if regex.firstMatch(in: frontApp, range: range) == nil {
show = false
}
}
}
if show {
let item = createItem(forIdentifier: identifier, definition: definition)
if item is SwipeItem {
swipeItems.append(item as! SwipeItem)
} else {
items[identifier] = item
}
} }
} }
} }
@ -231,26 +294,29 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
} }
func updateControlStripPresence() { func updateControlStripPresence() {
DFRElementSetControlStripPresenceForIdentifier(.controlStripItem, true) let showMtmrButtonOnControlStrip = touchBarContainsAnyItems()
DFRElementSetControlStripPresenceForIdentifier(.controlStripItem, showMtmrButtonOnControlStrip)
} }
@objc private func presentTouchBar() { @objc private func presentTouchBar() {
if AppSettings.showControlStripState { if AppSettings.showControlStripState {
updateControlStripPresence()
presentSystemModal(touchBar, systemTrayItemIdentifier: .controlStripItem) presentSystemModal(touchBar, systemTrayItemIdentifier: .controlStripItem)
} else { } else {
presentSystemModal(touchBar, placement: 1, systemTrayItemIdentifier: .controlStripItem) presentSystemModal(touchBar, placement: 1, systemTrayItemIdentifier: .controlStripItem)
} }
updateControlStripPresence()
} }
@objc private func dismissTouchBar() { @objc private func dismissTouchBar() {
minimizeSystemModal(touchBar) if touchBarContainsAnyItems() {
minimizeSystemModal(touchBar)
}
updateControlStripPresence() updateControlStripPresence()
} }
@objc func resetControlStrip() { @objc func resetControlStrip() {
dismissTouchBar() dismissTouchBar()
presentTouchBar() updateActiveApp()
} }
func touchBar(_: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? { func touchBar(_: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {

View File

@ -10,7 +10,7 @@ class VolumeViewController: NSCustomTouchBarItem {
super.init(identifier: identifier) super.init(identifier: identifier)
var forPropertyAddress = AudioObjectPropertyAddress( var forPropertyAddress = AudioObjectPropertyAddress(
mSelector: kAudioHardwareServiceDeviceProperty_VirtualMasterVolume, mSelector: kAudioHardwareServiceDeviceProperty_VirtualMainVolume,
mScope: kAudioDevicePropertyScopeOutput, mScope: kAudioDevicePropertyScopeOutput,
mElement: kAudioObjectPropertyElementMaster mElement: kAudioObjectPropertyElementMaster
) )
@ -66,7 +66,7 @@ class VolumeViewController: NSCustomTouchBarItem {
var volume: Float32 = 0.5 var volume: Float32 = 0.5
var size: UInt32 = UInt32(MemoryLayout.size(ofValue: volume)) var size: UInt32 = UInt32(MemoryLayout.size(ofValue: volume))
var address: AudioObjectPropertyAddress = AudioObjectPropertyAddress() var address: AudioObjectPropertyAddress = AudioObjectPropertyAddress()
address.mSelector = AudioObjectPropertySelector(kAudioHardwareServiceDeviceProperty_VirtualMasterVolume) address.mSelector = AudioObjectPropertySelector(kAudioHardwareServiceDeviceProperty_VirtualMainVolume)
address.mScope = AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput) address.mScope = AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput)
address.mElement = AudioObjectPropertyElement(kAudioObjectPropertyElementMaster) address.mElement = AudioObjectPropertyElement(kAudioObjectPropertyElementMaster)
AudioObjectGetPropertyData(defaultDeviceID, &address, 0, nil, &size, &volume) AudioObjectGetPropertyData(defaultDeviceID, &address, 0, nil, &size, &volume)
@ -86,7 +86,7 @@ class VolumeViewController: NSCustomTouchBarItem {
var address: AudioObjectPropertyAddress = AudioObjectPropertyAddress() var address: AudioObjectPropertyAddress = AudioObjectPropertyAddress()
address.mScope = AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput) address.mScope = AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput)
address.mElement = AudioObjectPropertyElement(kAudioObjectPropertyElementMaster) address.mElement = AudioObjectPropertyElement(kAudioObjectPropertyElementMaster)
address.mSelector = AudioObjectPropertySelector(kAudioHardwareServiceDeviceProperty_VirtualMasterVolume) address.mSelector = AudioObjectPropertySelector(kAudioHardwareServiceDeviceProperty_VirtualMainVolume)
return AudioObjectSetPropertyData(defaultDeviceID, &address, 0, nil, size, &inputVolume) return AudioObjectSetPropertyData(defaultDeviceID, &address, 0, nil, size, &inputVolume)
} }

View File

@ -31,7 +31,7 @@ My idea is to create a platform for creating plugins to customize the TouchBar.
- Or via Homebrew `brew install --cask mtmr` - Or via Homebrew `brew install --cask mtmr`
- [Dario Prski](https://medium.com/@urdigitalpulse) has written a [fantastic article on medium](https://medium.com/@urdigitalpulse/customise-your-macbook-pro-touch-bar-966998e606b5) that goes into more detail on installing MTMR - [Dario Prski](https://medium.com/@urdigitalpulse) has written a [fantastic article on medium](https://medium.com/@urdigitalpulse/customise-your-macbook-pro-touch-bar-966998e606b5) that goes into more detail on installing MTMR
**On first install** you need to allow access for MTMR in Accessibility otherwise buttons like <kbd>Esc</kbd>, <kbd>Volume</kbd>, <kbd>Brightness</kbd> and other system keys won't work **On first install** you need to allow access for MTMR in Accessibility otherwise buttons like <kbd>Esc</kbd>, <kbd>Volume</kbd>, <kbd>Brightness</kbd> and other system keys won't work.
<p align="center"> <p align="center">
<img width="450" alt="screenshot 2019-02-24 at 23 19 20" src="https://user-images.githubusercontent.com/2198153/53307057-2b078200-388c-11e9-8212-8c2b1aff0aa6.png"> <img width="450" alt="screenshot 2019-02-24 at 23 19 20" src="https://user-images.githubusercontent.com/2198153/53307057-2b078200-388c-11e9-8212-8c2b1aff0aa6.png">
@ -51,7 +51,7 @@ My idea is to create a platform for creating plugins to customize the TouchBar.
## Customization ## Customization
MTMR preferences are stored under `~/Library/Application\ Support/MTMR/items.json`. MTMR preferences are stored in `~/Library/Application\ Support/MTMR/items.json`.
The pre-installed configuration contains less or more than you'll probably want, try to configure: The pre-installed configuration contains less or more than you'll probably want, try to configure:
@ -159,7 +159,7 @@ You may create as many `swipe` objects in the preset as you want.
} }
``` ```
> Note: appleScriptTitledButton can change its icon. To do it, you need to do the following things: > Note: You can change appleScriptTitledButton's icon by following these steps:
1. Declare dictionary of icons in `alternativeImages` field 1. Declare dictionary of icons in `alternativeImages` field
2. Make you script return array of two values - `{"TITLE", "IMAGE_LABEL"}` 2. Make you script return array of two values - `{"TITLE", "IMAGE_LABEL"}`
3. Make sure that your `IMAGE_LABEL` is declared in `alternativeImages` field 3. Make sure that your `IMAGE_LABEL` is declared in `alternativeImages` field
@ -187,10 +187,10 @@ Example:
``` ```
#### `shellScriptTitledButton` #### `shellScriptTitledButton`
> Note: script may return also colors using escape sequences (read more here https://misc.flogisoft.com/bash/tip_colors_and_formatting) > Note: script may also use escape sequences to return colors (read https://misc.flogisoft.com/bash/tip_colors_and_formatting for more information)
> Only "16 Colors" mode supported atm. If background color returned, button will pick it up as own background color. > "16 Colors" is the only mode supported presently. Buttons will set their own background color to the color returned.
Example of "CPU load" button which also changes color based on load value (Note: you can use native `cpu` plugin for that purpose which runs better): Example of "CPU load" button which also changes color based on load value (Note: The native `cpu` plugin runs runs better):
```js ```js
{ {
"type": "shellScriptTitledButton", "type": "shellScriptTitledButton",
@ -249,8 +249,8 @@ To close a group, use the button:
#### `cpu` #### `cpu`
> Shows current CPU load in percents, changes color based on load value. > Shows current CPU load in percent, changes color based on load value.
> Has lower power consumption and more stable in comparison to shell-based solution. > Has lower power consumption and higher stability than the shell-based solution.
```js ```js
{ {
@ -262,7 +262,7 @@ To close a group, use the button:
#### `timeButton` #### `timeButton`
> Attention! Works not all: https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations > NOTE: Some values don't work properly: https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations
> formatTemplate examples: https://www.datetimeformatter.com/how-to-format-date-time-in-swift/ > formatTemplate examples: https://www.datetimeformatter.com/how-to-format-date-time-in-swift/
@ -280,9 +280,9 @@ To close a group, use the button:
#### `weather` #### `weather`
> Provider: https://openweathermap.org \ > Provider: https://openweathermap.org \
> Note: you need to register on https://openweathermap.org to get your API key \ > Note: Register at https://openweathermap.org to get your API key \
> Note: you may need to wait for near 20 mins until your API key will be activated by Openweathermap \ > Note: Wait for 20 minutes or so for Openweathermap to activate your API key.\
> Note: you need to allow using "Location Services" in your Mac OS "Security & Privacy" settings for MTMR > Note: Enable MTMR in "Location Services" in the "Security & Privacy" System Preferences pane
```js ```js
"type": "weather", "type": "weather",
@ -295,7 +295,7 @@ To close a group, use the button:
#### `yandexWeather` (experimental) #### `yandexWeather` (experimental)
> Provider: https://yandex.ru/pogoda. One click to open up weather forecast in your browser. \ > Provider: https://yandex.ru/pogoda. One click to open up weather forecast in your browser. \
> Note: you need to allow using "Location Services" in your Mac OS "Security & Privacy" settings for MTMR > Note: Enable MTMR in "Location Services" in the "Security & Privacy" System Preferences pane
```js ```js
"type": "yandexWeather", "type": "yandexWeather",
@ -330,7 +330,7 @@ To close a group, use the button:
#### `pomodoro` #### `pomodoro`
> Pomodoro plugin. One click to start the work timer, longclick to start the rest timer. Click in progress for reset. > Pomodoro plugin. One tap starts the work timer, long-press to start the rest timer. Tap an in-progress timer to reset.
```js ```js
{ {
@ -342,7 +342,7 @@ To close a group, use the button:
#### `network` #### `network`
> Network plugin. The plugin to show usage a network > Network plugin. The plugin to show network usage
```js ```js
{ {
@ -488,6 +488,13 @@ by using background with color "#000000" and bordered == false you can create bu
} }
``` ```
- `matchAppId` displays the button only when active app's id matches given regexp
```json
"matchAppId": "Safari"
```
## Troubleshooting ## Troubleshooting
#### If you can't open preferences: #### If you can't open preferences: