Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Macros #493

Merged
merged 16 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Combine
import Cocoa
import MachPort

final class ApplicationTriggerController {
private let commandRunner: CommandRunning
Expand Down Expand Up @@ -94,19 +95,24 @@ final class ApplicationTriggerController {

private func runCommands(in workflow: Workflow) {
let commands = workflow.commands.filter(\.isEnabled)
guard let machPortEvent = MachPortEvent.empty() else { return }
switch workflow.execution {
case .concurrent:
commandRunner.concurrentRun(
commands,
checkCancellation: true,
resolveUserEnvironment: workflow.resolveUserEnvironment(),
shortcut: .empty(),
machPortEvent: machPortEvent,
repeatingEvent: false
)
case .serial:
commandRunner.serialRun(
commands,
checkCancellation: true,
resolveUserEnvironment: workflow.resolveUserEnvironment(),
shortcut: .empty(),
machPortEvent: machPortEvent,
repeatingEvent: false
)
}
Expand Down
13 changes: 10 additions & 3 deletions App/Sources/Core/Core.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,19 @@ final class Core {
recorderStore: recorderStore,
shortcutStore: shortcutStore,
scriptCommandRunner: scriptCommandRunner)
lazy private(set) var macroCoordinator = MacroCoordinator()
lazy private(set) var groupStore = GroupStore()
lazy private(set) var keyCodeStore = KeyCodesStore(InputSourceController())
lazy private(set) var workflowRunner = WorkflowRunner(commandRunner: commandRunner,
store: keyCodeStore, notifications: notifications)
lazy private(set) var notifications = MachPortUINotifications(keyboardShortcutsController: keyboardShortcutsController)
lazy private(set) var machPortCoordinator = MachPortCoordinator(store: keyboardCommandRunner.store,
commandRunner: commandRunner,
keyboardCommandRunner: keyboardCommandRunner,
keyboardShortcutsController: keyboardShortcutsController,
mode: .intercept)
macroCoordinator: macroCoordinator,
mode: .intercept,
notifications: notifications,
workflowRunner: workflowRunner)
lazy private(set) var engine = KeyboardCowboyEngine(
contentStore,
commandRunner: commandRunner,
Expand All @@ -97,14 +103,15 @@ final class Core {
// MARK: - Runners
lazy private(set) var commandRunner = CommandRunner(
applicationStore: ApplicationStore.shared,
builtInCommandRunner: BuiltInCommandRunner(configurationStore: configurationStore),
builtInCommandRunner: BuiltInCommandRunner(configurationStore: configurationStore, macroRunner: macroRunner),
scriptCommandRunner: scriptCommandRunner,
keyboardCommandRunner: keyboardCommandRunner,
uiElementCommandRunner: uiElementCommandRunner
)
lazy private(set) var keyboardCommandRunner = KeyboardCommandRunner(store: keyCodeStore)
lazy private(set) var uiElementCommandRunner = UIElementCommandRunner()
lazy private(set) var scriptCommandRunner = ScriptCommandRunner(workspace: .shared)
lazy private(set) var macroRunner = MacroRunner(coordinator: macroCoordinator)

// MARK: - Controllers

Expand Down
12 changes: 12 additions & 0 deletions App/Sources/Core/KeyboardCowboy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct KeyboardCowboy: App {

PermissionsWindow()
PermissionsScene(onAction: handlePermissionAction(_:))
ReleaseNotesScene()

NewCommandWindow(contentStore: core.contentStore,
uiElementCaptureStore: core.uiElementCaptureStore,
Expand Down Expand Up @@ -91,6 +92,11 @@ struct KeyboardCowboy: App {
handleAppScene(.permissions)
return
}

if AppStorageContainer.shared.releaseNotes < KeyboardCowboy.marektingVersion {
openWindow(id: KeyboardCowboy.releaseNotesWindowIdentifier)
}

}
case .openMainWindow:
handleAppScene(.mainWindow)
Expand Down Expand Up @@ -133,3 +139,9 @@ struct KeyboardCowboy: App {
}
}
}

private extension String {
static func < (lhs: String, rhs: String) -> Bool {
return lhs.compare(rhs, options: .numeric) == .orderedAscending
}
}
30 changes: 20 additions & 10 deletions App/Sources/Core/Models/Commands/BuildInCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,44 @@ struct BuiltInCommand: MetaDataProviding {
case toggle
}

case macro(MacroAction)
case userMode(UserMode, Action)

var id: String {
switch self {
case .userMode(let id, let action):
case .macro(let macro):
return macro.id
case .userMode(let id, let action):
return switch action {
case .enable: "enable-\(id)"
case .disable: "disable-\(id)"
case .toggle: "toggle-\(id)"
case .enable: "enable-\(id)"
case .disable: "disable-\(id)"
case .toggle: "toggle-\(id)"
}
}
}

var userModeId: UserMode.ID {
switch self {
case .macro(let action):
return action.id
case .userMode(let model, _):
return model.id
return model.id
}
}

public var displayValue: String {
switch self {
case .macro(let action):
switch action.kind {
case .remove: "Remove Macro"
case .record: "Record Macro"
}
case .userMode(_, let action):
return switch action {
case .enable: "Enable User Mode"
case .disable: "Disable User Mode"
case .toggle: "Toggle User Mode"
}
switch action {
case .enable: "Enable User Mode"
case .disable: "Disable User Mode"
case .toggle: "Toggle User Mode"
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions App/Sources/Core/Models/KeyboardCowboyMode.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
enum KeyboardCowboyMode {
case intercept
case recordKeystroke
case recordMacro
case captureUIElement
case disabled
}
24 changes: 24 additions & 0 deletions App/Sources/Core/Models/MacroAction.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Foundation

struct MacroAction: Identifiable, Codable, Hashable, Sendable {
let id: String
let kind: Kind

enum Kind: Codable {
case record
case remove
}

init(id: String, kind: Kind) {
self.id = id
self.kind = kind
}

init(_ kind: Kind, id: String = UUID().uuidString) {
self.id = id
self.kind = kind
}

static var record: MacroAction { MacroAction(.record) }
static var remove: MacroAction { MacroAction(.remove) }
}
20 changes: 14 additions & 6 deletions App/Sources/Core/Runners/BuiltInCommandRunner.swift
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
import Foundation
import MachPort

final class BuiltInCommandRunner {
let configurationStore: ConfigurationStore
let macroRunner: MacroRunner

init(configurationStore: ConfigurationStore) {
init(configurationStore: ConfigurationStore,
macroRunner: MacroRunner) {
self.configurationStore = configurationStore
self.macroRunner = macroRunner
}

func run(_ command: BuiltInCommand) async throws -> String {
func run(_ command: BuiltInCommand,
shortcut: KeyShortcut,
machPortEvent: MachPortEvent) async throws -> String {
return switch command.kind {
case .userMode(let model, let action): try await UserModesRunner(
configurationStore: configurationStore
)
.run(model, builtInCommand: command, action: action)
case .macro(let action):
await macroRunner
.run(action, shortcut: shortcut, machPortEvent: machPortEvent)
case .userMode(let model, let action):
try await UserModesRunner(configurationStore: configurationStore)
.run(model, builtInCommand: command, action: action)
}
}
}
37 changes: 25 additions & 12 deletions App/Sources/Core/Runners/CommandRunner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import MachPort

protocol CommandRunning {
func serialRun(_ commands: [Command], checkCancellation: Bool,
resolveUserEnvironment: Bool, repeatingEvent: Bool)
resolveUserEnvironment: Bool, shortcut: KeyShortcut, machPortEvent: MachPortEvent,
repeatingEvent: Bool)
func concurrentRun(_ commands: [Command], checkCancellation: Bool,
resolveUserEnvironment: Bool, repeatingEvent: Bool)
resolveUserEnvironment: Bool,
shortcut: KeyShortcut, machPortEvent: MachPortEvent,
repeatingEvent: Bool)
}

final class CommandRunner: CommandRunning, @unchecked Sendable {
Expand Down Expand Up @@ -110,9 +113,9 @@ final class CommandRunner: CommandRunning, @unchecked Sendable {
}
}

func serialRun(_ commands: [Command],
checkCancellation: Bool,
resolveUserEnvironment: Bool,
func serialRun(_ commands: [Command], checkCancellation: Bool,
resolveUserEnvironment: Bool,
shortcut: KeyShortcut, machPortEvent: MachPortEvent,
repeatingEvent: Bool) {
let originalPasteboardContents: String? = commands.shouldRestorePasteboard
? NSPasteboard.general.string(forType: .string)
Expand All @@ -133,7 +136,8 @@ final class CommandRunner: CommandRunning, @unchecked Sendable {
for command in commands {
if checkCancellation { try Task.checkCancellation() }
do {
try await self.run(command, snapshot: snapshot, repeatingEvent: repeatingEvent)
try await self.run(command, snapshot: snapshot, shortcut: shortcut,
machPortEvent: machPortEvent, repeatingEvent: repeatingEvent)
} catch { }
if let delay = command.delay {
try await Task.sleep(for: .milliseconds(delay))
Expand All @@ -152,7 +156,9 @@ final class CommandRunner: CommandRunning, @unchecked Sendable {
}

func concurrentRun(_ commands: [Command], checkCancellation: Bool,
resolveUserEnvironment: Bool, repeatingEvent: Bool) {
resolveUserEnvironment: Bool,
shortcut: KeyShortcut, machPortEvent: MachPortEvent,
repeatingEvent: Bool) {
let originalPasteboardContents: String? = commands.shouldRestorePasteboard
? NSPasteboard.general.string(forType: .string)
: nil
Expand All @@ -161,8 +167,7 @@ final class CommandRunner: CommandRunning, @unchecked Sendable {
guard let self else { return }
let shouldDismissMissionControl = commands.contains(where: {
switch $0 {
case .builtIn: false
default: true
case .builtIn: false default: true
}
})

Expand All @@ -172,7 +177,8 @@ final class CommandRunner: CommandRunning, @unchecked Sendable {
for command in commands {
do {
if checkCancellation { try Task.checkCancellation() }
try await self.run(command, snapshot: snapshot, repeatingEvent: repeatingEvent)
try await self.run(command, snapshot: snapshot, shortcut: shortcut,
machPortEvent: machPortEvent, repeatingEvent: repeatingEvent)
} catch { }
}

Expand All @@ -186,7 +192,10 @@ final class CommandRunner: CommandRunning, @unchecked Sendable {
}
}

func run(_ command: Command, snapshot: UserSpace.Snapshot, repeatingEvent: Bool) async throws {
func run(_ command: Command, snapshot: UserSpace.Snapshot,
shortcut: KeyShortcut,
machPortEvent: MachPortEvent,
repeatingEvent: Bool) async throws {
do {
let id = UUID().uuidString
if command.notification {
Expand All @@ -200,7 +209,11 @@ final class CommandRunner: CommandRunning, @unchecked Sendable {
try await runners.application.run(applicationCommand)
output = command.name
case .builtIn(let builtInCommand):
output = try await runners.builtIn.run(builtInCommand)
output = try await runners.builtIn.run(
builtInCommand,
shortcut: shortcut,
machPortEvent: machPortEvent
)
case .keyboard(let keyboardCommand):
try runners.keyboard.run(keyboardCommand.keyboardShortcuts,
type: .keyDown,
Expand Down
Loading
Loading