Skip to content

Commit 036d54e

Browse files
committed
Debug mode
1 parent 020f3bc commit 036d54e

2 files changed

Lines changed: 73 additions & 24 deletions

File tree

Wave/AppState.swift

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -202,16 +202,26 @@ final class AppState {
202202
microphoneManager.applySelection(uid: selectedMicUID)
203203
}
204204

205-
// Default shortcut: Fn
205+
// Default shortcut: Fn (debug uses Right Shift to avoid conflicting with prod)
206206
if hotkeyKeyCode == 0 && hotkeyModifiers == 0 {
207+
#if DEBUG
208+
hotkeyKeyCode = 60 // kVK_RightShift
209+
hotkeyModifiers = CGEventFlags.maskShift.rawValue
210+
#else
207211
hotkeyKeyCode = 63 // kVK_Function
208212
hotkeyModifiers = CGEventFlags.maskSecondaryFn.rawValue
213+
#endif
209214
}
210215

211-
// Default AI shortcut: Right Option
216+
// Default AI shortcut: Right Option (debug uses Right Control)
212217
if aiModeKeyCode == 0 && aiModeModifiers == 0 {
218+
#if DEBUG
219+
aiModeKeyCode = 62 // kVK_RightControl
220+
aiModeModifiers = CGEventFlags.maskControl.rawValue
221+
#else
213222
aiModeKeyCode = 61 // kVK_RightOption
214223
aiModeModifiers = CGEventFlags.maskAlternate.rawValue
224+
#endif
215225
}
216226

217227
if !isOnboardingComplete {
@@ -290,18 +300,21 @@ final class AppState {
290300
DispatchQueue.main.async {
291301
guard let self = self else { return }
292302
self.isAIMode = true
293-
self.selectedContext = PasteService.getSelectedText()
294-
switch self.dictationMode {
295-
case .pushToTalk:
296-
if self.status == .idle {
297-
self.isKeyHeld = true
298-
Task { await self.startDictation() }
299-
}
300-
case .toggle:
301-
if self.status == .idle {
302-
Task { await self.startDictation() }
303-
} else if self.status == .recording {
304-
Task { await self.stopDictationAndPaste() }
303+
Task { @MainActor [weak self] in
304+
guard let self = self else { return }
305+
self.selectedContext = await PasteService.getSelectedText()
306+
switch self.dictationMode {
307+
case .pushToTalk:
308+
if self.status == .idle {
309+
self.isKeyHeld = true
310+
await self.startDictation()
311+
}
312+
case .toggle:
313+
if self.status == .idle {
314+
await self.startDictation()
315+
} else if self.status == .recording {
316+
await self.stopDictationAndPaste()
317+
}
305318
}
306319
}
307320
}

Wave/Services/PasteService.swift

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import AppKit
2-
import ApplicationServices
32
import Carbon.HIToolbox
43

54
struct PasteService {
@@ -49,14 +48,51 @@ struct PasteService {
4948
}
5049
}
5150

52-
static func getSelectedText() -> String? {
53-
let systemWide = AXUIElementCreateSystemWide()
54-
var focusedElement: CFTypeRef?
55-
guard AXUIElementCopyAttributeValue(systemWide, kAXFocusedUIElementAttribute as CFString, &focusedElement) == .success,
56-
let element = focusedElement else { return nil }
57-
var value: CFTypeRef?
58-
guard AXUIElementCopyAttributeValue(element as! AXUIElement, kAXSelectedTextAttribute as CFString, &value) == .success,
59-
let text = value as? String, !text.isEmpty else { return nil }
60-
return text
51+
@MainActor
52+
static func getSelectedText() async -> String? {
53+
let pasteboard = NSPasteboard.general
54+
55+
// Save current clipboard state
56+
let savedItems = pasteboard.pasteboardItems?.compactMap { item -> [NSPasteboard.PasteboardType: Data]? in
57+
var dataMap: [NSPasteboard.PasteboardType: Data] = [:]
58+
for type in item.types {
59+
if let data = item.data(forType: type) { dataMap[type] = data }
60+
}
61+
return dataMap.isEmpty ? nil : dataMap
62+
}
63+
let savedChangeCount = pasteboard.changeCount
64+
65+
// Simulate Cmd+C — works in every app (browsers, Electron, Terminal)
66+
let src = CGEventSource(stateID: .hidSystemState)
67+
let cKey = CGKeyCode(kVK_ANSI_C)
68+
let down = CGEvent(keyboardEventSource: src, virtualKey: cKey, keyDown: true)
69+
let up = CGEvent(keyboardEventSource: src, virtualKey: cKey, keyDown: false)
70+
down?.flags = .maskCommand
71+
up?.flags = .maskCommand
72+
down?.post(tap: .cghidEventTap)
73+
up?.post(tap: .cghidEventTap)
74+
75+
// Suspend (not block) until clipboard is updated
76+
try? await Task.sleep(for: .milliseconds(80))
77+
78+
// Only read if the clipboard actually changed (i.e. something was selected)
79+
let text: String?
80+
if pasteboard.changeCount != savedChangeCount {
81+
text = pasteboard.string(forType: .string)
82+
} else {
83+
text = nil
84+
}
85+
86+
// Restore original clipboard
87+
pasteboard.clearContents()
88+
if let items = savedItems, !items.isEmpty {
89+
for dataMap in items {
90+
let newItem = NSPasteboardItem()
91+
for (type, data) in dataMap { newItem.setData(data, forType: type) }
92+
pasteboard.writeObjects([newItem])
93+
}
94+
}
95+
96+
return text?.isEmpty == false ? text : nil
6197
}
6298
}

0 commit comments

Comments
 (0)