Initial commit: uskey - macOS keyboard remapper

Features:
- Menu bar GUI with enable/disable toggle
- JSON-based configuration system
- File-based logging with debug support
- CGEventTap-based key remapping
- Custom app icon support
- DMG installer packaging

Core Components:
- AppDelegate: Application lifecycle and initialization
- EventTapManager: Event tap creation and management with proper pointer lifetime
- KeyMapper: Key mapping logic and configuration loading
- StatusBarController: Menu bar UI and user interactions
- Logger: File and console logging with configurable levels
- Config: JSON configuration parser with default creation

Build System:
- build-app.sh: Creates macOS .app bundle with icon
- build-dmg.sh: Generates distributable DMG installer
- create-icon.sh: Converts PNG to .icns format

Documentation:
- README.md: User guide and troubleshooting
- BUILD.md: Build instructions and packaging
- DEBUG.md: Debugging guide with log access

🤖 Generated with [Qoder](https://qoder.com)
This commit is contained in:
loveuer
2025-12-02 17:51:56 +08:00
commit 1e8b79585f
18 changed files with 1229 additions and 0 deletions

47
Sources/KeyMapper.swift Normal file
View File

@@ -0,0 +1,47 @@
@preconcurrency import Foundation
@preconcurrency import CoreGraphics
struct KeyMapper {
private var mappings: [Int64: Int64] = [:]
init() {
}
init(fromConfig config: Config) {
loadFromConfig(config)
}
mutating func loadFromConfig(_ config: Config) {
mappings.removeAll()
for (from, to) in config.mapping.getAllMappings() {
mappings[from] = to
Logger.debug("Loaded mapping: \(from) -> \(to)")
}
}
mutating func addMapping(from: Int64, to: Int64) {
mappings[from] = to
}
mutating func removeMapping(from: Int64) {
mappings.removeValue(forKey: from)
}
func getMappedKey(for keyCode: Int64) -> Int64? {
return mappings[keyCode]
}
func hasMappingFor(keyCode: Int64) -> Bool {
return mappings[keyCode] != nil
}
func printMappings() {
Logger.info("")
Logger.info("Current key mappings:")
Logger.info("====================")
for (from, to) in mappings.sorted(by: { $0.key < $1.key }) {
Logger.info(" \(from) -> \(to)")
}
Logger.info("")
}
}