Clipy/Magnet

add a NSMenuItem.keyEquivalent compatible string transformation

DivineDominion opened this issue · 3 comments

I suggest adding a convenience function next to KeyCodeTransformer.transformValue(_:carbonModifiers:) that outputs a NSMenuItem-compatible String. Because transformValue produces a printable, upper-case letter, using this as NSMenuItem.keyEquivalent will result in always adding the ⇧ (Shift) modifier key.

The proposed KeyCodeTransformer.keyEquivalent should behave like this for example:

  • ⌃⇧T should return "T"
  • ⌥T should return "t"
  • ⌘⌥⇧⌃1 should return "1"

What do you think?


It's basically a refactoring:

    fileprivate func transformValue(_ keyCode: Int, modifiers: Int) -> String {
        return keyEquivalent(keyCode, modifiers).uppercased
    }

    fileprivate func keyEquivalent(_ keyCode: Int, modifiers: Int) -> String {
        // Return Special KeyCode
        if let unmappedString = transformSpecialKeyCode(keyCode) {
            return unmappedString
        }

        let source = TISCopyCurrentASCIICapableKeyboardLayoutInputSource().takeUnretainedValue()
        let layoutData = TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData)
        let dataRef = unsafeBitCast(layoutData, to: CFData.self)

        let keyLayout = unsafeBitCast(CFDataGetBytePtr(dataRef), to: UnsafePointer<CoreServices.UCKeyboardLayout>.self)

        let keyTranslateOptions = OptionBits(CoreServices.kUCKeyTranslateNoDeadKeysBit)
        var deadKeyState: UInt32 = 0
        let maxChars = 256
        var chars = [UniChar](repeating: 0, count: maxChars)
        var length = 0

        let error = CoreServices.UCKeyTranslate(keyLayout,
                                                UInt16(keyCode),
                                                UInt16(CoreServices.kUCKeyActionDisplay),
                                                UInt32(modifiers),
                                                UInt32(LMGetKbdType()),
                                                keyTranslateOptions,
                                                &deadKeyState,
                                                maxChars,
                                                &length,
                                                &chars)

        if error != noErr { return "" }

        return NSString(characters: &chars, length: length)
    }

@DivineDominion KeyCodeTransformer.transformValue(_:carbonModifiers:) could not return T with ⇧T because it had not been able to correctly consider the modifier before.
From v3.0.0, string generation has been migrated to the Sauce.framework.
This library can be used to generate the correct string with modifiers 🎉

Good to know, and I'm glad to see progress on this because I really like the lib :)

@Econa77 FYI, I finally updated my dependencies and it works well with the Sauce framework transformations.