Skip to content
This repository was archived by the owner on Mar 24, 2020. It is now read-only.
Open
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
26 changes: 25 additions & 1 deletion Keyboard Connect Open Source.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0730;
LastUpgradeCheck = 1010;
ORGANIZATIONNAME = "Arthur Yidi";
TargetAttributes = {
228F34571DA3014B00F264A0 = {
Expand Down Expand Up @@ -156,13 +156,23 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
Expand All @@ -189,6 +199,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
Expand All @@ -201,13 +212,23 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
Expand All @@ -226,6 +247,8 @@
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_VERSION = 3.0;
};
name = Release;
};
Expand Down Expand Up @@ -270,6 +293,7 @@
228F34671DA3014C00F264A0 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
Expand Down
44 changes: 23 additions & 21 deletions Keyboard Connect Open Source/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@ import IOBluetooth
func myCGEventCallback(proxy : CGEventTapProxy,
type : CGEventType,
event : CGEvent,
refcon : UnsafeMutablePointer<Void>) -> Unmanaged<CGEvent>? {
refcon : UnsafeMutableRawPointer?) -> Unmanaged<CGEvent>? {

let btKey = UnsafeMutablePointer<BTKeyboard>(refcon).memory
let oPtr = OpaquePointer(refcon)
let btPtr = UnsafeMutablePointer<BTKeyboard>(oPtr)
let btKey = btPtr?.pointee
switch type {
case .KeyUp:
if let nsEvent = NSEvent(CGEvent: event) {
btKey.sendKey(-1, nsEvent.modifierFlags.rawValue)
case .keyUp:
if let nsEvent = NSEvent(cgEvent: event) {
btKey?.sendKey(vkeyCode: -1, nsEvent.modifierFlags.rawValue)
}
break
case .KeyDown:
if let nsEvent = NSEvent(CGEvent: event) {
btKey.sendKey(Int(nsEvent.keyCode), nsEvent.modifierFlags.rawValue)
case .keyDown:
if let nsEvent = NSEvent(cgEvent: event) {
btKey?.sendKey(vkeyCode: Int(nsEvent.keyCode), nsEvent.modifierFlags.rawValue)
}
break
default:
Expand All @@ -38,7 +40,7 @@ var btKey: BTKeyboard?

class AppDelegate: NSObject, NSApplicationDelegate {

func applicationDidBecomeActive(notification: NSNotification) {
func applicationDidBecomeActive(_ notification: Notification) {
btKey = BTKeyboard()

if !AXIsProcessTrusted() {
Expand All @@ -47,23 +49,23 @@ class AppDelegate: NSObject, NSApplicationDelegate {

// capture all key events
var eventMask: CGEventMask = 0
eventMask |= (1 << CGEventMask(CGEventType.KeyUp.rawValue))
eventMask |= (1 << CGEventMask(CGEventType.KeyDown.rawValue))
eventMask |= (1 << CGEventMask(CGEventType.FlagsChanged.rawValue))
eventMask |= (1 << CGEventMask(CGEventType.keyUp.rawValue))
eventMask |= (1 << CGEventMask(CGEventType.keyDown.rawValue))
eventMask |= (1 << CGEventMask(CGEventType.flagsChanged.rawValue))

if let eventTap = CGEventTapCreate(.CGSessionEventTap,
.HeadInsertEventTap,
.Default,
eventMask,
myCGEventCallback,
&btKey) {
if let eventTap = CGEvent.tapCreate(tap:.cgSessionEventTap,
place:.headInsertEventTap,
options:CGEventTapOptions.defaultTap,
eventsOfInterest:eventMask,
callback:myCGEventCallback,
userInfo:&btKey) {
let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0)
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes)
CGEventTapEnable(eventTap, true)
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, CFRunLoopMode.commonModes)
CGEvent.tapEnable(tap: eventTap, enable: true)
}
}

func applicationWillTerminate(aNotification: NSNotification) {
btKey?.terminate()
}
}
}
87 changes: 46 additions & 41 deletions Keyboard Connect Open Source/BTKeyboard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ struct BTChannels {
}

private class CallbackWrapper: IOBluetoothDeviceAsyncCallbacks {
var callback: ((device: IOBluetoothDevice!, status: IOReturn) -> Void)? = nil
@objc func connectionComplete(device: IOBluetoothDevice!, status: IOReturn) {
var callback: ((_ device: IOBluetoothDevice?, _ status: IOReturn) -> Void)? = nil
@objc func connectionComplete(_ device: IOBluetoothDevice, status: IOReturn) {
if let callback = self.callback {
callback(device: device, status: status)
callback(device, status)
}
}
@objc func remoteNameRequestComplete(device: IOBluetoothDevice!, status: IOReturn) {}
@objc func sdpQueryComplete(device: IOBluetoothDevice!, status: IOReturn) {}
@objc func remoteNameRequestComplete(_ device: IOBluetoothDevice!, status: IOReturn) {}
@objc func sdpQueryComplete(_ device: IOBluetoothDevice!, status: IOReturn) {}
}

class BTDevice {
Expand All @@ -76,27 +76,27 @@ class BTKeyboard: IOBluetoothL2CAPChannelDelegate {
bluetoothHost.setClassOfDevice(0x002540, forTimeInterval: 60)

// Bluetooth SDP Service
let dictPath = NSBundle.mainBundle().pathForResource("SerialPortDictionary", ofType: "plist")
let sdpDict = NSDictionary.init(contentsOfFile: dictPath!) as! Dictionary<NSObject, AnyObject>
service = IOBluetoothSDPServiceRecord.publishedServiceRecordWithDictionary(sdpDict)
let dictPath = Bundle.main.path(forResource:"SerialPortDictionary", ofType: "plist")
let sdpDict = NSDictionary.init(contentsOfFile: dictPath!)! as Dictionary<NSObject, AnyObject>
service = IOBluetoothSDPServiceRecord.publishedServiceRecord(with: sdpDict)

// Open Channels for Incoming Connections
guard IOBluetoothL2CAPChannel
.registerForChannelOpenNotifications(self,
selector: #selector(newL2CAPChannelOpened),
withPSM: BTChannels.Control,
direction: kIOBluetoothUserNotificationChannelDirectionIncoming) != nil else
.register(forChannelOpenNotifications: self,
selector: #selector(newL2CAPChannelOpened),
withPSM: BTChannels.Control,
direction: kIOBluetoothUserNotificationChannelDirectionIncoming) != nil else
{
print("failed to register: \(BTChannels.Control)")
return
}
guard IOBluetoothL2CAPChannel
.registerForChannelOpenNotifications(self,
selector: #selector(newL2CAPChannelOpened),
withPSM: BTChannels.Interrupt,
direction: kIOBluetoothUserNotificationChannelDirectionIncoming) != nil else
.register(forChannelOpenNotifications: self,
selector: #selector(newL2CAPChannelOpened),
withPSM: BTChannels.Interrupt,
direction: kIOBluetoothUserNotificationChannelDirectionIncoming) != nil else
{
print("failed to registered: \(BTChannels.Interrupt)")
print("failed to register: \(BTChannels.Interrupt)")
return
}
}
Expand All @@ -111,7 +111,7 @@ class BTKeyboard: IOBluetoothL2CAPChannelDelegate {
{ return didfail }

defer {
if didfail { deviceWrapper.controlChannel?.closeChannel() }
if didfail { deviceWrapper.controlChannel?.close() }
}

guard device.openL2CAPChannelSync(&deviceWrapper.interruptChannel, withPSM: BTChannels.Interrupt, delegate: self) == kIOReturnSuccess else
Expand All @@ -122,23 +122,24 @@ class BTKeyboard: IOBluetoothL2CAPChannelDelegate {
}

private func sendBytes(channel: IOBluetoothL2CAPChannel, _ bytes: [UInt8]) {
let ioError = channel.writeAsync(UnsafeMutablePointer<UInt8>(bytes), length: UInt16(bytes.count), refcon: nil)
let oPtr = OpaquePointer(bytes)
let ioError = channel.writeAsync(UnsafeMutablePointer<UInt8>(oPtr), length: UInt16(bytes.count), refcon: nil)
if ioError != kIOReturnSuccess {
print("Buff Data Failed \(channel.PSM)")
print("Buff Data Failed \(channel.psm)")
}
}

func sendHandshake(channel: IOBluetoothL2CAPChannel, _ status: BTHandshake) {
guard channel.PSM == BTChannels.Control else {
guard channel.psm == BTChannels.Control else {
print("Passing wrong channel to handshake")
return
}
sendBytes(channel, [0x0 | status.rawValue])
sendBytes(channel: channel, [0x0 | status.rawValue])
}

func sendData(bytes: [UInt8]) {
if let interruptChannel = curDevice?.interruptChannel {
sendBytes(interruptChannel, bytes)
sendBytes(channel: interruptChannel, bytes)
}
}

Expand Down Expand Up @@ -170,35 +171,37 @@ class BTKeyboard: IOBluetoothL2CAPChannelDelegate {
- modifierRawValue: raw modifier provided by NSEvent
*/
func sendKey(vkeyCode: Int, _ modifierRawValue: UInt) {
let keyCode = UInt8(virtualKeyCodeToHIDKeyCode(vkeyCode))
let keyCode = UInt8(virtualKeyCodeToHIDKeyCode(vKeyCode: vkeyCode))

let vmodifier = NSEventModifierFlags(rawValue: modifierRawValue)
let vmodifier = NSEvent.ModifierFlags(rawValue: modifierRawValue)
var modifier: UInt8 = 0

if vmodifier.contains(NSEventModifierFlags.CommandKeyMask) {
if vmodifier.contains(NSEvent.ModifierFlags.command) {
modifier |= (1 << 3)
}
if vmodifier.contains(NSEventModifierFlags.AlternateKeyMask) {
if vmodifier.contains(NSEvent.ModifierFlags.option) {
modifier |= (1 << 2)
}
if vmodifier.contains(NSEventModifierFlags.ShiftKeyMask) {
if vmodifier.contains(NSEvent.ModifierFlags.shift) {
modifier |= (1 << 1)
}
if vmodifier.contains(NSEventModifierFlags.ControlKeyMask) {
if vmodifier.contains(NSEvent.ModifierFlags.control) {
modifier |= 1
}

sendData(hidReport(keyCode, modifier))
sendData(bytes: hidReport(keyCode: keyCode, modifier))
}

func terminate() {
curDevice?.device?.closeConnection()
}

@objc func l2capChannelData(channel: IOBluetoothL2CAPChannel!, data dataPointer: UnsafeMutablePointer<Void>, length dataLength: Int) {
let data = UnsafeBufferPointer<UInt8>(start:UnsafePointer<UInt8>(dataPointer), count:dataLength)
@objc func l2capChannelData(_ channel: IOBluetoothL2CAPChannel!, data dataPointer: UnsafeMutableRawPointer, length dataLength: Int) {
let oPtr = OpaquePointer(dataPointer)
let uPtr = UnsafeMutablePointer<UInt8>(oPtr)
let data = UnsafeBufferPointer<UInt8>(start: uPtr, count:dataLength)

if channel.PSM == BTChannels.Control {
if channel.psm == BTChannels.Control {
guard data.count > 0 else
{ return }

Expand All @@ -211,19 +214,21 @@ class BTKeyboard: IOBluetoothL2CAPChannelDelegate {
case .HIDControl:
channel.device.closeConnection()
case .SetReport:
sendHandshake(channel, .Successful)
sendHandshake(channel: channel, .Successful)
case .SetProtocol:
sendHandshake(channel, .Successful)
sendHandshake(channel: channel, .Successful)
default:
return
}
}
}

@objc func l2capChannelOpenComplete(channel: IOBluetoothL2CAPChannel!, status error: IOReturn) {
setupDevice(channel.device)
@objc func l2capChannelOpenComplete(_ channel: IOBluetoothL2CAPChannel!, status error: IOReturn) {
if !setupDevice(device: channel.device) {
return
}

switch channel.PSM {
switch channel.psm {
case BTChannels.Control:
curDevice?.controlChannel = channel
break
Expand All @@ -235,15 +240,15 @@ class BTKeyboard: IOBluetoothL2CAPChannelDelegate {
}
}

@objc func l2capChannelClosed(channel: IOBluetoothL2CAPChannel!) {
@objc func l2capChannelClosed(_ channel: IOBluetoothL2CAPChannel!) {

}

@objc func l2capChannelWriteComplete(channel: IOBluetoothL2CAPChannel!, refcon: UnsafeMutablePointer<Void>, status error: IOReturn) {
@objc func l2capChannelWriteComplete(_ channel: IOBluetoothL2CAPChannel!, refcon: UnsafeMutableRawPointer, status error: IOReturn) {

}

@objc func newL2CAPChannelOpened(notification: IOBluetoothUserNotification, channel: IOBluetoothL2CAPChannel) {
channel.setDelegate(self)
}
}
}
6 changes: 3 additions & 3 deletions Keyboard Connect Open Source/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
import Cocoa

func main(arguments: [String]) {
let application = NSApplication.sharedApplication()
let application = NSApplication.shared()
let delegate = AppDelegate()
application.delegate = delegate

func quit(signal: Int32) {
NSApplication.sharedApplication().terminate(NSNumber(int: signal))
NSApplication.shared().terminate(NSNumber(value: signal))
}

signal(SIGHUP, quit)
Expand All @@ -25,4 +25,4 @@ func main(arguments: [String]) {
application.run()
}

main(Process.arguments)
main(arguments: CommandLine.arguments)