Skip to content

Commit

Permalink
Merge pull request #7 from sieren/add-customizable-hotkey
Browse files Browse the repository at this point in the history
Add Customizable Hotkeys
  • Loading branch information
sieren authored Oct 6, 2023
2 parents 97b997e + 65b5476 commit b3565b9
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 25 deletions.
38 changes: 23 additions & 15 deletions WidgetToggler/WidgetToggler.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
objects = {

/* Begin PBXBuildFile section */
693C9CB32ABEE67200A2DB62 /* HotKey in Frameworks */ = {isa = PBXBuildFile; productRef = 693C9CB22ABEE67200A2DB62 /* HotKey */; };
691985502ACFEE87007E88A9 /* KeyboardShortcuts in Frameworks */ = {isa = PBXBuildFile; productRef = 6919854F2ACFEE87007E88A9 /* KeyboardShortcuts */; };
691985522ACFEEA5007E88A9 /* ShortcutHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 691985512ACFEEA5007E88A9 /* ShortcutHelpers.swift */; };
691985542ACFEF23007E88A9 /* SettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 691985532ACFEF23007E88A9 /* SettingsScreen.swift */; };
693C9D072ABEFDB400A2DB62 /* FocusFilters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693C9CB42ABEEC3500A2DB62 /* FocusFilters.swift */; };
69A392FB2AAE152B007B9101 /* WidgetTogglerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69A392FA2AAE152B007B9101 /* WidgetTogglerApp.swift */; };
69A392FF2AAE152C007B9101 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 69A392FE2AAE152C007B9101 /* Assets.xcassets */; };
Expand Down Expand Up @@ -42,6 +44,8 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
691985512ACFEEA5007E88A9 /* ShortcutHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutHelpers.swift; sourceTree = "<group>"; };
691985532ACFEF23007E88A9 /* SettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreen.swift; sourceTree = "<group>"; };
693C9CB42ABEEC3500A2DB62 /* FocusFilters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FocusFilters.swift; sourceTree = "<group>"; };
693C9CBC2ABEECF800A2DB62 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; };
693C9D062ABEFCE400A2DB62 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
Expand All @@ -60,8 +64,8 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
693C9CB32ABEE67200A2DB62 /* HotKey in Frameworks */,
69ED90242AAF752600137DA5 /* LaunchAtLogin in Frameworks */,
691985502ACFEE87007E88A9 /* KeyboardShortcuts in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -108,6 +112,8 @@
693C9D062ABEFCE400A2DB62 /* Info.plist */,
693C9CF02ABEF0C000A2DB62 /* Shared */,
69A392FA2AAE152B007B9101 /* WidgetTogglerApp.swift */,
691985532ACFEF23007E88A9 /* SettingsScreen.swift */,
691985512ACFEEA5007E88A9 /* ShortcutHelpers.swift */,
693C9CB42ABEEC3500A2DB62 /* FocusFilters.swift */,
69ED90252AAF788A00137DA5 /* Bundle.swift */,
69A392FE2AAE152C007B9101 /* Assets.xcassets */,
Expand Down Expand Up @@ -145,7 +151,7 @@
name = WidgetToggler;
packageProductDependencies = (
69ED90232AAF752600137DA5 /* LaunchAtLogin */,
693C9CB22ABEE67200A2DB62 /* HotKey */,
6919854F2ACFEE87007E88A9 /* KeyboardShortcuts */,
);
productName = WidgetToggler;
productReference = 69A392F72AAE152B007B9101 /* WidgetToggler.app */;
Expand Down Expand Up @@ -177,7 +183,7 @@
mainGroup = 69A392EE2AAE152B007B9101;
packageReferences = (
69ED90222AAF752600137DA5 /* XCRemoteSwiftPackageReference "LaunchAtLogin-Modern" */,
693C9CB12ABEE67200A2DB62 /* XCRemoteSwiftPackageReference "HotKey" */,
6919854E2ACFEE87007E88A9 /* XCRemoteSwiftPackageReference "KeyboardShortcuts" */,
);
productRefGroup = 69A392F82AAE152B007B9101 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -206,10 +212,12 @@
buildActionMask = 2147483647;
files = (
69B7C75D2AAEFFD800804939 /* UserDefaults.swift in Sources */,
691985542ACFEF23007E88A9 /* SettingsScreen.swift in Sources */,
69ED90262AAF788A00137DA5 /* Bundle.swift in Sources */,
69A3930A2AAE1A80007B9101 /* WidgetsPrefs.swift in Sources */,
693C9D072ABEFDB400A2DB62 /* FocusFilters.swift in Sources */,
69A392FB2AAE152B007B9101 /* WidgetTogglerApp.swift in Sources */,
691985522ACFEEA5007E88A9 /* ShortcutHelpers.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -343,7 +351,7 @@
CODE_SIGN_ENTITLEMENTS = WidgetToggler/WidgetToggler.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2;
CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_ASSET_PATHS = "\"WidgetToggler/Preview Content\"";
DEVELOPMENT_TEAM = VEESE9857L;
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -357,7 +365,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.1;
MARKETING_VERSION = 1.2;
PRODUCT_BUNDLE_IDENTIFIER = com.sieren.WidgetToggler;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -374,7 +382,7 @@
CODE_SIGN_ENTITLEMENTS = WidgetToggler/WidgetToggler.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2;
CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_ASSET_PATHS = "\"WidgetToggler/Preview Content\"";
DEVELOPMENT_TEAM = VEESE9857L;
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -388,7 +396,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.1;
MARKETING_VERSION = 1.2;
PRODUCT_BUNDLE_IDENTIFIER = com.sieren.WidgetToggler;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand Down Expand Up @@ -420,12 +428,12 @@
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
693C9CB12ABEE67200A2DB62 /* XCRemoteSwiftPackageReference "HotKey" */ = {
6919854E2ACFEE87007E88A9 /* XCRemoteSwiftPackageReference "KeyboardShortcuts" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/soffes/HotKey.git";
repositoryURL = "https://github.com/sindresorhus/KeyboardShortcuts";
requirement = {
branch = main;
kind = branch;
kind = upToNextMajorVersion;
minimumVersion = 1.15.0;
};
};
69ED90222AAF752600137DA5 /* XCRemoteSwiftPackageReference "LaunchAtLogin-Modern" */ = {
Expand All @@ -439,10 +447,10 @@
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
693C9CB22ABEE67200A2DB62 /* HotKey */ = {
6919854F2ACFEE87007E88A9 /* KeyboardShortcuts */ = {
isa = XCSwiftPackageProductDependency;
package = 693C9CB12ABEE67200A2DB62 /* XCRemoteSwiftPackageReference "HotKey" */;
productName = HotKey;
package = 6919854E2ACFEE87007E88A9 /* XCRemoteSwiftPackageReference "KeyboardShortcuts" */;
productName = KeyboardShortcuts;
};
69ED90232AAF752600137DA5 /* LaunchAtLogin */ = {
isa = XCSwiftPackageProductDependency;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"pins" : [
{
"identity" : "hotkey",
"identity" : "keyboardshortcuts",
"kind" : "remoteSourceControl",
"location" : "https://github.com/soffes/HotKey.git",
"location" : "https://github.com/sindresorhus/KeyboardShortcuts",
"state" : {
"branch" : "main",
"revision" : "4d02d80de143d69b7eeb5962729591a157a57ede"
"revision" : "ac302e21da5883f4bd0490cbd0cb710b08740500",
"version" : "1.15.0"
}
},
{
Expand Down
Binary file not shown.
24 changes: 24 additions & 0 deletions WidgetToggler/WidgetToggler/SettingsScreen.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) 2023 Matthias Frick. All rights reserved.

import Foundation
import SwiftUI

import KeyboardShortcuts

struct SettingsScreen: View {
@Environment(\.dismiss) var dismiss

var body: some View {
VStack(alignment: .leading) {
Spacer()
Text("Set a global HotKey to toggle Widgets.")
Form {
KeyboardShortcuts.Recorder("HotKey:", name: .toggleWidgetMode)
}
Text("Requires restarting WidgetToggler to show in the UI.")
Spacer()
}
.frame(minWidth: 200)
.padding(50)
}
}
92 changes: 92 additions & 0 deletions WidgetToggler/WidgetToggler/ShortcutHelpers.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright (c) 2023 Matthias Frick. All rights reserved.

import Carbon
import Foundation
import SwiftUI

import KeyboardShortcuts

extension KeyboardShortcuts.Name {
static let toggleWidgetMode = Self(
"ToggleWidgetMode",
default: .init(
.w,
modifiers: [.command, .control]
)
)
}

extension View {
public func keyboardShortcut(_ shortcut: KeyboardShortcuts.Name) -> some View {
if let shortcut = shortcut.shortcut {
if let keyEquivalent = shortcut.toKeyEquivalent() {
return AnyView(self.keyboardShortcut(keyEquivalent, modifiers: shortcut.toEventModifiers()))
}
}

return AnyView(self)
}
}

extension KeyboardShortcuts.Shortcut {

func toKeyEquivalent() -> KeyEquivalent? {
let carbonKeyCode = UInt16(self.carbonKeyCode)
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, carbonKeyCode, UInt16(kUCKeyActionDown),
modifierKeys, keyboardType, UInt32(kUCKeyTranslateNoDeadKeysMask),
&deadKeys, maxNameLength, &nameLength, &nameBuffer)
}
guard osStatus == noErr else {
NSLog("Code: 0x%04X Status: %+i", carbonKeyCode, osStatus);
return nil
}

return KeyEquivalent(Character(String(utf16CodeUnits: nameBuffer, count: nameLength)))
}

func toEventModifiers() -> SwiftUI.EventModifiers {
var modifiers: SwiftUI.EventModifiers = []

if self.modifiers.contains(NSEvent.ModifierFlags.command) {
modifiers.update(with: EventModifiers.command)
}

if self.modifiers.contains(NSEvent.ModifierFlags.control) {
modifiers.update(with: EventModifiers.control)
}

if self.modifiers.contains(NSEvent.ModifierFlags.option) {
modifiers.update(with: EventModifiers.option)
}

if self.modifiers.contains(NSEvent.ModifierFlags.shift) {
modifiers.update(with: EventModifiers.shift)
}

if self.modifiers.contains(NSEvent.ModifierFlags.capsLock) {
modifiers.update(with: EventModifiers.capsLock)
}

if self.modifiers.contains(NSEvent.ModifierFlags.numericPad) {
modifiers.update(with: EventModifiers.numericPad)
}

return modifiers
}

}
18 changes: 12 additions & 6 deletions WidgetToggler/WidgetToggler/WidgetTogglerApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,24 @@

import SwiftUI

import HotKey
import KeyboardShortcuts
import LaunchAtLogin

@main
struct WidgetTogglerApp: App {
@State var widgetsPrefs: WidgetPreferences
private let hotKey: HotKey

public init() {
widgetsPrefs = WidgetPreferences.shared
hotKey = HotKey(keyCombo: KeyCombo(key: .w, modifiers: [.command, .control]))
hotKey.keyDownHandler = { [self] in
KeyboardShortcuts.onKeyUp(for: .toggleWidgetMode) { [self] in
widgetsPrefs.toggleWidgets()
}
}

var body: some Scene {
Settings {
SettingsScreen()
}
MenuBarExtra(
"WidgetToggler",
systemImage: widgetsPrefs.hideWidgets ? "rectangle.on.rectangle.slash" : "rectangle.inset.filled.on.rectangle"
Expand All @@ -28,10 +29,15 @@ struct WidgetTogglerApp: App {
widgetsPrefs.toggleWidgets()
},
label: {
Text(widgetsPrefs.hideWidgets ? "Show Widgets" : "Hide Widgets")
HStack {
Text(widgetsPrefs.hideWidgets ? "Show Widgets" : "Hide Widgets")
}
}
).keyboardShortcut(KeyEquivalent("w"), modifiers: [.control, .command])
).keyboardShortcut(.toggleWidgetMode)
Divider()
SettingsLink(label: {
Text("Settings")
})
LaunchAtLogin.Toggle()
Divider()
Button(
Expand Down

0 comments on commit b3565b9

Please sign in to comment.