Skip to content

Commit

Permalink
feat: Enable/disable keyboard event handling with a global hotkey (Ct…
Browse files Browse the repository at this point in the history
…rl+Opt+Cmd+K) (#12)
  • Loading branch information
jbmorley authored Dec 3, 2022
1 parent 688f911 commit 97b9e22
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 20 deletions.
40 changes: 26 additions & 14 deletions macos/TinyBoard/Model/ApplicationModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import Carbon
import Combine
import SwiftUI

Expand All @@ -29,8 +30,7 @@ class ApplicationModel: NSObject, ObservableObject {
@AppStorage("TrustedDevices") var trustedDevices: Set<UUID> = []

let deviceManager = DeviceManager()

private let eventTap: EventTap
private let eventTap = EventTap()
private var cancellables: Set<AnyCancellable> = []

private lazy var aboutWindow: NSWindow = {
Expand All @@ -54,19 +54,9 @@ class ApplicationModel: NSObject, ObservableObject {
}()

override init() {
eventTap = EventTap(deviceManager: deviceManager)
super.init()
$isEnabled
.receive(on: DispatchQueue.main)
.sink { isEnabled in
switch isEnabled {
case true:
self.eventTap.enableTap()
case false:
self.eventTap.disableTap()
}
}
.store(in: &cancellables)
eventTap.delegate = self
eventTap.start()
deviceManager.delegate = self
}

Expand Down Expand Up @@ -99,3 +89,25 @@ extension ApplicationModel: DeviceManagerDelegate {
}

}

extension ApplicationModel: EventTapDelegate {

func eventTap(_ eventTap: EventTap, handleEvent event: CGEvent) -> Bool {
if let nsEvent = NSEvent(cgEvent: event) {
let deviceIndependentModifiers = nsEvent.modifierFlags.intersection(.deviceIndependentFlagsMask)
if deviceIndependentModifiers == [.control, .option, .command] && nsEvent.keyCode == kVK_ANSI_K {
if nsEvent.type == .keyDown {
isEnabled = !isEnabled
}
return true
}
}

guard isEnabled else {
return false
}
deviceManager.sendEvent(event)
return true
}

}
20 changes: 14 additions & 6 deletions macos/TinyBoard/Model/EventTap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,19 @@ private func eventTapCallback(proxy: CGEventTapProxy,
return eventTap.handleEvent(proxy: proxy, type: type, event: event)
}

protocol EventTapDelegate: AnyObject {

func eventTap(_ eventTap: EventTap, handleEvent event: CGEvent) -> Bool

}

class EventTap {

let deviceManager: DeviceManager
var eventTap: CFMachPort? = nil

init(deviceManager: DeviceManager) {
self.deviceManager = deviceManager
weak var delegate: EventTapDelegate?

init() {
}

func createEventTapIfNecessry() {
Expand All @@ -61,7 +67,7 @@ class EventTap {
self.eventTap = eventTap
}

func enableTap() {
func start() {
createEventTapIfNecessry()
guard let eventTap = eventTap else {
print("No event tap to disable")
Expand All @@ -70,7 +76,7 @@ class EventTap {
CGEvent.tapEnable(tap: eventTap, enable: true)
}

func disableTap() {
func stop() {
print("disableTap")
guard let eventTap = eventTap else {
return
Expand All @@ -79,7 +85,9 @@ class EventTap {
}

func handleEvent(proxy: CGEventTapProxy, type: CGEventType, event: CGEvent) -> Unmanaged<CGEvent>? {
deviceManager.sendEvent(event)
guard delegate?.eventTap(self, handleEvent: event) ?? false else {
return Unmanaged.passRetained(event)
}
return nil
}

Expand Down

0 comments on commit 97b9e22

Please sign in to comment.