Permalink
Browse files

IOKit

  • Loading branch information...
youknowone committed Jan 22, 2019
1 parent 93bf8bc commit 4d5c1d455c98749eab5d105783ddabfdf77f9320
Showing with 89 additions and 55 deletions.
  1. +81 −49 OSXCore/IOKit.swift
  2. +8 −6 OSXCore/InputMethodServer.swift
@@ -11,101 +11,133 @@ import IOKit
import IOKit.hid
import IOKit.hidsystem

class IOKitError: Error {
init() {}
enum IOError: Error {
case kernel(kern_return_t)
}

public extension io_connect_t {
func close() -> IOReturn {
return IOServiceClose(self)
}
public class IOConnect {
let rawValue: io_connect_t

func getModifierLockState(_ selector: Int) -> (kern_return_t, Bool) {
var state: Bool = false
let kr = IOHIDGetModifierLockState(self, Int32(selector), &state)
return (kr, state)
init(rawValue: io_connect_t) {
self.rawValue = rawValue
}

func setModifierLockState(_ selector: Int, state: Bool) -> kern_return_t {
return IOHIDSetModifierLockState(self, Int32(selector), state)
deinit {
try? close()
IOObjectRelease(rawValue)
}
}

@objcMembers class IOConnect: NSObject {
let id: io_connect_t
public struct IOConnectSelector {
let rawValue: Int32

init(id: io_connect_t) {
self.id = id
static let capsLock = IOConnectSelector(rawValue: Int32(kIOHIDCapsLockState))
static let numLock = IOConnectSelector(rawValue: Int32(kIOHIDNumLockState))
static let activityUserIdle = IOConnectSelector(rawValue: Int32(kIOHIDActivityUserIdle))
static let activityDisplayOn = IOConnectSelector(rawValue: Int32(kIOHIDActivityDisplayOn))
}

deinit {
_ = self.id.close()
public func close() throws {
let kr = IOServiceClose(rawValue)
guard kr == KERN_SUCCESS else {
throw IOError.kernel(kr)
}
}

var capsLockState: Bool {
get {
let (kr, state) = id.getModifierLockState(kIOHIDCapsLockState)
guard kr == KERN_SUCCESS else {
return false
}
return state
public func getState(selector: IOConnectSelector) throws -> UInt32 {
var state: UInt32 = 0
let kr = IOHIDGetStateForSelector(rawValue, selector.rawValue, &state)
if kr != KERN_SUCCESS {
throw IOError.kernel(kr)
}
set {
let kr = id.setModifierLockState(kIOHIDCapsLockState, state: newValue)
// NSLog("set capslock state: \(newValue) \(kr == KERN_SUCCESS)")
return state
}

public func setState(selector: IOConnectSelector, state: UInt32) throws {
let kr = IOHIDSetStateForSelector(rawValue, selector.rawValue, state)
if kr != KERN_SUCCESS {
throw IOError.kernel(kr)
}
}
}

@objcMembers class IOService: NSObject {
let id: io_service_t
public func getModifierLock(selector: IOConnectSelector) throws -> Bool {
var state: Bool = false
let kr = IOHIDGetModifierLockState(rawValue, selector.rawValue, &state)
if kr != KERN_SUCCESS {
throw IOError.kernel(kr)
}
return state
}

init(id: io_service_t) {
self.id = id
public func setModifierLock(selector: IOConnectSelector, state: Bool) throws {
let kr = IOHIDSetModifierLockState(rawValue, selector.rawValue, state)
if kr != KERN_SUCCESS {
throw IOError.kernel(kr)
}
}
}

class IOService {
let rawValue: io_service_t

convenience init(port: mach_port_t, matching: NSDictionary?) throws {
let id = IOServiceGetMatchingService(port, matching)
if id == 0 {
throw IOKitError()
init?(port: mach_port_t, matching: NSDictionary?) {
rawValue = IOServiceGetMatchingService(port, matching)
guard rawValue != 0 else {
return nil
}
self.init(id: id)
}

convenience init(name: String) throws {
let matching = IOServiceMatching(name)
try! self.init(port: kIOMasterPortDefault, matching: matching)
convenience init?(name: String) {
self.init(port: kIOMasterPortDefault, matching: IOService.matching(name: name))
}

deinit {
IOObjectRelease(self.id)
IOObjectRelease(rawValue)
}

func open(owningTask: mach_port_t, type: Int) -> IOConnect? {
var connectId: io_connect_t = 0
let r = IOServiceOpen(id, owningTask, UInt32(type), &connectId)
guard r == KERN_SUCCESS else {
return nil
static func matching(name: String) -> NSDictionary? {
return IOServiceMatching(name)
}

func open(owningTask: mach_port_t, type: Int) throws -> IOConnect {
var connect: io_connect_t = 0
let kr = IOServiceOpen(rawValue, owningTask, UInt32(type), &connect)
guard kr == KERN_SUCCESS else {
throw IOError.kernel(kr)
}
return IOConnect(id: connectId)
return IOConnect(rawValue: connect)
}
}

public extension IOHIDValueScaleType {
public static let Calibrated = kIOHIDValueScaleTypeCalibrated
public static let Physical = kIOHIDValueScaleTypePhysical
public static let Exponent = kIOHIDValueScaleTypeExponent
}

public extension IOHIDValue {
public typealias ScaleType = IOHIDValueScaleType
public typealias Callback = IOHIDValueCallback
public typealias MultipleCallback = IOHIDValueMultipleCallback

var element: IOHIDElement {
return IOHIDValueGetElement(self)
}

var timestamp: UInt64 {
return IOHIDValueGetTimeStamp(self)
}

var length: CFIndex {
return IOHIDValueGetLength(self)
}

var integerValue: CFIndex {
return IOHIDValueGetIntegerValue(self)
}

func scaledValue(ofType type: ScaleType) -> Double {
return IOHIDValueGetScaledValue(self, type)
}
}

public extension IOHIDManager {
@@ -53,16 +53,16 @@ class IOKitty {
var capsLockDate: Date?

init?() {
guard let _service = try? IOService(name: kIOHIDSystemClass) else {
guard let _service = IOService(name: kIOHIDSystemClass) else {
return nil
}
guard let _connect = _service.open(owningTask: mach_task_self_, type: kIOHIDParamConnectType) else {
service = _service
guard let _connect = try? service.open(owningTask: mach_task_self_, type: kIOHIDParamConnectType) else {
return nil
}

service = _service
connect = _connect
defaultCapsLockState = connect.capsLockState

defaultCapsLockState = (try? connect.getModifierLock(selector: .capsLock)) ?? false

manager = IOHIDManager.create()
manager.setDeviceMatching(page: kHIDPage_GenericDesktop, usage: kHIDUsage_GD_Keyboard)
@@ -87,9 +87,11 @@ class IOKitty {
dlog(DEBUG_IOKIT_EVENT, "caps lock pressed set in context")
} else {
if _self.defaultCapsLockState || (_self.capsLockDate != nil && !_self.capsLockTriggered) {
// long pressed
_self.defaultCapsLockState = !_self.defaultCapsLockState
} else {
_self.connect.capsLockState = _self.defaultCapsLockState
// short pressed
try? _self.connect.setModifierLock(selector: .capsLock, state: _self.defaultCapsLockState)
}
_self.capsLockDate = nil
}

0 comments on commit 4d5c1d4

Please sign in to comment.