Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ enum KeyboardKeyCode: UInt16 {
// MARK: - Letters & punctuation

case a = 0x00
case k = 0x28
case e = 0x0E
case digit7 = 0x1A
case minus = 0x1B
case u = 0x20
case k = 0x28
case grave = 0x32

// MARK: - Whitespace & editing

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ final class EventTap {
}

fileprivate func handleFlagsChanged(_ cgEvent: CGEvent) {
let flags = NSEvent.ModifierFlags(rawValue: UInt(cgEvent.flags.rawValue))
let flags = NSEvent.ModifierFlags(cgEventFlags: cgEvent.flags)
self.delegate?.eventTap(self, noteFlagsChanged: flags)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// NSEventModifierFlags+RawMasks.swift
// Keyty
//
// SPDX-FileCopyrightText: 2026 Serhii Bykov
// SPDX-License-Identifier: BSD-3-Clause
//

import AppKit

extension NSEvent.ModifierFlags {
init(cgEventFlags: CGEventFlags) {
self.init(rawValue: UInt(cgEventFlags.rawValue))
}

func addingRawMasks(_ masks: UInt...) -> Self {
self.addingRawMasks(masks)
}

func addingRawMasks(_ masks: [UInt]) -> Self {
Self(rawValue: masks.reduce(self.rawValue) { $0 | $1 })
}
}
21 changes: 4 additions & 17 deletions Apps/Keyty/Tests/KeytyTests/Domain/Events/MouseEventTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import XCTest

final class MouseEventTests: XCTestCase {
func testKindClassifiesButtonsAndScrollDirections() {
XCTAssertEqual(makeMouseEvent(type: .leftMouseDown, buttonNumber: 0).kind, .leftButton)
XCTAssertEqual(makeMouseEvent(type: .rightMouseDown, buttonNumber: 1).kind, .rightButton)
XCTAssertEqual(makeMouseEvent(type: .otherMouseDown, buttonNumber: 2).kind, .middleButton)
XCTAssertEqual(makeMouseEvent(type: .otherMouseDown, buttonNumber: 3).kind, .otherButton(4))
XCTAssertEqual(TestMouseEvents.make(type: .leftMouseDown, buttonNumber: 0).kind, .leftButton)
XCTAssertEqual(TestMouseEvents.make(type: .rightMouseDown, buttonNumber: 1).kind, .rightButton)
XCTAssertEqual(TestMouseEvents.make(type: .otherMouseDown, buttonNumber: 2).kind, .middleButton)
XCTAssertEqual(TestMouseEvents.make(type: .otherMouseDown, buttonNumber: 3).kind, .otherButton(4))
XCTAssertEqual(makeScrollEvent(deltaX: 0, deltaY: 1).kind, .wheelUp)
XCTAssertEqual(makeScrollEvent(deltaX: 0, deltaY: -1).kind, .wheelDown)
XCTAssertEqual(makeScrollEvent(deltaX: -1, deltaY: 0).kind, .wheelLeft)
Expand Down Expand Up @@ -68,19 +68,6 @@ final class MouseEventTests: XCTestCase {
XCTAssertEqual(location.y, 980)
}

private func makeMouseEvent(type: NSEvent.EventType, buttonNumber: Int) -> MouseEvent {
let cgType: CGEventType = {
switch type {
case .leftMouseDown: return .leftMouseDown
case .rightMouseDown: return .rightMouseDown
default: return .otherMouseDown
}
}()
let cgEvent = CGEvent(mouseEventSource: nil, mouseType: cgType, mouseCursorPosition: .zero, mouseButton: .left)!
cgEvent.setIntegerValueField(.mouseEventButtonNumber, value: Int64(buttonNumber))
return MouseEvent(nsEvent: NSEvent(cgEvent: cgEvent)!)
}

private func makeScrollEvent(deltaX: CGFloat, deltaY: CGFloat) -> MouseEvent {
let cgEvent = CGEvent(scrollWheelEvent2Source: nil, units: .pixel, wheelCount: 2, wheel1: Int32(deltaY), wheel2: Int32(deltaX), wheel3: 0)!
return MouseEvent(nsEvent: NSEvent(cgEvent: cgEvent)!)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ final class KeyboardVisualizerSpecialKeyFilteringTests: XCTestCase {
}

func testResolverClassifiesInsertFunctionKeyAsSpecial() {
let ch = Self.appKitFunctionKey(NSInsertFunctionKey)
let event = Self.makeKeystroke(
let ch = TestKeyboardCharacters.functionKeyCharacter(NSInsertFunctionKey)
let event = TestKeystrokes.make(
keyCode: KeyboardKeyCode.help.rawValue,
characters: ch,
charactersIgnoringModifiers: ch
Expand All @@ -44,7 +44,7 @@ final class KeyboardVisualizerSpecialKeyFilteringTests: XCTestCase {
}

func testResolverClassifiesPrintableLetterAsNonSpecial() {
let event = Self.makeKeystroke(
let event = TestKeystrokes.make(
keyCode: KeyboardKeyCode.a.rawValue,
characters: "a",
charactersIgnoringModifiers: "a"
Expand All @@ -53,27 +53,4 @@ final class KeyboardVisualizerSpecialKeyFilteringTests: XCTestCase {
XCTAssertFalse(KeyboardSpecialKeyResolver.isSpecial(event))
}

private static func makeKeystroke(
keyCode: UInt16,
characters: String,
charactersIgnoringModifiers: String
) -> StandardKeyEvent {
let event = NSEvent.keyEvent(
with: .keyDown,
location: .zero,
modifierFlags: [],
timestamp: NSDate.timeIntervalSinceReferenceDate,
windowNumber: 0,
context: nil,
characters: characters,
charactersIgnoringModifiers: charactersIgnoringModifiers,
isARepeat: false,
keyCode: keyCode
)!
return StandardKeyEvent(nsEvent: event)
}

private static func appKitFunctionKey(_ key: Int) -> String {
String(UnicodeScalar(key)!)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ import XCTest

final class KeycapItemFactoryTests: XCTestCase {
func testKeyboardModifierKeysDecodeLocationSpecificFlags() {
let flags = NSEvent.ModifierFlags(
.command,
deviceMasks: UInt(NX_DEVICELCMDKEYMASK),
let flags = NSEvent.ModifierFlags.command.addingRawMasks(
UInt(NX_DEVICELCMDKEYMASK),
UInt(NX_DEVICERCMDKEYMASK)
)

Expand All @@ -37,9 +36,8 @@ final class KeycapItemFactoryTests: XCTestCase {

func testModifierItemsUseLocationSpecificModifierKeys() {
let items = KeycapItemFactory.modifierItems(
currentFlags: NSEvent.ModifierFlags(
.command,
deviceMasks: UInt(NX_DEVICELCMDKEYMASK),
currentFlags: NSEvent.ModifierFlags.command.addingRawMasks(
UInt(NX_DEVICELCMDKEYMASK),
UInt(NX_DEVICERCMDKEYMASK)
),
releasedFlags: [],
Expand All @@ -55,9 +53,8 @@ final class KeycapItemFactoryTests: XCTestCase {

func testModifierItemsUseInwardAlignmentForNonCommandModifierKeys() {
let items = KeycapItemFactory.modifierItems(
currentFlags: NSEvent.ModifierFlags(
.shift,
deviceMasks: UInt(NX_DEVICELSHIFTKEYMASK),
currentFlags: NSEvent.ModifierFlags.shift.addingRawMasks(
UInt(NX_DEVICELSHIFTKEYMASK),
UInt(NX_DEVICERSHIFTKEYMASK)
),
releasedFlags: [],
Expand Down Expand Up @@ -137,11 +134,11 @@ final class KeycapItemFactoryTests: XCTestCase {
let palette = Self.makePalette()

let downItem = KeycapItemFactory.mouseItem(
for: Self.makeMouseEvent(type: .leftMouseDown),
for: TestMouseEvents.make(type: .leftMouseDown),
palette: palette
)
let upItem = KeycapItemFactory.mouseItem(
for: Self.makeMouseEvent(type: .leftMouseUp),
for: TestMouseEvents.make(type: .leftMouseUp),
palette: palette
)

Expand All @@ -167,9 +164,4 @@ final class KeycapItemFactoryTests: XCTestCase {
)
}

private static func makeMouseEvent(type: NSEvent.EventType) -> MouseEvent {
let cgType: CGEventType = type == .leftMouseDown ? .leftMouseDown : .leftMouseUp
let cgEvent = CGEvent(mouseEventSource: nil, mouseType: cgType, mouseCursorPosition: .zero, mouseButton: .left)!
return MouseEvent(nsEvent: NSEvent(cgEvent: cgEvent)!)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ final class EventProcessorTests: XCTestCase {
var items: [DisplayItem] = []
processor.onItemProduced = { items.append($0) }

processor.noteMouseEvent(Self.makeMouseEvent(type: .leftMouseUp, buttonNumber: 0, modifiers: [.command]))
processor.noteMouseEvent(TestMouseEvents.make(type: .leftMouseUp, buttonNumber: 0, modifiers: [.command]))

XCTAssertEqual(items.count, 2)
XCTAssertEqual(items[0].kind, .content)
Expand All @@ -28,37 +28,12 @@ final class EventProcessorTests: XCTestCase {
var items: [DisplayItem] = []
processor.onItemProduced = { items.append($0) }

processor.noteMouseEvent(Self.makeMouseEvent(type: .leftMouseUp, buttonNumber: 0, modifiers: []))
processor.noteMouseEvent(TestMouseEvents.make(type: .leftMouseUp, buttonNumber: 0, modifiers: []))

XCTAssertEqual(items.count, 2)
XCTAssertEqual(items[0].kind, .content)
XCTAssertEqual(items[0].sourceEvent?.type, .leftMouseUp)
XCTAssertEqual(items[1].kind, .groupBreak)
}

private static func makeMouseEvent(
type: NSEvent.EventType,
buttonNumber: Int,
modifiers: NSEvent.ModifierFlags
) -> MouseEvent {
let cgType: CGEventType = {
switch type {
case .leftMouseDown, .leftMouseUp: return type == .leftMouseDown ? .leftMouseDown : .leftMouseUp
case .rightMouseDown, .rightMouseUp: return type == .rightMouseDown ? .rightMouseDown : .rightMouseUp
default: return type == .otherMouseDown ? .otherMouseDown : .otherMouseUp
}
}()

var cgFlags: CGEventFlags = []
if modifiers.contains(.shift) { cgFlags.insert(.maskShift) }
if modifiers.contains(.command) { cgFlags.insert(.maskCommand) }
if modifiers.contains(.control) { cgFlags.insert(.maskControl) }
if modifiers.contains(.option) { cgFlags.insert(.maskAlternate) }
if modifiers.contains(.function) { cgFlags.insert(.maskSecondaryFn) }

let cgEvent = CGEvent(mouseEventSource: nil, mouseType: cgType, mouseCursorPosition: .zero, mouseButton: .left)!
cgEvent.setIntegerValueField(.mouseEventButtonNumber, value: Int64(buttonNumber))
cgEvent.flags = cgFlags
return MouseEvent(nsEvent: NSEvent(cgEvent: cgEvent)!)
}
}
Loading
Loading