From b34b2e26b7d0092ee8fab7b68fd48e76a9243c5b Mon Sep 17 00:00:00 2001 From: Qijia Liu Date: Fri, 14 Jun 2024 00:50:21 -0400 Subject: [PATCH] save as fcitx key string --- macosfrontend/keycode.cpp | 5 +-- macosfrontend/keycode.h | 5 +-- macosfrontend/macosfrontend-public.h | 2 ++ macosfrontend/macosfrontend.cpp | 22 +++++++++---- src/config/keycode.swift | 16 ++++++++++ src/config/keyrecorder.swift | 48 +++++++++++++++++----------- src/config/optionviews.swift | 12 +++++-- 7 files changed, 80 insertions(+), 30 deletions(-) create mode 100644 src/config/keycode.swift diff --git a/macosfrontend/keycode.cpp b/macosfrontend/keycode.cpp index 4b5dcd7..977665e 100644 --- a/macosfrontend/keycode.cpp +++ b/macosfrontend/keycode.cpp @@ -176,8 +176,9 @@ static struct { {OSX_VK_SHIFT_R, 54}, }; -fcitx::KeySym osx_unicode_to_fcitx_keysym(uint32_t unicode, uint16_t osxKeycode, - uint32_t osxModifiers) { +fcitx::KeySym osx_unicode_to_fcitx_keysym(uint32_t unicode, + uint32_t osxModifiers, + uint16_t osxKeycode) { for (const auto &pair : sym_mappings) { if (pair.osxKeycode == osxKeycode) { return pair.sym; diff --git a/macosfrontend/keycode.h b/macosfrontend/keycode.h index 46f0efd..8fa4a9d 100644 --- a/macosfrontend/keycode.h +++ b/macosfrontend/keycode.h @@ -246,8 +246,9 @@ #define OSX_MODIFIER_FUNCTION (1 << 23) // clang-format on -fcitx::KeySym osx_unicode_to_fcitx_keysym(uint32_t unicode, uint16_t osxKeycode, - uint32_t osxModifiers); +fcitx::KeySym osx_unicode_to_fcitx_keysym(uint32_t unicode, + uint32_t osxModifiers, + uint16_t osxKeycode); uint16_t osx_keycode_to_fcitx_keycode(uint16_t osxKeycode); fcitx::KeyStates osx_modifiers_to_fcitx_keystates(uint32_t osxModifiers); diff --git a/macosfrontend/macosfrontend-public.h b/macosfrontend/macosfrontend-public.h index f8af660..96fc3ea 100644 --- a/macosfrontend/macosfrontend-public.h +++ b/macosfrontend/macosfrontend-public.h @@ -6,6 +6,8 @@ // Though being UInt, 32b is enough for modifiers std::string process_key(ICUUID uuid, uint32_t unicode, uint32_t osxModifiers, uint16_t osxKeycode, bool isRelease) noexcept; +std::string osx_key_to_fcitx_string(uint32_t unicode, uint32_t modifiers, + uint16_t code) noexcept; ICUUID create_input_context(const char *appId, id client) noexcept; void destroy_input_context(ICUUID uuid) noexcept; diff --git a/macosfrontend/macosfrontend.cpp b/macosfrontend/macosfrontend.cpp index 9d2dbf6..ea9dd7f 100644 --- a/macosfrontend/macosfrontend.cpp +++ b/macosfrontend/macosfrontend.cpp @@ -190,14 +190,24 @@ MacosInputContext::getCursorCoordinates(bool followCursor) { } // namespace fcitx -std::string process_key(ICUUID uuid, uint32_t unicode, uint32_t osxModifiers, - uint16_t osxKeycode, bool isRelease) noexcept { - const fcitx::Key parsedKey{ - osx_unicode_to_fcitx_keysym(unicode, osxKeycode, osxModifiers), - osx_modifiers_to_fcitx_keystates(osxModifiers), - osx_keycode_to_fcitx_keycode(osxKeycode), +fcitx::Key osx_key_to_fcitx_key(uint32_t unicode, uint32_t modifiers, + uint16_t code) noexcept { + return fcitx::Key{ + osx_unicode_to_fcitx_keysym(unicode, modifiers, code), + osx_modifiers_to_fcitx_keystates(modifiers), + osx_keycode_to_fcitx_keycode(code), }; +} +std::string osx_key_to_fcitx_string(uint32_t unicode, uint32_t modifiers, + uint16_t code) noexcept { + return osx_key_to_fcitx_key(unicode, modifiers, code).toString(); +} + +std::string process_key(ICUUID uuid, uint32_t unicode, uint32_t osxModifiers, + uint16_t osxKeycode, bool isRelease) noexcept { + const fcitx::Key parsedKey = + osx_key_to_fcitx_key(unicode, osxModifiers, osxKeycode); return with_fcitx([=](Fcitx &fcitx) { auto that = dynamic_cast(fcitx.frontend()); return that->keyEvent(uuid, parsedKey, isRelease); diff --git a/src/config/keycode.swift b/src/config/keycode.swift new file mode 100644 index 0000000..88730cd --- /dev/null +++ b/src/config/keycode.swift @@ -0,0 +1,16 @@ +import Cocoa +import CxxFrontend + +private func keyToUnicode(_ key: String) -> UInt32 { + if key.isEmpty { + return 0 + } + let usv = key.unicodeScalars + return usv[usv.startIndex].value +} + +func macKeyToFcitxString(_ key: String, _ modifier: NSEvent.ModifierFlags, _ code: UInt16) -> String +{ + let unicode = keyToUnicode(key) + return String(osx_key_to_fcitx_string(unicode, UInt32(modifier.rawValue), code)) +} diff --git a/src/config/keyrecorder.swift b/src/config/keyrecorder.swift index db9f592..90005c9 100644 --- a/src/config/keyrecorder.swift +++ b/src/config/keyrecorder.swift @@ -2,6 +2,9 @@ import SwiftUI struct RecordingOverlay: NSViewRepresentable { @Binding var recordedShortcut: String + @Binding var recordedKey: String + @Binding var recordedModifiers: NSEvent.ModifierFlags + @Binding var recordedCode: UInt16 func makeNSView(context: Context) -> NSView { let view = KeyCaptureView() @@ -56,12 +59,12 @@ struct RecordingOverlay: NSViewRepresentable { 0x67: "F11", 0x6f: "F12", // cursor - 0x7e: "↑", - 0x7d: "↓", - 0x7b: "←", - 0x7c: "→", - 0x74: "⇡", - 0x79: "⇣", + 0x7e: "▲", + 0x7d: "▼", + 0x7b: "◀", + 0x7c: "▶", + 0x74: "⭡", + 0x79: "⭣", 0x73: "⇱", 0x77: "⇲", // pc keyboard @@ -72,33 +75,42 @@ struct RecordingOverlay: NSViewRepresentable { ] private var parent: RecordingOverlay private var key = "" - private var modifier = NSEvent.ModifierFlags() + private var keySym = "" + private var modifiers = NSEvent.ModifierFlags() + private var code: UInt16 = 0 init(_ parent: RecordingOverlay) { self.parent = parent } - func handleKeyCapture(key: String, code: Int) { - self.key = Coordinator.codeMap[code] ?? key - + func handleKeyCapture(key: String, code: UInt16) { + self.key = key + self.keySym = Coordinator.codeMap[Int(code)] ?? key + self.code = code updateParent() } - func handleKeyCapture(modifier: NSEvent.ModifierFlags) { - if modifier.isDisjoint(with: [.command, .option, .control, .shift]) { - self.modifier = NSEvent.ModifierFlags() + func handleKeyCapture(modifiers: NSEvent.ModifierFlags, code: UInt16) { + if modifiers.isDisjoint(with: [.command, .option, .control, .shift]) { + self.modifiers = NSEvent.ModifierFlags() + self.code = 0 } else { - if modifier.isSuperset(of: self.modifier) { + if modifiers.isSuperset(of: self.modifiers) { // Don't change on release - self.modifier = modifier + self.modifiers = modifiers self.key = "" + self.keySym = "" + self.code = code } updateParent() } } private func updateParent() { - parent.recordedShortcut = modifier.description + key + parent.recordedKey = key + parent.recordedModifiers = modifiers + parent.recordedCode = code + parent.recordedShortcut = modifiers.description + keySym } } } @@ -113,11 +125,11 @@ class KeyCaptureView: NSView { override func keyDown(with event: NSEvent) { coordinator?.handleKeyCapture( - key: event.charactersIgnoringModifiers ?? "", code: Int(event.keyCode)) + key: event.charactersIgnoringModifiers ?? "", code: event.keyCode) } override func flagsChanged(with event: NSEvent) { - coordinator?.handleKeyCapture(modifier: event.modifierFlags) + coordinator?.handleKeyCapture(modifiers: event.modifierFlags, code: event.keyCode) } } diff --git a/src/config/optionviews.swift b/src/config/optionviews.swift index 7624567..35c2883 100644 --- a/src/config/optionviews.swift +++ b/src/config/optionviews.swift @@ -26,7 +26,10 @@ struct KeyOptionView: OptionView { let overrideLabel: String? = nil @ObservedObject var model: KeyOption @State private var showRecorder = false - @State private var recordedShortcut: String = "" + @State private var recordedShortcut = "" + @State private var recordedKey = "" + @State private var recordedModifiers = NSEvent.ModifierFlags() + @State private var recordedCode: UInt16 = 0 var body: some View { Button { @@ -36,7 +39,11 @@ struct KeyOptionView: OptionView { }.sheet(isPresented: $showRecorder) { VStack { Text(recordedShortcut) - .background(RecordingOverlay(recordedShortcut: $recordedShortcut)) + .background( + RecordingOverlay( + recordedShortcut: $recordedShortcut, recordedKey: $recordedKey, + recordedModifiers: $recordedModifiers, recordedCode: $recordedCode) + ) .frame(minWidth: 200, minHeight: 50) HStack { Button { @@ -45,6 +52,7 @@ struct KeyOptionView: OptionView { Text("Cancel") } Button { + model.value = macKeyToFcitxString(recordedKey, recordedModifiers, recordedCode) showRecorder = false } label: { Text("OK")