Skip to content
Draft
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
2 changes: 1 addition & 1 deletion KeyType/Collection/Custom.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let Custom = [
// To launch Alfred faster
Remap(Key.shiftR.without.shift, to: Key.SPACE.with.option),
// Left to 'a' becomes escape
Remap(Key.ctrlR.without.ctrl, to: Key.ESCAPE.alone),
Remap(Key.ctrlR.without.ctrl, to: Key.ESCAPE),
// To launch OmniFocus faster
Remap(Key.shiftL.without.shift, to: Key.SPACE.with.shift.command.option),
]
19 changes: 9 additions & 10 deletions KeyType/Collection/Emacs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@

import Foundation

let Emacs = [
[Key.ctrlL.without.ctrl, Key.ESCAPE.alone],
[Key.J.with.ctrl, Key.RETURN.alone],
[Key.M.with.ctrl, Key.RETURN.alone],
[Key.F.with.ctrl, Key.RIGHT_ARROW.alone],
[Key.B.with.ctrl, Key.LEFT_ARROW.alone],
[Key.N.with.ctrl, Key.DOWN_ARROW.alone],
[Key.P.with.ctrl, Key.UP_ARROW.alone],
[Key.H.with.ctrl, Key.DELETE.alone],
].map { Remap($0[0], to: $0[1]) }
let EmacsLike = [
Remap(Key.J.with.ctrl, to: .returnKey),
Remap(Key.M.with.ctrl, to: .returnKey),
Remap(Key.F.with.ctrl, to: .rightArrow),
Remap(Key.B.with.ctrl, to: .leftArrow),
Remap(Key.N.with.ctrl, to: .downArrow),
Remap(Key.P.with.ctrl, to: .upArrow),
Remap(Key.H.with.ctrl, to: .delete),
]
4 changes: 2 additions & 2 deletions KeyType/Collection/KanaEisu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
import Foundation

let KanaEisu: KeyMapCollection = [
Remap(Key.commandL.without.command, to: Key.EISU.alone),
Remap(Key.commandR.without.command, to: Key.KANA.alone),
Remap(Key.commandL.without.command, to: Key.EISU),
Remap(Key.commandR.without.command, to: Key.KANA),
]
2 changes: 1 addition & 1 deletion KeyType/EventConverter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class EventConverter {
}

for remap in candidateRemaps {
if eventKeyCombination.isCompatible(with: remap) {
if eventKeyCombination.canTrigger(remap.input) {
event.keyCode = remap.outputKeyCode
event.flags = remap.renderEventFlag(for: event)
return event
Expand Down
12 changes: 6 additions & 6 deletions KeyType/Key/Key.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ enum Key: UInt16 {
case SQUARE_BRA = 33
case I = 34
case P = 35
case RETURN = 36
case returnKey = 36
case L = 37
case J = 38
case QUOTE = 39
Expand All @@ -60,7 +60,7 @@ enum Key: UInt16 {
case TAB = 48
case SPACE = 49
case BACKQUOTE = 50
case DELETE = 51
case delete = 51
case ENTER_POWERBOOK = 52
case ESCAPE = 53
case commandR = 54
Expand Down Expand Up @@ -123,10 +123,10 @@ enum Key: UInt16 {
case F2 = 120
case PG_DOWN = 121
case F1 = 122
case LEFT_ARROW = 123
case RIGHT_ARROW = 124
case DOWN_ARROW = 125
case UP_ARROW = 126
case leftArrow = 123
case rightArrow = 124
case downArrow = 125
case upArrow = 126
case PC_POWER = 127
case GERMAN_PC_LESS_THAN = 128
case DASHBOARD = 130
Expand Down
71 changes: 37 additions & 34 deletions KeyType/Key/KeyCombination.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,13 @@ import Cocoa

class KeyCombination {
let keyCode: CGKeyCode
var flags = CGEventFlags()
private(set) var withFlags = CGEventFlags()
private var withoutFlags = CGEventFlags()
private var addToWithFlag = true

var withoutModifier: CGEventFlags {
return withoutFlags
}

init(fromEvent: CGEvent) {
keyCode = fromEvent.keyCode
flags = fromEvent.flags
withFlags = fromEvent.flags
}

init(_ key: Key) {
Expand All @@ -29,7 +25,7 @@ class KeyCombination {

private func addMask(_ mask: CGEventFlags) -> KeyCombination {
if addToWithFlag {
flags.insert(mask)
withFlags.insert(mask)
} else {
withoutFlags.insert(mask)
}
Expand All @@ -52,33 +48,14 @@ class KeyCombination {
return addMask(.maskAlternate)
}

private func setModeExAddition() {
addToWithFlag = false
}

var without: KeyCombination {
setModeExAddition()
addToWithFlag = false
return self
}

var label: String {
guard let key = Key(rawValue: keyCode) else { return flagString }
return flagString + String(describing: key)
}

private var flagString: String {
var flagString = ""
if has(modifier: .maskSecondaryFn) { flagString += "(fn)" }
if has(modifier: .maskAlphaShift) { flagString += "⇪" }
if has(modifier: .maskCommand) { flagString += "⌘" }
if has(modifier: .maskShift) { flagString += "⇧" }
if has(modifier: .maskControl) { flagString += "⌃" }
if has(modifier: .maskAlternate) { flagString += "⌥" }
return flagString
}

private func has(modifier key: CGEventFlags) -> Bool {
return flags.contains(key)
var with: KeyCombination {
addToWithFlag = true
return self
}

func postEvent() {
Expand All @@ -87,22 +64,48 @@ class KeyCombination {
let keyDownEvent = CGEvent(keyboardEventSource: nil, virtualKey: keyCode, keyDown: true)!
let keyUpEvent = CGEvent(keyboardEventSource: nil, virtualKey: keyCode, keyDown: false)!

keyDownEvent.flags = flags
keyDownEvent.flags = withFlags
keyUpEvent.flags = CGEventFlags()

keyDownEvent.post(tap: loc)
keyUpEvent.post(tap: loc)
}

func isCompatible(with mapping: Remap) -> Bool {
let cmb = mapping.input
func canTrigger(_ cmb: KeyCombination) -> Bool {
if cmb.has(modifier: .maskCommand), !has(modifier: .maskCommand) { return false }
if cmb.has(modifier: .maskShift), !has(modifier: .maskShift) { return false }
if cmb.has(modifier: .maskControl), !has(modifier: .maskControl) { return false }
if cmb.has(modifier: .maskAlternate), !has(modifier: .maskAlternate) { return false }
if cmb.has(modifier: .maskSecondaryFn), !has(modifier: .maskSecondaryFn) { return false }
if cmb.has(modifier: .maskAlphaShift), !has(modifier: .maskAlphaShift) { return false }

return mapping.hasAnyModToAvoid(flags)
return cmb.hasAnyModToAvoid(withFlags)
}

private func hasAnyModToAvoid(_ flags: CGEventFlags) -> Bool {
return flags.rawValue & withoutFlags.rawValue == 0
}

private func has(modifier key: CGEventFlags) -> Bool {
return withFlags.contains(key)
}
}

// Debug
extension KeyCombination {
var label: String {
guard let key = Key(rawValue: keyCode) else { return flagString }
return flagString + String(describing: key)
}

private var flagString: String {
var flagString = ""
if has(modifier: .maskSecondaryFn) { flagString += "(fn)" }
if has(modifier: .maskAlphaShift) { flagString += "⇪" }
if has(modifier: .maskCommand) { flagString += "⌘" }
if has(modifier: .maskShift) { flagString += "⇧" }
if has(modifier: .maskControl) { flagString += "⌃" }
if has(modifier: .maskAlternate) { flagString += "⌥" }
return flagString
}
}
11 changes: 6 additions & 5 deletions KeyType/Key/Remap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ class Remap: NSObject {
self.output = output
}

func renderEventFlag(for event: CGEvent) -> CGEventFlags {
let rawValue = (event.flags.rawValue & ~input.flags.rawValue) | output.flags.rawValue
return CGEventFlags(rawValue: rawValue)
init(_ from: KeyCombination, to output: Key) {
input = from
self.output = output.alone
}

func hasAnyModToAvoid(_ flags: CGEventFlags) -> Bool {
return flags.rawValue & input.withoutModifier.rawValue == 0
func renderEventFlag(for event: CGEvent) -> CGEventFlags {
let rawValue = (event.flags.rawValue & ~input.withFlags.rawValue) | output.withFlags.rawValue
return CGEventFlags(rawValue: rawValue)
}
}
2 changes: 1 addition & 1 deletion KeyType/KeyEventWatcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Cocoa
class KeyEventWatcher {
private var keyCode: CGKeyCode?
private let bundleId = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String
private let config = EventConverter(LRDvorak + KanaEisu + Emacs + Custom)
private let config = EventConverter(LRDvorak + KanaEisu + EmacsLike + Custom)

private var eventMaskToWatch: CGEventMask {
let eventTypeList: [CGEventType] = [
Expand Down
4 changes: 4 additions & 0 deletions KeyTypeTests/KeyCombinationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class KeyCombinationTests: XCTestCase {
XCTAssert(convert(KanaEisu, key: Key.commandR)?.keyCode == Key.KANA.rawValue)
}

func testChain() {
XCTAssertFalse(Key.commandR.without.command.withFlags.contains(.maskCommand))
}

private func convert(_ collection: KeyMapCollection, key: Key) -> CGEvent? {
let converter = EventConverter(collection)
let event = CGEvent(
Expand Down