# CutBox.app

## Coverage Report

#### Created: 2024-03-12 03:40

    .../Source/Utilities/FakeKey.swift

    Line

    Count

    Source (jump to first uncovered line)

    1

    //

    2

    //  FakeKeyEvents.swift

    3

    //  CutBox

    4

    //

    5

    //  Created by Jason Milkins on 26/3/18.

    6

    //  Copyright © 2018-2023 ocodo. All rights reserved.

    7

    //

    8

    9

    import Foundation

    10

    import Carbon

    11

    12

    class FakeKey {

    13

        static var testing = false

    14

        static var testResult: [CGEvent?] = []

    15

    16

    144

        private let keyCodeRange = 0x00...0x7E

    17

    18

    5

        func send(fakeKey key: String, useCommandFlag: Bool) {

    19

    5

            let keyCode = stringToKeyCode(key)

    20

    5

            send(fakeKey: numericCast(keyCode), useCommandFlag: useCommandFlag)

    21

    5

        }

    22

    23

    508

        private func transformKeyCode(_ keyCode: Int) -> String {

    24

    508

            guard keyCodeRange.contains(keyCode)

    25

    508

                else { fatalError("Cannot transform \(keyCode) - out of range") }

    26

    508

    27

    508

            let inputSource = unsafeBitCast(

    28

    508

                TISGetInputSourceProperty(

    29

    508

                    TISCopyCurrentASCIICapableKeyboardLayoutInputSource().takeUnretainedValue(),

    30

    508

                    kTISPropertyUnicodeKeyLayoutData

    31

    508

            ), to: CFData.self)

    32

    508

    33

    508

            var deadKeyState: UInt32 = 0

    34

    508

            var char = UniChar()

    35

    508

            var length = 0

    36

    508

    37

    508

            CoreServices.UCKeyTranslate(unsafeBitCast(CFDataGetBytePtr(inputSource),

    38

    508

                                                      to: UnsafePointer<CoreServices.UCKeyboardLayout>.self),

    39

    508

                                        UInt16(keyCode),

    40

    508

                                        UInt16(CoreServices.kUCKeyActionDisplay),

    41

    508

                                        UInt32(0),

    42

    508

                                        UInt32(LMGetKbdType()),

    43

    508

                                        OptionBits(CoreServices.kUCKeyTranslateNoDeadKeysBit),

    44

    508

    45

    508

                                        &deadKeyState,

    46

    508

                                        1,

    47

    508

                                        &length,

    48

    508

                                        &char)

    49

    508

    50

    508

            return NSString(characters: &char, length: length).uppercased

    51

    508

        }

    52

    53

    4

        private func keyCodeTranslationTable() -> [String: Int] {

    54

    4

            var table = [String: Int]()

    55

    508

            for code in keyCodeRange {

    56

    508

                table[transformKeyCode(code)] = code

    57

    508

            }

    58

    4

            return table

    59

    4

        }

    60

    61

    5

        private func stringToKeyCode(_ key: String) -> Int {

    62

    5

            guard key.count == 1 else { fatalError("Only single char strings can be used") }

    63

    5

    64

    5

            let translationTable = keyCodeTranslationTable()

    65

    5

    66

    5

            guard let keyCode = translationTable[key]

    67

    5

                else { fatalError("Unable to get keyCode for: \(key)") }

    68

    5

    69

    5

            return keyCode

    70

    5

        }

    71

    72

    4

        private func send(fakeKey keyCode: CGKeyCode, useCommandFlag: Bool) {

    73

    4

            let sourceRef = CGEventSource(stateID: .combinedSessionState)

    74

    4

    75

    4

            if sourceRef == nil {

    76

    0

                NSLog("No event source")

    77

    0

                return

    78

    4

            }

    79

    4

    80

    4

            let keyDownEvent = CGEvent(

    81

    4

                keyboardEventSource: sourceRef,

    82

    4

                virtualKey: keyCode,

    83

    4

                keyDown: true

    84

    4

            )

    85

    4

    86

    4

            if useCommandFlag {

    87

    3

                keyDownEvent?.flags = .maskCommand

    88

    4

            }

    89

    4

    90

    4

            let keyUpEvent = CGEvent(

    91

    4

                keyboardEventSource: sourceRef,

    92

    4

                virtualKey: keyCode,

    93

    4

                keyDown: false

    94

    4

            )

    95

    4

    96

    4

            if !Self.testing {

    97

    0

                keyDownEvent?.post(tap: .cghidEventTap)

    98

    0

                keyUpEvent?.post(tap: .cghidEventTap)

    99

    4

            } else {

    100

    4

                Self.testResult = [keyDownEvent, keyUpEvent]

    101

    4

            }

    102

    4

        }

    103

    }