├── .gitignore ├── CONTRIBUTING.md ├── Debug └── TouchBarServer.app.dSYM │ └── Contents │ ├── Info.plist │ └── Resources │ └── DWARF │ └── TouchBarServer ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── Resources ├── Screenshot.png ├── TouchBarIcon.sketch └── Xcode.png ├── Scripts ├── generate_keyboard_layouts.sh └── release.sh ├── Shared ├── Generated │ ├── KeyboardLayoutANSI.h │ ├── KeyboardLayoutANSI.m │ ├── KeyboardLayoutISO.h │ ├── KeyboardLayoutISO.m │ ├── KeyboardLayoutJIS.h │ └── KeyboardLayoutJIS.m ├── Keyboard.h ├── KeyboardLayout.h ├── KeyboardLayout.m ├── Peertalk │ ├── PTChannel.h │ ├── PTChannel.m │ ├── PTPrivate.h │ ├── PTProtocol.h │ ├── PTProtocol.m │ ├── PTUSBHub.h │ ├── PTUSBHub.m │ ├── Peertalk.h │ └── prefix.pch └── Protocol.h ├── TouchBar.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ ├── TouchBarClient.xcscheme │ ├── TouchBarServer Helper.xcscheme │ └── TouchBarServer.xcscheme ├── TouchBarClient ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-40.png │ │ ├── Icon-40@2x.png │ │ ├── Icon-40@3x.png │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-72.png │ │ ├── Icon-72@2x.png │ │ ├── Icon-76.png │ │ ├── Icon-76@2x.png │ │ ├── Icon-83.5@2x.png │ │ ├── Icon-Small-50.png │ │ ├── Icon-Small-50@2x.png │ │ ├── Icon-Small.png │ │ ├── Icon-Small@2x.png │ │ ├── Icon-Small@3x.png │ │ ├── Icon.png │ │ ├── Icon@2x.png │ │ ├── NotificationIcon@2x.png │ │ ├── NotificationIcon@3x.png │ │ ├── NotificationIcon~ipad.png │ │ └── NotificationIcon~ipad@2x.png │ ├── Contents.json │ ├── DemoImage1.imageset │ │ ├── Contents.json │ │ └── DemoImage1.jpg │ ├── DemoImage2.imageset │ │ ├── Contents.json │ │ └── DemoImage2.jpg │ ├── DemoImage3.imageset │ │ ├── Contents.json │ │ └── DemoImage3.jpg │ ├── DemoImage4.imageset │ │ ├── Contents.json │ │ └── DemoImage4.jpg │ └── DemoImage5.imageset │ │ ├── Contents.json │ │ └── DemoImage5.jpg ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── KeyboardView.h ├── KeyboardView.m ├── ViewController.h ├── ViewController.m └── main.m ├── TouchBarServer Helper ├── AppDelegate.h ├── AppDelegate.m ├── Info.plist └── main.m └── TouchBarServer ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets ├── AppIcon.appiconset │ ├── Contents.json │ ├── icon_128x128.png │ ├── icon_128x128@2x.png │ ├── icon_16x16.png │ ├── icon_16x16@2x.png │ ├── icon_256x256.png │ ├── icon_256x256@2x.png │ ├── icon_32x32.png │ ├── icon_32x32@2x.png │ ├── icon_512x512.png │ └── icon_512x512@2x.png └── Contents.json ├── Base.lproj └── MainMenu.xib ├── GlobalEventApplication.h ├── GlobalEventApplication.m ├── Info.plist ├── ModifierKeyController.h ├── ModifierKeyController.m ├── StartAtLoginController.h ├── StartAtLoginController.m ├── TouchBarView.h ├── TouchBarView.m ├── TouchBarWindow.h ├── TouchBarWindow.m ├── UsbDeviceController.h ├── UsbDeviceController.m └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | *.xcworkspace 15 | !default.xcworkspace 16 | xcuserdata 17 | profile 18 | *.moved-aside 19 | DerivedData/ 20 | 21 | # Release products 22 | TouchBarServer.xcarchive 23 | TouchBarServer.zip 24 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ### Please avoid duplicate issues 2 | 3 | Before submitting a new issue, please search previous issues first. You can do this on the [issues page](https://github.com/bikkelbroeders/TouchBarDemoApp/issues?q=is%3Aissue). 4 | -------------------------------------------------------------------------------- /Debug/TouchBarServer.app.dSYM/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleIdentifier 8 | com.apple.xcode.dsym.com.bikkelbroeders.TouchBarServer 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundlePackageType 12 | dSYM 13 | CFBundleSignature 14 | ???? 15 | CFBundleShortVersionString 16 | 1.6 17 | CFBundleVersion 18 | 1 19 | 20 | 21 | -------------------------------------------------------------------------------- /Debug/TouchBarServer.app.dSYM/Contents/Resources/DWARF/TouchBarServer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/Debug/TouchBarServer.app.dSYM/Contents/Resources/DWARF/TouchBarServer -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | PLEASE READ: 2 | Before submitting a new issue, make sure to search previous issues first. You can do this on the [issues page](https://github.com/bikkelbroeders/TouchBarDemoApp/issues?q=is%3Aissue). 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2016 Bikkelbroeders 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Touch Bar Demo App 2 | 3 | 4 | 5 | Touch Bar Demo App allows you to use your macOS Touch Bar from an iPad (through USB connection) or on-screen by pressing the Fn-key. It shows the original Apple Touch Bar, which changes dynamically based on the app you're currently using. With this demo app, you can try out the Touch Bar on any Mac that does not have a physical Touch Bar. 6 | 7 | Check out [this video](https://www.youtube.com/watch?v=RZLx03OPpUU) to see it in action. 8 | 9 | ## How to install 10 | 11 | 1. Make sure you have macOS Sierra 10.12.1 **build 16B2657** installed, which adds support for the Touch Bar to macOS. 12 | 13 | [You can download it from this link](https://support.apple.com/kb/dl1897). 14 | 15 | :warning: **Just having 10.12.1 is not enough, you need the right build number. 10.12.1 build 16B2555 does not have Touch Bar support, so it WILL NOT WORK!** 16 | 17 | You can check which build you have by clicking the version number in About This Mac: 18 | 19 | ![how to check macOS build number](http://g.recordit.co/9mz6r6t9rA.gif) 20 | 21 | 2. [Fetch the ZIP from Releases](https://github.com/bikkelbroeders/TouchBarDemoApp/releases/latest). 22 | 23 | - TouchBarServer.zip to run the Touch Bar on your Mac 24 | - Source code (zip) to build the iOS app 25 | 26 | 3. To run the Touch Bar on your Mac, put the app into your Applications folder and open it. Press the Fn-key to toggle the Touch Bar on and off. 27 | 28 | 4. To build the iOS app, open `TouchBar.xcodeproj`, connect your iOS device and select the TouchBarClient target and your device, like show here: 29 | 30 | 31 | 32 | To get the app installed on your iOS device, it needs to be properly signed. See [these sideloading instructions](https://www.reddit.com/r/sideloaded/wiki/how-to-sideload) to set this up. 33 | 34 | ## Authors 35 | 36 | * Andreas Verhoeven, 37 | * Robbert Klarenbeek, 38 | 39 | ## Credits 40 | 41 | * Thanks to [Alex Zielenski](https://twitter.com/#!/alexzielenski) for [StartAtLoginController](https://github.com/alexzielenski/StartAtLoginController), which ties together the ServiceManagement stuff without even a single line of code (gotta love KVO). 42 | 43 | * Thanks to [Aleksei Mazelyuk](https://dribbble.com/mazelyuk) for his [Touch bar for VK Messenger](https://dribbble.com/shots/3057522-Touch-bar-for-VK-Messenger), which was an inspiration for the app icon. 44 | 45 | * Thanks to [Rasmus Andersson](https://rsms.me/) for [peertalk](https://github.com/rsms/peertalk), which is used to communicate between the macOS and iOS apps through USB connection. 46 | 47 | * Thanks to [Bas van der Ploeg](http://basvanderploeg.nl) for testing and shooting a sample video. 48 | 49 | ## License 50 | 51 | Touch Bar Demo App is published under the [MIT License](http://www.opensource.org/licenses/mit-license.php). 52 | -------------------------------------------------------------------------------- /Resources/Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/Resources/Screenshot.png -------------------------------------------------------------------------------- /Resources/TouchBarIcon.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/Resources/TouchBarIcon.sketch -------------------------------------------------------------------------------- /Resources/Xcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/Resources/Xcode.png -------------------------------------------------------------------------------- /Scripts/generate_keyboard_layouts.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 58, 11 | 'ISO' => 59, 12 | 'JIS' => 60, 13 | ]; 14 | 15 | define('TOUCH_BAR_KEY_HEIGHT', 10); 16 | define('TOUCH_BAR_KEY_MARGIN', 3); 17 | define('EXTRA_TOP_SPACE', TOUCH_BAR_KEY_HEIGHT + TOUCH_BAR_KEY_MARGIN); 18 | define('FONT_SIZE_OFFSET', -2); 19 | define('KEY_WIDTH_INCREASE', 1); 20 | define('KEY_HEIGHT_INCREASE', 2); 21 | define('MARGIN_INCREASE', -0.5); 22 | define('HORIZONTAL_MARGIN_INCREASE', MARGIN_INCREASE + KEY_WIDTH_INCREASE / 2); 23 | define('VERTICAL_MARGIN_INCREASE', MARGIN_INCREASE + KEY_HEIGHT_INCREASE / 2); 24 | 25 | $hidToMac = [ 26 | 0x04 => [0x00, 'kVK_ANSI_A'], 27 | 0x05 => [0x0B, 'kVK_ANSI_B'], 28 | 0x06 => [0x08, 'kVK_ANSI_C'], 29 | 0x07 => [0x02, 'kVK_ANSI_D'], 30 | 0x08 => [0x0E, 'kVK_ANSI_E'], 31 | 0x09 => [0x03, 'kVK_ANSI_F'], 32 | 0x0A => [0x05, 'kVK_ANSI_G'], 33 | 0x0B => [0x04, 'kVK_ANSI_H'], 34 | 0x0C => [0x22, 'kVK_ANSI_I'], 35 | 0x0D => [0x26, 'kVK_ANSI_J'], 36 | 0x0E => [0x28, 'kVK_ANSI_K'], 37 | 0x0F => [0x25, 'kVK_ANSI_L'], 38 | 0x10 => [0x2E, 'kVK_ANSI_M'], 39 | 0x11 => [0x2D, 'kVK_ANSI_N'], 40 | 0x12 => [0x1F, 'kVK_ANSI_O'], 41 | 0x13 => [0x23, 'kVK_ANSI_P'], 42 | 0x14 => [0x0C, 'kVK_ANSI_Q'], 43 | 0x15 => [0x0F, 'kVK_ANSI_R'], 44 | 0x16 => [0x01, 'kVK_ANSI_S'], 45 | 0x17 => [0x11, 'kVK_ANSI_T'], 46 | 0x18 => [0x20, 'kVK_ANSI_U'], 47 | 0x19 => [0x09, 'kVK_ANSI_V'], 48 | 0x1A => [0x0D, 'kVK_ANSI_W'], 49 | 0x1B => [0x07, 'kVK_ANSI_X'], 50 | 0x1C => [0x10, 'kVK_ANSI_Y'], 51 | 0x1D => [0x06, 'kVK_ANSI_Z'], 52 | 0x1E => [0x12, 'kVK_ANSI_1'], 53 | 0x1F => [0x13, 'kVK_ANSI_2'], 54 | 0x20 => [0x14, 'kVK_ANSI_3'], 55 | 0x21 => [0x15, 'kVK_ANSI_4'], 56 | 0x22 => [0x17, 'kVK_ANSI_5'], 57 | 0x23 => [0x16, 'kVK_ANSI_6'], 58 | 0x24 => [0x1A, 'kVK_ANSI_7'], 59 | 0x25 => [0x1C, 'kVK_ANSI_8'], 60 | 0x26 => [0x19, 'kVK_ANSI_9'], 61 | 0x27 => [0x1D, 'kVK_ANSI_0'], 62 | 0x28 => [0x24, 'kVK_Return'], 63 | 0x29 => [0x35, 'kVK_Escape'], 64 | 0x2A => [0x33, 'kVK_Delete'], 65 | 0x2B => [0x30, 'kVK_Tab'], 66 | 0x2C => [0x31, 'kVK_Space'], 67 | 0x2D => [0x1B, 'kVK_ANSI_Minus'], 68 | 0x2E => [0x18, 'kVK_ANSI_Equal'], 69 | 0x2F => [0x21, 'kVK_ANSI_LeftBracket'], 70 | 0x30 => [0x1E, 'kVK_ANSI_RightBracket'], 71 | 0x31 => [0x2A, 'kVK_ANSI_Backslash'], 72 | 0x33 => [0x29, 'kVK_ANSI_Semicolon'], 73 | 0x34 => [0x27, 'kVK_ANSI_Quote'], 74 | 0x35 => [0x32, 'kVK_ANSI_Grave'], 75 | 0x36 => [0x2B, 'kVK_ANSI_Comma'], 76 | 0x37 => [0x2F, 'kVK_ANSI_Period'], 77 | 0x38 => [0x2C, 'kVK_ANSI_Slash'], 78 | 0x39 => [0x39, 'kVK_CapsLock'], 79 | 0x3A => [0x7A, 'kVK_F1'], 80 | 0x3B => [0x78, 'kVK_F2'], 81 | 0x3C => [0x63, 'kVK_F3'], 82 | 0x3D => [0x76, 'kVK_F4'], 83 | 0x3E => [0x60, 'kVK_F5'], 84 | 0x3F => [0x61, 'kVK_F6'], 85 | 0x40 => [0x62, 'kVK_F7'], 86 | 0x41 => [0x64, 'kVK_F8'], 87 | 0x42 => [0x65, 'kVK_F9'], 88 | 0x43 => [0x6D, 'kVK_F10'], 89 | 0x44 => [0x67, 'kVK_F11'], 90 | 0x45 => [0x6F, 'kVK_F12'], 91 | 0x4A => [0x73, 'kVK_Home'], 92 | 0x4B => [0x74, 'kVK_PageUp'], 93 | 0x4C => [0x75, 'kVK_ForwardDelete'], 94 | 0x4D => [0x77, 'kVK_End'], 95 | 0x4E => [0x79, 'kVK_PageDown'], 96 | 0x4F => [0x7C, 'kVK_RightArrow'], 97 | 0x50 => [0x7B, 'kVK_LeftArrow'], 98 | 0x51 => [0x7D, 'kVK_DownArrow'], 99 | 0x52 => [0x7E, 'kVK_UpArrow'], 100 | 0x54 => [0x4B, 'kVK_ANSI_KeypadDivide'], 101 | 0x55 => [0x43, 'kVK_ANSI_KeypadMultiply'], 102 | 0x56 => [0x4E, 'kVK_ANSI_KeypadMinus'], 103 | 0x57 => [0x45, 'kVK_ANSI_KeypadPlus'], 104 | 0x58 => [0x4C, 'kVK_ANSI_KeypadEnter'], 105 | 0x59 => [0x53, 'kVK_ANSI_Keypad1'], 106 | 0x5A => [0x54, 'kVK_ANSI_Keypad2'], 107 | 0x5B => [0x55, 'kVK_ANSI_Keypad3'], 108 | 0x5C => [0x56, 'kVK_ANSI_Keypad4'], 109 | 0x5D => [0x57, 'kVK_ANSI_Keypad5'], 110 | 0x5E => [0x58, 'kVK_ANSI_Keypad6'], 111 | 0x5F => [0x59, 'kVK_ANSI_Keypad7'], 112 | 0x60 => [0x5B, 'kVK_ANSI_Keypad8'], 113 | 0x61 => [0x5C, 'kVK_ANSI_Keypad9'], 114 | 0x62 => [0x52, 'kVK_ANSI_Keypad0'], 115 | 0x63 => [0x41, 'kVK_ANSI_KeypadDecimal'], 116 | 0x64 => [0x0A, 'kVK_ISO_Section'], 117 | 0x67 => [0x51, 'kVK_ANSI_KeypadEquals'], 118 | 0x68 => [0x69, 'kVK_F13'], 119 | 0x69 => [0x6B, 'kVK_F14'], 120 | 0x6A => [0x71, 'kVK_F15'], 121 | 0x6B => [0x6A, 'kVK_F16'], 122 | 0x6C => [0x40, 'kVK_F17'], 123 | 0x6D => [0x4F, 'kVK_F18'], 124 | 0x6E => [0x50, 'kVK_F19'], 125 | 0x6F => [0x5A, 'kVK_F20'], 126 | 0x75 => [0x72, 'kVK_Help'], 127 | 0x7F => [0x4A, 'kVK_Mute'], 128 | 0x80 => [0x48, 'kVK_VolumeUp'], 129 | 0x81 => [0x49, 'kVK_VolumeDown'], 130 | 0x85 => [0x5F, 'kVK_JIS_KeypadComma'], 131 | 0x87 => [0x5E, 'kVK_JIS_Underscore'], 132 | 0x89 => [0x5D, 'kVK_JIS_Yen'], 133 | 0x90 => [0x66, 'kVK_JIS_Eisu'], 134 | 0x94 => [0x68, 'kVK_JIS_Kana'], 135 | 0xD8 => [0x47, 'kVK_ANSI_KeypadClear'], 136 | 0xE0 => [0x3B, 'kVK_Control'], 137 | 0xE1 => [0x38, 'kVK_Shift'], 138 | 0xE2 => [0x3A, 'kVK_Option'], 139 | 0xE3 => [0x37, 'kVK_Command'], 140 | 0xE4 => [0x3E, 'kVK_RightControl'], 141 | 0xE5 => [0x3C, 'kVK_RightShift'], 142 | 0xE6 => [0x3D, 'kVK_RightOption'], 143 | 0xE7 => [0x36, 'kVK_RightCommand'], 144 | 0xE8 => [0x3F, 'kVK_Function'], 145 | ]; 146 | 147 | $keyConstantToModifierFlag = [ 148 | 'kVK_CapsLock' => 'KeyEventModifierFlagCapsLock', 149 | 'kVK_Shift' => 'KeyEventModifierFlagShift', 150 | 'kVK_RightShift' => 'KeyEventModifierFlagShift', 151 | 'kVK_Control' => 'KeyEventModifierFlagControl', 152 | 'kVK_RightControl' => 'KeyEventModifierFlagControl', 153 | 'kVK_Option' => 'KeyEventModifierFlagOption', 154 | 'kVK_RightOption' => 'KeyEventModifierFlagOption', 155 | 'kVK_Command' => 'KeyEventModifierFlagCommand', 156 | 'kVK_RightCommand' => 'KeyEventModifierFlagCommand', 157 | 'kVK_Function' => 'KeyEventModifierFlagFunction', 158 | ]; 159 | 160 | foreach ($layouts as $type => $id) { 161 | $file = "/System/Library/Input Methods/KeyboardViewer.app/Contents/Resources/KeyboardLayoutDefinition{$id}.svg"; 162 | if (!file_exists($file)) { 163 | fprintf(STDERR, "Error: Layout definition SVG #{$id} ({$type}) not found!\n"); 164 | exit(1); 165 | } 166 | 167 | $svg = new SimpleXMLElement(file_get_contents($file)); 168 | 169 | $viewBox = (string)$svg['viewBox']; 170 | $viewBoxElements = explode(' ', $viewBox); 171 | $width = $viewBoxElements[2]; 172 | $width += HORIZONTAL_MARGIN_INCREASE * 2; 173 | $height = $viewBoxElements[3]; 174 | $height += VERTICAL_MARGIN_INCREASE * 2; 175 | $height += EXTRA_TOP_SPACE; 176 | $size = "CGSizeMake({$width}, {$height})"; 177 | 178 | foreach ($hidToMac as $hidCode => $macCode) { 179 | list($keyCode, $keyConstant) = $macCode; 180 | if ($keyConstant == 'kVK_DownArrow') { 181 | $arrowDownHidCode = $hidCode; 182 | } elseif ($keyConstant == 'kVK_UpArrow') { 183 | $arrowUpHidCode = $hidCode; 184 | } 185 | } 186 | $svg->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg'); 187 | $arrowDownRect = $svg->xpath('//svg:g[@keyCode=' . $arrowDownHidCode . ']/svg:rect')[0]; 188 | $arrowUpRect = $svg->xpath('//svg:g[@keyCode=' . $arrowUpHidCode . ']/svg:rect')[0]; 189 | $arrowCenter = ((string)$arrowUpRect['y'] + (string)$arrowUpRect['height'] + (string)$arrowDownRect['y']) / 2; 190 | $arrowCenter = correctY($arrowCenter); 191 | 192 | $keyCodes = ''; 193 | $modifierFlags = ''; 194 | $bezierPaths = ''; 195 | $textPositions = ''; 196 | $fontSizes = ''; 197 | 198 | $numberOfKeys = 0; 199 | foreach ($svg->g as $g) { 200 | $keyIndex = $numberOfKeys; 201 | 202 | $hidCode = (string)$g['keyCode']; 203 | list($keyCode, $keyConstant) = $hidToMac[(int)$hidCode]; 204 | 205 | if ($g->text->count() != 1) continue; 206 | 207 | if ($g->rect->count() == 1) { 208 | $bezierPath = bezierPathForSvgRect($g->rect[0], $keyConstant == 'kVK_DownArrow', $keyConstant == 'kVK_UpArrow'); 209 | } else if ($g->path->count() == 1) { 210 | $bezierPath = bezierPathForSvgPath($g->path[0]); 211 | } else { 212 | continue; 213 | } 214 | 215 | $text = $g->text[0]; 216 | $x = correctX((string)$text['x']); 217 | $y = correctY((string)$text['y']); 218 | 219 | if ($keyConstant == 'kVK_DownArrow' || $keyConstant == 'kVK_UpArrow') $y += $centerOffset; 220 | 221 | $fontSize = (string)$text['font-size'] + FONT_SIZE_OFFSET; 222 | $textPosition = "CGPointMake({$x}, {$y})"; 223 | 224 | $keyCodes .= " case " . pad($keyIndex) . ": return " . hex($keyCode) . "; // {$keyConstant}\n"; 225 | $bezierPaths .= " case " . pad($keyIndex) . ": {$bezierPath}\n"; 226 | $textPositions .= " case " . pad($keyIndex) . ": return {$textPosition};\n"; 227 | $fontSizes .= " case " . pad($keyIndex) . ": return {$fontSize};\n"; 228 | 229 | if (array_key_exists($keyConstant, $keyConstantToModifierFlag)) { 230 | $modifierFlags .= " case " . pad($keyIndex) . ": return {$keyConstantToModifierFlag[$keyConstant]};\n"; 231 | } 232 | 233 | $numberOfKeys++; 234 | } 235 | 236 | // Add Touch Bar "key" 237 | { 238 | $keyIndex = $numberOfKeys; 239 | $bezierPath = bezierPathForSvgRect([ 240 | 'x' => 1, 241 | 'y' => 1 - TOUCH_BAR_KEY_HEIGHT - TOUCH_BAR_KEY_MARGIN, 242 | 'width' => $viewBoxElements[2] - 2, 243 | 'height' => TOUCH_BAR_KEY_HEIGHT, 244 | 'rx' => 2, 245 | 'ry' => 2, 246 | ]); 247 | $bezierPaths .= " case {$keyIndex}: {$bezierPath}\n"; 248 | $numberOfKeys++; 249 | } 250 | 251 | $keyCodes = rtrim($keyCodes); 252 | $modifierFlags = rtrim($modifierFlags); 253 | $bezierPaths = rtrim($bezierPaths); 254 | $textPositions = rtrim($textPositions); 255 | $fontSizes = rtrim($fontSizes); 256 | 257 | $header = << 0) { 381 | $centerOffset = $d / 2; 382 | $h -= $d; 383 | $y = $arrowCenter; 384 | } 385 | } elseif ($isArrowUp) { 386 | $d = $y + $h - $arrowCenter; 387 | if ($d > 0) { 388 | $centerOffset = -$d / 2; 389 | $h -= $d; 390 | } 391 | } 392 | 393 | return "return [UIBezierPath bezierPathWithRoundedRect:CGRectMake({$x}, {$y}, {$w}, {$h}) cornerRadius:{$r}];"; 394 | } 395 | 396 | function boundariesForSvgPathDescriptor($descriptor) { 397 | $minX = 99999; 398 | $minY = 99999; 399 | $maxX = -99999; 400 | $maxY = -99999; 401 | while (!empty($descriptor)) { 402 | $x = null; 403 | $y = null; 404 | $command = array_shift($descriptor); 405 | switch ($command) { 406 | case 'A': 407 | array_shift($descriptor); 408 | array_shift($descriptor); 409 | array_shift($descriptor); 410 | array_shift($descriptor); 411 | array_shift($descriptor); 412 | $x = array_shift($descriptor); 413 | $y = array_shift($descriptor); 414 | break; 415 | case 'L': 416 | $x = array_shift($descriptor); 417 | $y = array_shift($descriptor); 418 | break; 419 | case 'M': 420 | $x = array_shift($descriptor); 421 | $y = array_shift($descriptor); 422 | break; 423 | default: 424 | break; 425 | } 426 | if ($x !== null) { 427 | $minX = min($minX, $x); 428 | $minY = min($minY, $y); 429 | $maxX = max($maxX, $x); 430 | $maxY = max($maxY, $y); 431 | } 432 | } 433 | return [$minX, $minY, $maxX, $maxY]; 434 | } 435 | 436 | function stretchX($x, $minX, $maxX) { 437 | $dx = ($x - $minX) / ($maxX - $minX); 438 | return $x + KEY_WIDTH_INCREASE / 2 * ($dx < 0.5 ? -1 : 1); 439 | } 440 | 441 | function stretchY($y, $minY, $maxY) { 442 | $dy = ($y - $minY) / ($maxY - $minY); 443 | return $y + KEY_HEIGHT_INCREASE / 2 * ($dy < 0.25 ? -1 : 1); 444 | } 445 | 446 | function bezierPathForSvgPath($path) { 447 | $i = " "; 448 | $p = "{\n"; 449 | $p .= "{$i}UIBezierPath *path = [UIBezierPath new];\n"; 450 | 451 | $descriptor = trim((string)$path['d']); 452 | $descriptor = str_replace(',', ' ', $descriptor); 453 | $descriptor = preg_replace('/\s\s+/', ' ', $descriptor); 454 | $descriptor = explode(' ', $descriptor); 455 | 456 | list($minX, $minY, $maxX, $maxY) = boundariesForSvgPathDescriptor($descriptor); 457 | 458 | while (!empty($descriptor)) { 459 | $command = array_shift($descriptor); 460 | switch ($command) { 461 | case 'A': 462 | // Simplification assumptions: 463 | // rx == ry 464 | // phi == 0 465 | // largeArcFlag == false 466 | 467 | $rx = array_shift($descriptor); 468 | $ry = array_shift($descriptor); // Ignored, assumed equal to $rx 469 | $phi = array_shift($descriptor); // Ignored, assumed 0 470 | $largeArcFlag = array_shift($descriptor) != 0; // Ignored, assumed false 471 | $sweepFlag = array_shift($descriptor) != 0; 472 | $x = correctX(stretchX(array_shift($descriptor), $minX, $maxX)); 473 | $y = correctY(stretchY(array_shift($descriptor), $minY, $maxY)); 474 | 475 | $x1p = ($lastX - $x) / 2; 476 | $y1p = ($lastY - $y) / 2; 477 | 478 | $rx_2 = $rx * $rx; 479 | $xp_2 = $x1p * $x1p; 480 | $yp_2 = $y1p * $y1p; 481 | 482 | $delta = ($xp_2 + $yp_2) / $rx_2; 483 | 484 | if ($delta > 1.0) { 485 | $rx *= sqrt($delta); 486 | $rx_2 = $rx * $rx; 487 | } 488 | 489 | $numerator = $rx_2 * ($rx_2 - $yp_2 - $xp_2); 490 | $denom = $rx_2 * ($xp_2 + $yp_2); 491 | $numerator = max(0, $numerator); 492 | $lhs = sqrt($numerator / $denom) * ($sweepFlag ? 1 : -1); 493 | 494 | $cx = $lhs * $y1p + ($lastX + $x) / 2; 495 | $cy = $lhs * -$x1p + ($lastY + $y) / 2; 496 | 497 | $startAngle = atan2($lastY - $cy, $lastX - $cx); 498 | $endAngle = atan2($y - $cy, $x - $cx); 499 | 500 | $clockWise = $sweepFlag ? 'YES' : 'NO'; 501 | $p .= "{$i}[path addArcWithCenter:CGPointMake({$cx}, {$cy}) radius:{$rx} startAngle:${startAngle} endAngle:${endAngle} clockwise:{$clockWise}];\n"; 502 | break; 503 | 504 | case 'L': 505 | $x = correctX(stretchX(array_shift($descriptor), $minX, $maxX)); 506 | $y = correctY(stretchY(array_shift($descriptor), $minY, $maxY)); 507 | $p .= "{$i}[path addLineToPoint:CGPointMake({$x}, {$y})];\n"; 508 | break; 509 | case 'M': 510 | $x = correctX(stretchX(array_shift($descriptor), $minX, $maxX)); 511 | $y = correctY(stretchY(array_shift($descriptor), $minY, $maxY)); 512 | $p .= "{$i}[path moveToPoint:CGPointMake({$x}, {$y})];\n"; 513 | break; 514 | case 'Z': 515 | case 'z': 516 | $p .= "{$i}[path closePath];\n"; 517 | break; 518 | } 519 | $lastX = $x; 520 | $lastY = $y; 521 | } 522 | 523 | $p .= "{$i}return path;\n"; 524 | $p .= " }"; 525 | return $p; 526 | } 527 | 528 | function pad($x) { 529 | return str_pad($x, 2, ' ', STR_PAD_LEFT); 530 | } 531 | 532 | function hex($x) { 533 | return '0x' . str_pad(strtoupper(dechex($x)), 2, '0', STR_PAD_LEFT); 534 | } 535 | -------------------------------------------------------------------------------- /Scripts/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd `dirname ${0}`/.. 4 | 5 | repo="https://github.com/bikkelbroeders/TouchBarDemoApp" 6 | name="Touch Bar Demo App" 7 | project="TouchBar.xcodeproj" 8 | app="TouchBarServer" 9 | 10 | git diff-index --quiet HEAD -- 11 | if [ ${?} -ne 0 ] 12 | then 13 | echo 1>&2 "Error: uncomitted changes found; please commit, discard or stash them first." 14 | exit 1 15 | fi 16 | 17 | plist=`pwd`"/${app}/Info" 18 | previous_version=`defaults read "${plist}" CFBundleShortVersionString` 19 | 20 | version="${1}" 21 | if [ -z "${version}" ] 22 | then 23 | major=`echo "${previous_version}" | cut -d. -f1` 24 | minor=`echo "${previous_version}" | cut -d. -f2` 25 | minor=`echo ${minor}+1 | bc` 26 | version="${major}.${minor}" 27 | fi 28 | 29 | version=`echo ${version} | sed 's/^v//'` 30 | 31 | set -e 32 | set -x 33 | 34 | # Put new version in the app plist 35 | plutil -replace CFBundleShortVersionString -string "${version}" "${app}/Info.plist" 36 | 37 | # Build release archive 38 | xcodebuild -quiet -project "${project}" -archivePath "${app}" -scheme "${app}" archive 39 | 40 | # Zip the app 41 | zip=`pwd`"/${app}.zip" 42 | pushd "${app}.xcarchive/Products/Applications" > /dev/null 43 | zip -q -r "${zip}" "${app}.app" 44 | popd > /dev/null 45 | 46 | # Store the dSYM for debugging 47 | rm -Rf "Debug/${app}.app.dSYM" 48 | mv "${app}.xcarchive/dSYMs/${app}.app.dSYM" Debug/ 49 | 50 | # Remove the created archive 51 | rm -Rf "${app}.xcarchive" 52 | 53 | # Make a release commit + tag 54 | git add Debug/ 55 | git add "${app}/Info.plist" 56 | git commit -q -m "Release v${version}" 57 | git tag "v${version}" 58 | 59 | set +x 60 | 61 | # Print info 62 | echo 63 | echo "Finished creating release v${version} !" 64 | echo 65 | echo "Changes:" 66 | git log "v${previous_version}..v${version}^" --oneline 67 | echo 68 | echo "To publish this release:" 69 | echo " git push -u origin master --tags" 70 | echo " open ${repo}/releases/new?tag=v${version}" 71 | echo " # use release title '${name} v${version}'" 72 | echo " # attach ${app}.zip" 73 | echo 74 | echo "To undo this release (only while not yet published!):" 75 | echo " git tag -d v${version}" 76 | echo " git reset --hard HEAD^" 77 | echo " rm ${app}.zip" 78 | -------------------------------------------------------------------------------- /Shared/Generated/KeyboardLayoutANSI.h: -------------------------------------------------------------------------------- 1 | // 2 | // KeyboardLayoutANSI.h 3 | // TouchBar 4 | // 5 | // Generated by generate_keyboard_layouts.sh. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import "KeyboardLayout.h" 10 | 11 | @interface KeyboardLayoutANSI : KeyboardLayout 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Shared/Generated/KeyboardLayoutANSI.m: -------------------------------------------------------------------------------- 1 | // 2 | // KeyboardLayoutANSI.m 3 | // TouchBar 4 | // 5 | // Generated by generate_keyboard_layouts.sh. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import "KeyboardLayoutANSI.h" 10 | 11 | @implementation KeyboardLayoutANSI 12 | 13 | /************************************************************* 14 | * * 15 | * WARNING: this is an auto-generated file. DO NOT EDIT! * 16 | * * 17 | *************************************************************/ 18 | 19 | - (KeyboardLayoutType)type { 20 | return KeyboardLayoutTypeANSI; 21 | } 22 | 23 | - (UInt8)macKbdType { 24 | return 58; 25 | } 26 | 27 | - (CGSize)size { 28 | return CGSizeMake(290, 113); 29 | } 30 | 31 | - (NSUInteger)numberOfKeys { 32 | return 65; 33 | } 34 | 35 | - (KeyCode)keyCodeForKeyIndex:(NSUInteger)keyIndex { 36 | switch (keyIndex) { 37 | case 0: return 0x32; // kVK_ANSI_Grave 38 | case 1: return 0x12; // kVK_ANSI_1 39 | case 2: return 0x13; // kVK_ANSI_2 40 | case 3: return 0x14; // kVK_ANSI_3 41 | case 4: return 0x15; // kVK_ANSI_4 42 | case 5: return 0x17; // kVK_ANSI_5 43 | case 6: return 0x16; // kVK_ANSI_6 44 | case 7: return 0x1A; // kVK_ANSI_7 45 | case 8: return 0x1C; // kVK_ANSI_8 46 | case 9: return 0x19; // kVK_ANSI_9 47 | case 10: return 0x1D; // kVK_ANSI_0 48 | case 11: return 0x1B; // kVK_ANSI_Minus 49 | case 12: return 0x18; // kVK_ANSI_Equal 50 | case 13: return 0x2A; // kVK_ANSI_Backslash 51 | case 14: return 0x1E; // kVK_ANSI_RightBracket 52 | case 15: return 0x21; // kVK_ANSI_LeftBracket 53 | case 16: return 0x23; // kVK_ANSI_P 54 | case 17: return 0x1F; // kVK_ANSI_O 55 | case 18: return 0x22; // kVK_ANSI_I 56 | case 19: return 0x20; // kVK_ANSI_U 57 | case 20: return 0x10; // kVK_ANSI_Y 58 | case 21: return 0x11; // kVK_ANSI_T 59 | case 22: return 0x0F; // kVK_ANSI_R 60 | case 23: return 0x0E; // kVK_ANSI_E 61 | case 24: return 0x0D; // kVK_ANSI_W 62 | case 25: return 0x0C; // kVK_ANSI_Q 63 | case 26: return 0x00; // kVK_ANSI_A 64 | case 27: return 0x01; // kVK_ANSI_S 65 | case 28: return 0x02; // kVK_ANSI_D 66 | case 29: return 0x03; // kVK_ANSI_F 67 | case 30: return 0x05; // kVK_ANSI_G 68 | case 31: return 0x04; // kVK_ANSI_H 69 | case 32: return 0x26; // kVK_ANSI_J 70 | case 33: return 0x28; // kVK_ANSI_K 71 | case 34: return 0x25; // kVK_ANSI_L 72 | case 35: return 0x29; // kVK_ANSI_Semicolon 73 | case 36: return 0x27; // kVK_ANSI_Quote 74 | case 37: return 0x2C; // kVK_ANSI_Slash 75 | case 38: return 0x2F; // kVK_ANSI_Period 76 | case 39: return 0x2B; // kVK_ANSI_Comma 77 | case 40: return 0x2E; // kVK_ANSI_M 78 | case 41: return 0x2D; // kVK_ANSI_N 79 | case 42: return 0x0B; // kVK_ANSI_B 80 | case 43: return 0x09; // kVK_ANSI_V 81 | case 44: return 0x08; // kVK_ANSI_C 82 | case 45: return 0x07; // kVK_ANSI_X 83 | case 46: return 0x06; // kVK_ANSI_Z 84 | case 47: return 0x3F; // kVK_Function 85 | case 48: return 0x3B; // kVK_Control 86 | case 49: return 0x3A; // kVK_Option 87 | case 50: return 0x3A; // kVK_Option 88 | case 51: return 0x37; // kVK_Command 89 | case 52: return 0x37; // kVK_Command 90 | case 53: return 0x7B; // kVK_LeftArrow 91 | case 54: return 0x7D; // kVK_DownArrow 92 | case 55: return 0x7C; // kVK_RightArrow 93 | case 56: return 0x7E; // kVK_UpArrow 94 | case 57: return 0x30; // kVK_Tab 95 | case 58: return 0x33; // kVK_Delete 96 | case 59: return 0x39; // kVK_CapsLock 97 | case 60: return 0x24; // kVK_Return 98 | case 61: return 0x38; // kVK_Shift 99 | case 62: return 0x38; // kVK_Shift 100 | case 63: return 0x31; // kVK_Space 101 | default: return [super keyCodeForKeyIndex:keyIndex]; 102 | } 103 | } 104 | 105 | - (KeyEventModifierFlags)modifierFlagForKeyIndex:(NSUInteger)keyIndex { 106 | switch (keyIndex) { 107 | case 47: return KeyEventModifierFlagFunction; 108 | case 48: return KeyEventModifierFlagControl; 109 | case 49: return KeyEventModifierFlagOption; 110 | case 50: return KeyEventModifierFlagOption; 111 | case 51: return KeyEventModifierFlagCommand; 112 | case 52: return KeyEventModifierFlagCommand; 113 | case 59: return KeyEventModifierFlagCapsLock; 114 | case 61: return KeyEventModifierFlagShift; 115 | case 62: return KeyEventModifierFlagShift; 116 | default: return [super modifierFlagForKeyIndex:keyIndex]; 117 | } 118 | } 119 | 120 | #if TARGET_OS_IPHONE 121 | - (UIBezierPath *)bezierPathForKeyIndex:(NSUInteger)keyIndex { 122 | switch (keyIndex) { 123 | case 0: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.5, 13.5, 19, 19) cornerRadius:2]; 124 | case 1: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20.5, 13.5, 19, 19) cornerRadius:2]; 125 | case 2: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(40.5, 13.5, 19, 19) cornerRadius:2]; 126 | case 3: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(60.5, 13.5, 19, 19) cornerRadius:2]; 127 | case 4: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(80.5, 13.5, 19, 19) cornerRadius:2]; 128 | case 5: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(100.5, 13.5, 19, 19) cornerRadius:2]; 129 | case 6: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(120.5, 13.5, 19, 19) cornerRadius:2]; 130 | case 7: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(140.5, 13.5, 19, 19) cornerRadius:2]; 131 | case 8: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(160.5, 13.5, 19, 19) cornerRadius:2]; 132 | case 9: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(180.5, 13.5, 19, 19) cornerRadius:2]; 133 | case 10: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(200.5, 13.5, 19, 19) cornerRadius:2]; 134 | case 11: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(220.5, 13.5, 19, 19) cornerRadius:2]; 135 | case 12: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(240.5, 13.5, 19, 19) cornerRadius:2]; 136 | case 13: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(270.5, 33.5, 19, 19) cornerRadius:2]; 137 | case 14: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(250.5, 33.5, 19, 19) cornerRadius:2]; 138 | case 15: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(230.5, 33.5, 19, 19) cornerRadius:2]; 139 | case 16: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(210.5, 33.5, 19, 19) cornerRadius:2]; 140 | case 17: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(190.5, 33.5, 19, 19) cornerRadius:2]; 141 | case 18: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(170.5, 33.5, 19, 19) cornerRadius:2]; 142 | case 19: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(150.5, 33.5, 19, 19) cornerRadius:2]; 143 | case 20: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(130.5, 33.5, 19, 19) cornerRadius:2]; 144 | case 21: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(110.5, 33.5, 19, 19) cornerRadius:2]; 145 | case 22: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(90.5, 33.5, 19, 19) cornerRadius:2]; 146 | case 23: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(70.5, 33.5, 19, 19) cornerRadius:2]; 147 | case 24: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50.5, 33.5, 19, 19) cornerRadius:2]; 148 | case 25: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(30.5, 33.5, 19, 19) cornerRadius:2]; 149 | case 26: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(35.5, 53.5, 19, 19) cornerRadius:2]; 150 | case 27: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(55.5, 53.5, 19, 19) cornerRadius:2]; 151 | case 28: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(75.5, 53.5, 19, 19) cornerRadius:2]; 152 | case 29: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(95.5, 53.5, 19, 19) cornerRadius:2]; 153 | case 30: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(115.5, 53.5, 19, 19) cornerRadius:2]; 154 | case 31: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(135.5, 53.5, 19, 19) cornerRadius:2]; 155 | case 32: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(155.5, 53.5, 19, 19) cornerRadius:2]; 156 | case 33: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(175.5, 53.5, 19, 19) cornerRadius:2]; 157 | case 34: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(195.5, 53.5, 19, 19) cornerRadius:2]; 158 | case 35: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(215.5, 53.5, 19, 19) cornerRadius:2]; 159 | case 36: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(235.5, 53.5, 19, 19) cornerRadius:2]; 160 | case 37: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(225.5, 73.5, 19, 19) cornerRadius:2]; 161 | case 38: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(205.5, 73.5, 19, 19) cornerRadius:2]; 162 | case 39: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(185.5, 73.5, 19, 19) cornerRadius:2]; 163 | case 40: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(165.5, 73.5, 19, 19) cornerRadius:2]; 164 | case 41: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(145.5, 73.5, 19, 19) cornerRadius:2]; 165 | case 42: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(125.5, 73.5, 19, 19) cornerRadius:2]; 166 | case 43: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(105.5, 73.5, 19, 19) cornerRadius:2]; 167 | case 44: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(85.5, 73.5, 19, 19) cornerRadius:2]; 168 | case 45: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(65.5, 73.5, 19, 19) cornerRadius:2]; 169 | case 46: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(45.5, 73.5, 19, 19) cornerRadius:2]; 170 | case 47: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.5, 93.5, 19, 19) cornerRadius:2]; 171 | case 48: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20.5, 93.5, 19, 19) cornerRadius:2]; 172 | case 49: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(40.5, 93.5, 19, 19) cornerRadius:2]; 173 | case 50: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(210.5, 93.5, 19, 19) cornerRadius:2]; 174 | case 51: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(60.5, 93.5, 24, 19) cornerRadius:2]; 175 | case 52: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(185.5, 93.5, 24, 19) cornerRadius:2]; 176 | case 53: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(230.5, 93.5, 19, 19) cornerRadius:2]; 177 | case 54: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(250.5, 103, 19, 9.5) cornerRadius:2]; 178 | case 55: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(270.5, 93.5, 19, 19) cornerRadius:2]; 179 | case 56: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(250.5, 93.5, 19, 9.5) cornerRadius:2]; 180 | case 57: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.5, 33.5, 29, 19) cornerRadius:2]; 181 | case 58: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(260.5, 13.5, 29, 19) cornerRadius:2]; 182 | case 59: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.5, 53.5, 34, 19) cornerRadius:2]; 183 | case 60: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(255.5, 53.5, 34, 19) cornerRadius:2]; 184 | case 61: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.5, 73.5, 44, 19) cornerRadius:2]; 185 | case 62: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(245.5, 73.5, 44, 19) cornerRadius:2]; 186 | case 63: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(85.5, 93.5, 99, 19) cornerRadius:2]; 187 | case 64: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.5, 0.5, 289, 12) cornerRadius:2]; 188 | default: return [super bezierPathForKeyIndex:keyIndex]; 189 | } 190 | } 191 | #endif 192 | 193 | - (CGPoint)textPositionForKeyIndex:(NSUInteger)keyIndex { 194 | switch (keyIndex) { 195 | case 0: return CGPointMake(10, 22.5); 196 | case 1: return CGPointMake(30, 21.5); 197 | case 2: return CGPointMake(50, 21.5); 198 | case 3: return CGPointMake(70, 21.5); 199 | case 4: return CGPointMake(90, 21.5); 200 | case 5: return CGPointMake(110, 21.5); 201 | case 6: return CGPointMake(130, 21.5); 202 | case 7: return CGPointMake(150, 21.5); 203 | case 8: return CGPointMake(170, 21.5); 204 | case 9: return CGPointMake(190, 21.5); 205 | case 10: return CGPointMake(210, 21.5); 206 | case 11: return CGPointMake(230, 21.5); 207 | case 12: return CGPointMake(250, 21.5); 208 | case 13: return CGPointMake(280, 41.5); 209 | case 14: return CGPointMake(260, 41.5); 210 | case 15: return CGPointMake(240, 41.5); 211 | case 16: return CGPointMake(220, 41.5); 212 | case 17: return CGPointMake(200, 41.5); 213 | case 18: return CGPointMake(180, 41.5); 214 | case 19: return CGPointMake(160, 41.5); 215 | case 20: return CGPointMake(140, 41.5); 216 | case 21: return CGPointMake(120, 41.5); 217 | case 22: return CGPointMake(100, 41.5); 218 | case 23: return CGPointMake(80, 41.5); 219 | case 24: return CGPointMake(60, 41.5); 220 | case 25: return CGPointMake(40, 41.5); 221 | case 26: return CGPointMake(45, 61.5); 222 | case 27: return CGPointMake(65, 61.5); 223 | case 28: return CGPointMake(85, 61.5); 224 | case 29: return CGPointMake(105, 61.5); 225 | case 30: return CGPointMake(125, 61.5); 226 | case 31: return CGPointMake(145, 61.5); 227 | case 32: return CGPointMake(165, 61.5); 228 | case 33: return CGPointMake(185, 61.5); 229 | case 34: return CGPointMake(205, 61.5); 230 | case 35: return CGPointMake(225, 61.5); 231 | case 36: return CGPointMake(245, 61.5); 232 | case 37: return CGPointMake(235, 81.5); 233 | case 38: return CGPointMake(215, 81.5); 234 | case 39: return CGPointMake(195, 81.5); 235 | case 40: return CGPointMake(175, 81.5); 236 | case 41: return CGPointMake(155, 81.5); 237 | case 42: return CGPointMake(135, 81.5); 238 | case 43: return CGPointMake(115, 81.5); 239 | case 44: return CGPointMake(95, 81.5); 240 | case 45: return CGPointMake(75, 81.5); 241 | case 46: return CGPointMake(55, 81.5); 242 | case 47: return CGPointMake(10, 102.5); 243 | case 48: return CGPointMake(30, 102.5); 244 | case 49: return CGPointMake(50, 102.5); 245 | case 50: return CGPointMake(220, 102.5); 246 | case 51: return CGPointMake(72, 102.5); 247 | case 52: return CGPointMake(198, 102.5); 248 | case 53: return CGPointMake(240, 102.5); 249 | case 54: return CGPointMake(260, 107.75); 250 | case 55: return CGPointMake(280, 102.5); 251 | case 56: return CGPointMake(260, 97.25); 252 | case 57: return CGPointMake(15, 42.5); 253 | case 58: return CGPointMake(275, 22.5); 254 | case 59: return CGPointMake(18, 62.5); 255 | case 60: return CGPointMake(272, 62.5); 256 | case 61: return CGPointMake(22, 82.5); 257 | case 62: return CGPointMake(268, 82.5); 258 | case 63: return CGPointMake(135, 102.5); 259 | default: return [super textPositionForKeyIndex:keyIndex]; 260 | } 261 | } 262 | 263 | - (CGFloat)fontSizeForKeyIndex:(NSUInteger)keyIndex { 264 | switch (keyIndex) { 265 | case 0: return 9; 266 | case 1: return 8; 267 | case 2: return 8; 268 | case 3: return 8; 269 | case 4: return 8; 270 | case 5: return 8; 271 | case 6: return 8; 272 | case 7: return 8; 273 | case 8: return 8; 274 | case 9: return 8; 275 | case 10: return 8; 276 | case 11: return 8; 277 | case 12: return 8; 278 | case 13: return 8; 279 | case 14: return 8; 280 | case 15: return 8; 281 | case 16: return 9; 282 | case 17: return 9; 283 | case 18: return 9; 284 | case 19: return 9; 285 | case 20: return 9; 286 | case 21: return 9; 287 | case 22: return 9; 288 | case 23: return 9; 289 | case 24: return 9; 290 | case 25: return 9; 291 | case 26: return 9; 292 | case 27: return 9; 293 | case 28: return 9; 294 | case 29: return 9; 295 | case 30: return 9; 296 | case 31: return 9; 297 | case 32: return 9; 298 | case 33: return 9; 299 | case 34: return 9; 300 | case 35: return 8; 301 | case 36: return 8; 302 | case 37: return 8; 303 | case 38: return 8; 304 | case 39: return 9; 305 | case 40: return 9; 306 | case 41: return 9; 307 | case 42: return 9; 308 | case 43: return 9; 309 | case 44: return 9; 310 | case 45: return 9; 311 | case 46: return 9; 312 | case 47: return 8; 313 | case 48: return 8; 314 | case 49: return 8; 315 | case 50: return 8; 316 | case 51: return 8; 317 | case 52: return 8; 318 | case 53: return 5; 319 | case 54: return 5; 320 | case 55: return 5; 321 | case 56: return 5; 322 | case 57: return 8; 323 | case 58: return 8; 324 | case 59: return 8; 325 | case 60: return 8; 326 | case 61: return 8; 327 | case 62: return 8; 328 | case 63: return 8; 329 | default: return [super fontSizeForKeyIndex:keyIndex]; 330 | } 331 | } 332 | 333 | @end 334 | -------------------------------------------------------------------------------- /Shared/Generated/KeyboardLayoutISO.h: -------------------------------------------------------------------------------- 1 | // 2 | // KeyboardLayoutISO.h 3 | // TouchBar 4 | // 5 | // Generated by generate_keyboard_layouts.sh. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import "KeyboardLayout.h" 10 | 11 | @interface KeyboardLayoutISO : KeyboardLayout 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Shared/Generated/KeyboardLayoutISO.m: -------------------------------------------------------------------------------- 1 | // 2 | // KeyboardLayoutISO.m 3 | // TouchBar 4 | // 5 | // Generated by generate_keyboard_layouts.sh. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import "KeyboardLayoutISO.h" 10 | 11 | @implementation KeyboardLayoutISO 12 | 13 | /************************************************************* 14 | * * 15 | * WARNING: this is an auto-generated file. DO NOT EDIT! * 16 | * * 17 | *************************************************************/ 18 | 19 | - (KeyboardLayoutType)type { 20 | return KeyboardLayoutTypeISO; 21 | } 22 | 23 | - (UInt8)macKbdType { 24 | return 59; 25 | } 26 | 27 | - (CGSize)size { 28 | return CGSizeMake(290, 113); 29 | } 30 | 31 | - (NSUInteger)numberOfKeys { 32 | return 66; 33 | } 34 | 35 | - (KeyCode)keyCodeForKeyIndex:(NSUInteger)keyIndex { 36 | switch (keyIndex) { 37 | case 0: return 0x0A; // kVK_ISO_Section 38 | case 1: return 0x12; // kVK_ANSI_1 39 | case 2: return 0x13; // kVK_ANSI_2 40 | case 3: return 0x14; // kVK_ANSI_3 41 | case 4: return 0x15; // kVK_ANSI_4 42 | case 5: return 0x17; // kVK_ANSI_5 43 | case 6: return 0x16; // kVK_ANSI_6 44 | case 7: return 0x1A; // kVK_ANSI_7 45 | case 8: return 0x1C; // kVK_ANSI_8 46 | case 9: return 0x19; // kVK_ANSI_9 47 | case 10: return 0x1D; // kVK_ANSI_0 48 | case 11: return 0x1B; // kVK_ANSI_Minus 49 | case 12: return 0x18; // kVK_ANSI_Equal 50 | case 13: return 0x1E; // kVK_ANSI_RightBracket 51 | case 14: return 0x21; // kVK_ANSI_LeftBracket 52 | case 15: return 0x23; // kVK_ANSI_P 53 | case 16: return 0x1F; // kVK_ANSI_O 54 | case 17: return 0x22; // kVK_ANSI_I 55 | case 18: return 0x20; // kVK_ANSI_U 56 | case 19: return 0x10; // kVK_ANSI_Y 57 | case 20: return 0x11; // kVK_ANSI_T 58 | case 21: return 0x0F; // kVK_ANSI_R 59 | case 22: return 0x0E; // kVK_ANSI_E 60 | case 23: return 0x0D; // kVK_ANSI_W 61 | case 24: return 0x0C; // kVK_ANSI_Q 62 | case 25: return 0x00; // kVK_ANSI_A 63 | case 26: return 0x01; // kVK_ANSI_S 64 | case 27: return 0x02; // kVK_ANSI_D 65 | case 28: return 0x03; // kVK_ANSI_F 66 | case 29: return 0x05; // kVK_ANSI_G 67 | case 30: return 0x04; // kVK_ANSI_H 68 | case 31: return 0x26; // kVK_ANSI_J 69 | case 32: return 0x28; // kVK_ANSI_K 70 | case 33: return 0x25; // kVK_ANSI_L 71 | case 34: return 0x29; // kVK_ANSI_Semicolon 72 | case 35: return 0x27; // kVK_ANSI_Quote 73 | case 36: return 0x2A; // kVK_ANSI_Backslash 74 | case 37: return 0x2C; // kVK_ANSI_Slash 75 | case 38: return 0x2F; // kVK_ANSI_Period 76 | case 39: return 0x2B; // kVK_ANSI_Comma 77 | case 40: return 0x2E; // kVK_ANSI_M 78 | case 41: return 0x2D; // kVK_ANSI_N 79 | case 42: return 0x0B; // kVK_ANSI_B 80 | case 43: return 0x09; // kVK_ANSI_V 81 | case 44: return 0x08; // kVK_ANSI_C 82 | case 45: return 0x07; // kVK_ANSI_X 83 | case 46: return 0x06; // kVK_ANSI_Z 84 | case 47: return 0x32; // kVK_ANSI_Grave 85 | case 48: return 0x3F; // kVK_Function 86 | case 49: return 0x3B; // kVK_Control 87 | case 50: return 0x3A; // kVK_Option 88 | case 51: return 0x3A; // kVK_Option 89 | case 52: return 0x37; // kVK_Command 90 | case 53: return 0x37; // kVK_Command 91 | case 54: return 0x7B; // kVK_LeftArrow 92 | case 55: return 0x7D; // kVK_DownArrow 93 | case 56: return 0x7C; // kVK_RightArrow 94 | case 57: return 0x7E; // kVK_UpArrow 95 | case 58: return 0x33; // kVK_Delete 96 | case 59: return 0x30; // kVK_Tab 97 | case 60: return 0x24; // kVK_Return 98 | case 61: return 0x39; // kVK_CapsLock 99 | case 62: return 0x38; // kVK_Shift 100 | case 63: return 0x38; // kVK_Shift 101 | case 64: return 0x31; // kVK_Space 102 | default: return [super keyCodeForKeyIndex:keyIndex]; 103 | } 104 | } 105 | 106 | - (KeyEventModifierFlags)modifierFlagForKeyIndex:(NSUInteger)keyIndex { 107 | switch (keyIndex) { 108 | case 48: return KeyEventModifierFlagFunction; 109 | case 49: return KeyEventModifierFlagControl; 110 | case 50: return KeyEventModifierFlagOption; 111 | case 51: return KeyEventModifierFlagOption; 112 | case 52: return KeyEventModifierFlagCommand; 113 | case 53: return KeyEventModifierFlagCommand; 114 | case 61: return KeyEventModifierFlagCapsLock; 115 | case 62: return KeyEventModifierFlagShift; 116 | case 63: return KeyEventModifierFlagShift; 117 | default: return [super modifierFlagForKeyIndex:keyIndex]; 118 | } 119 | } 120 | 121 | #if TARGET_OS_IPHONE 122 | - (UIBezierPath *)bezierPathForKeyIndex:(NSUInteger)keyIndex { 123 | switch (keyIndex) { 124 | case 0: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.5, 13.5, 19, 19) cornerRadius:2.0]; 125 | case 1: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20.5, 13.5, 19, 19) cornerRadius:2.0]; 126 | case 2: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(40.5, 13.5, 19, 19) cornerRadius:2.0]; 127 | case 3: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(60.5, 13.5, 19, 19) cornerRadius:2.0]; 128 | case 4: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(80.5, 13.5, 19, 19) cornerRadius:2.0]; 129 | case 5: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(100.5, 13.5, 19, 19) cornerRadius:2.0]; 130 | case 6: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(120.5, 13.5, 19, 19) cornerRadius:2.0]; 131 | case 7: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(140.5, 13.5, 19, 19) cornerRadius:2.0]; 132 | case 8: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(160.5, 13.5, 19, 19) cornerRadius:2.0]; 133 | case 9: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(180.5, 13.5, 19, 19) cornerRadius:2.0]; 134 | case 10: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(200.5, 13.5, 19, 19) cornerRadius:2.0]; 135 | case 11: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(220.5, 13.5, 19, 19) cornerRadius:2.0]; 136 | case 12: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(240.5, 13.5, 19, 19) cornerRadius:2.0]; 137 | case 13: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(250.5, 33.5, 19, 19) cornerRadius:2.0]; 138 | case 14: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(230.5, 33.5, 19, 19) cornerRadius:2.0]; 139 | case 15: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(210.5, 33.5, 19, 19) cornerRadius:2.0]; 140 | case 16: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(190.5, 33.5, 19, 19) cornerRadius:2.0]; 141 | case 17: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(170.5, 33.5, 19, 19) cornerRadius:2.0]; 142 | case 18: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(150.5, 33.5, 19, 19) cornerRadius:2.0]; 143 | case 19: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(130.5, 33.5, 19, 19) cornerRadius:2.0]; 144 | case 20: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(110.5, 33.5, 19, 19) cornerRadius:2.0]; 145 | case 21: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(90.5, 33.5, 19, 19) cornerRadius:2.0]; 146 | case 22: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(70.5, 33.5, 19, 19) cornerRadius:2.0]; 147 | case 23: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50.5, 33.5, 19, 19) cornerRadius:2.0]; 148 | case 24: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(30.5, 33.5, 19, 19) cornerRadius:2.0]; 149 | case 25: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(35.5, 53.5, 19, 19) cornerRadius:2.0]; 150 | case 26: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(55.5, 53.5, 19, 19) cornerRadius:2.0]; 151 | case 27: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(75.5, 53.5, 19, 19) cornerRadius:2.0]; 152 | case 28: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(95.5, 53.5, 19, 19) cornerRadius:2.0]; 153 | case 29: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(115.5, 53.5, 19, 19) cornerRadius:2.0]; 154 | case 30: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(135.5, 53.5, 19, 19) cornerRadius:2.0]; 155 | case 31: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(155.5, 53.5, 19, 19) cornerRadius:2.0]; 156 | case 32: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(175.5, 53.5, 19, 19) cornerRadius:2.0]; 157 | case 33: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(195.5, 53.5, 19, 19) cornerRadius:2.0]; 158 | case 34: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(215.5, 53.5, 19, 19) cornerRadius:2.0]; 159 | case 35: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(235.5, 53.5, 19, 19) cornerRadius:2.0]; 160 | case 36: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(255.5, 53.5, 19, 19) cornerRadius:2.0]; 161 | case 37: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(225.5, 73.5, 19, 19) cornerRadius:2.0]; 162 | case 38: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(205.5, 73.5, 19, 19) cornerRadius:2.0]; 163 | case 39: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(185.5, 73.5, 19, 19) cornerRadius:2.0]; 164 | case 40: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(165.5, 73.5, 19, 19) cornerRadius:2.0]; 165 | case 41: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(145.5, 73.5, 19, 19) cornerRadius:2.0]; 166 | case 42: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(125.5, 73.5, 19, 19) cornerRadius:2.0]; 167 | case 43: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(105.5, 73.5, 19, 19) cornerRadius:2.0]; 168 | case 44: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(85.5, 73.5, 19, 19) cornerRadius:2.0]; 169 | case 45: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(65.5, 73.5, 19, 19) cornerRadius:2.0]; 170 | case 46: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(45.5, 73.5, 19, 19) cornerRadius:2.0]; 171 | case 47: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(25.5, 73.5, 19, 19) cornerRadius:2.0]; 172 | case 48: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.5, 93.5, 19, 19) cornerRadius:2.0]; 173 | case 49: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20.5, 93.5, 19, 19) cornerRadius:2.0]; 174 | case 50: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(40.5, 93.5, 19, 19) cornerRadius:2.0]; 175 | case 51: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(210.5, 93.5, 19, 19) cornerRadius:2.0]; 176 | case 52: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(60.5, 93.5, 24, 19) cornerRadius:2.0]; 177 | case 53: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(185.5, 93.5, 24, 19) cornerRadius:2.0]; 178 | case 54: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(230.5, 93.5, 19, 19) cornerRadius:2]; 179 | case 55: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(250.5, 103, 19, 9.5) cornerRadius:2]; 180 | case 56: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(270.5, 93.5, 19, 19) cornerRadius:2]; 181 | case 57: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(250.5, 93.5, 19, 9.5) cornerRadius:2]; 182 | case 58: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(260.5, 13.5, 29, 19) cornerRadius:2.0]; 183 | case 59: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.5, 33.5, 29, 19) cornerRadius:2.0]; 184 | case 60: { 185 | UIBezierPath *path = [UIBezierPath new]; 186 | [path moveToPoint:CGPointMake(270.5, 35.5)]; 187 | [path addArcWithCenter:CGPointMake(272.48323969742, 35.24161984871) radius:2 startAngle:3.012040486441 endAngle:-2.0847452684394 clockwise:YES]; 188 | [path addLineToPoint:CGPointMake(287.5, 33.5)]; 189 | [path addArcWithCenter:CGPointMake(287.5, 35.5) radius:2 startAngle:-1.5707963267949 endAngle:0 clockwise:YES]; 190 | [path addLineToPoint:CGPointMake(289.5, 70.5)]; 191 | [path addArcWithCenter:CGPointMake(287.5, 70.5) radius:2 startAngle:0 endAngle:1.5707963267949 clockwise:YES]; 192 | [path addLineToPoint:CGPointMake(277.5, 72.5)]; 193 | [path addArcWithCenter:CGPointMake(277.5, 70.5) radius:2 startAngle:1.5707963267949 endAngle:3.1415926535898 clockwise:YES]; 194 | [path addLineToPoint:CGPointMake(275.5, 53.5)]; 195 | [path addArcWithCenter:CGPointMake(273.75838015129, 54.483239697419) radius:2 startAngle:-0.51394894164447 endAngle:-1.7003484939437 clockwise:NO]; 196 | [path addLineToPoint:CGPointMake(271.5, 52.5)]; 197 | [path addArcWithCenter:CGPointMake(272.32287565553, 50.677124344468) radius:2 startAngle:1.9948273662856 endAngle:2.7175616140991 clockwise:YES]; 198 | [path closePath]; 199 | return path; 200 | } 201 | case 61: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.5, 53.5, 34, 19) cornerRadius:2.0]; 202 | case 62: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.5, 73.5, 24, 19) cornerRadius:2.0]; 203 | case 63: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(245.5, 73.5, 44, 19) cornerRadius:2.0]; 204 | case 64: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(85.5, 93.5, 99, 19) cornerRadius:2.0]; 205 | case 65: return [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.5, 0.5, 289, 12) cornerRadius:2]; 206 | default: return [super bezierPathForKeyIndex:keyIndex]; 207 | } 208 | } 209 | #endif 210 | 211 | - (CGPoint)textPositionForKeyIndex:(NSUInteger)keyIndex { 212 | switch (keyIndex) { 213 | case 0: return CGPointMake(10, 21.5); 214 | case 1: return CGPointMake(30, 21.5); 215 | case 2: return CGPointMake(50, 21.5); 216 | case 3: return CGPointMake(70, 21.5); 217 | case 4: return CGPointMake(90, 21.5); 218 | case 5: return CGPointMake(110, 21.5); 219 | case 6: return CGPointMake(130, 21.5); 220 | case 7: return CGPointMake(150, 21.5); 221 | case 8: return CGPointMake(170, 21.5); 222 | case 9: return CGPointMake(190, 21.5); 223 | case 10: return CGPointMake(210, 21.5); 224 | case 11: return CGPointMake(230, 21.5); 225 | case 12: return CGPointMake(250, 21.5); 226 | case 13: return CGPointMake(260, 41.5); 227 | case 14: return CGPointMake(240, 41.5); 228 | case 15: return CGPointMake(220, 41.5); 229 | case 16: return CGPointMake(200, 41.5); 230 | case 17: return CGPointMake(180, 41.5); 231 | case 18: return CGPointMake(160, 41.5); 232 | case 19: return CGPointMake(140, 41.5); 233 | case 20: return CGPointMake(120, 41.5); 234 | case 21: return CGPointMake(100, 41.5); 235 | case 22: return CGPointMake(80, 41.5); 236 | case 23: return CGPointMake(60, 41.5); 237 | case 24: return CGPointMake(40, 41.5); 238 | case 25: return CGPointMake(45, 61.5); 239 | case 26: return CGPointMake(65, 61.5); 240 | case 27: return CGPointMake(85, 61.5); 241 | case 28: return CGPointMake(105, 61.5); 242 | case 29: return CGPointMake(125, 61.5); 243 | case 30: return CGPointMake(145, 61.5); 244 | case 31: return CGPointMake(165, 61.5); 245 | case 32: return CGPointMake(185, 61.5); 246 | case 33: return CGPointMake(205, 61.5); 247 | case 34: return CGPointMake(225, 61.5); 248 | case 35: return CGPointMake(245, 61.5); 249 | case 36: return CGPointMake(265, 61.5); 250 | case 37: return CGPointMake(235, 81.5); 251 | case 38: return CGPointMake(215, 81.5); 252 | case 39: return CGPointMake(195, 81.5); 253 | case 40: return CGPointMake(175, 81.5); 254 | case 41: return CGPointMake(155, 81.5); 255 | case 42: return CGPointMake(135, 81.5); 256 | case 43: return CGPointMake(115, 81.5); 257 | case 44: return CGPointMake(95, 81.5); 258 | case 45: return CGPointMake(75, 81.5); 259 | case 46: return CGPointMake(55, 81.5); 260 | case 47: return CGPointMake(35, 82.5); 261 | case 48: return CGPointMake(10, 102.5); 262 | case 49: return CGPointMake(30, 102.5); 263 | case 50: return CGPointMake(50, 102.5); 264 | case 51: return CGPointMake(220, 102.5); 265 | case 52: return CGPointMake(73, 102.5); 266 | case 53: return CGPointMake(197, 102.5); 267 | case 54: return CGPointMake(240, 102.5); 268 | case 55: return CGPointMake(260, 107.25); 269 | case 56: return CGPointMake(280, 102.5); 270 | case 57: return CGPointMake(260, 97.75); 271 | case 58: return CGPointMake(276, 21.5); 272 | case 59: return CGPointMake(14, 41.5); 273 | case 60: return CGPointMake(281, 47.5); 274 | case 61: return CGPointMake(16, 61.5); 275 | case 62: return CGPointMake(12, 82.5); 276 | case 63: return CGPointMake(266, 82.5); 277 | case 64: return CGPointMake(124, 102.5); 278 | default: return [super textPositionForKeyIndex:keyIndex]; 279 | } 280 | } 281 | 282 | - (CGFloat)fontSizeForKeyIndex:(NSUInteger)keyIndex { 283 | switch (keyIndex) { 284 | case 0: return 8; 285 | case 1: return 8; 286 | case 2: return 8; 287 | case 3: return 8; 288 | case 4: return 8; 289 | case 5: return 8; 290 | case 6: return 8; 291 | case 7: return 8; 292 | case 8: return 8; 293 | case 9: return 8; 294 | case 10: return 8; 295 | case 11: return 8; 296 | case 12: return 8; 297 | case 13: return 8; 298 | case 14: return 8; 299 | case 15: return 9; 300 | case 16: return 9; 301 | case 17: return 9; 302 | case 18: return 9; 303 | case 19: return 9; 304 | case 20: return 9; 305 | case 21: return 9; 306 | case 22: return 9; 307 | case 23: return 9; 308 | case 24: return 9; 309 | case 25: return 9; 310 | case 26: return 9; 311 | case 27: return 9; 312 | case 28: return 9; 313 | case 29: return 9; 314 | case 30: return 9; 315 | case 31: return 9; 316 | case 32: return 9; 317 | case 33: return 9; 318 | case 34: return 9; 319 | case 35: return 9; 320 | case 36: return 8; 321 | case 37: return 9; 322 | case 38: return 9; 323 | case 39: return 9; 324 | case 40: return 9; 325 | case 41: return 9; 326 | case 42: return 9; 327 | case 43: return 9; 328 | case 44: return 9; 329 | case 45: return 9; 330 | case 46: return 9; 331 | case 47: return 9; 332 | case 48: return 7; 333 | case 49: return 7; 334 | case 50: return 8; 335 | case 51: return 8; 336 | case 52: return 8; 337 | case 53: return 8; 338 | case 54: return 4; 339 | case 55: return 4; 340 | case 56: return 4; 341 | case 57: return 4; 342 | case 58: return 7; 343 | case 59: return 8; 344 | case 60: return 8; 345 | case 61: return 8; 346 | case 62: return 8; 347 | case 63: return 8; 348 | case 64: return 8; 349 | default: return [super fontSizeForKeyIndex:keyIndex]; 350 | } 351 | } 352 | 353 | @end 354 | -------------------------------------------------------------------------------- /Shared/Generated/KeyboardLayoutJIS.h: -------------------------------------------------------------------------------- 1 | // 2 | // KeyboardLayoutJIS.h 3 | // TouchBar 4 | // 5 | // Generated by generate_keyboard_layouts.sh. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import "KeyboardLayout.h" 10 | 11 | @interface KeyboardLayoutJIS : KeyboardLayout 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Shared/Keyboard.h: -------------------------------------------------------------------------------- 1 | // 2 | // Keyboard.h 3 | // TouchBar 4 | // 5 | // Created by Robbert Klarenbeek on 10/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #ifndef Keyboard_h 10 | #define Keyboard_h 11 | 12 | typedef NS_ENUM(uint64_t, KeyEventType) { 13 | KeyEventTypeKeyDown = 10, 14 | KeyEventTypeKeyUp = 11, 15 | KeyEventTypeFlagsChanged = 12, 16 | }; 17 | 18 | typedef uint16_t KeyCode; 19 | 20 | typedef NS_OPTIONS(uint16_t, KeyEventModifierFlags) { 21 | KeyEventModifierFlagCapsLock = 1 << 0, 22 | KeyEventModifierFlagShift = 1 << 1, 23 | KeyEventModifierFlagControl = 1 << 2, 24 | KeyEventModifierFlagOption = 1 << 3, 25 | KeyEventModifierFlagCommand = 1 << 4, 26 | KeyEventModifierFlagFunction = 1 << 5, // Keep this last 27 | }; 28 | 29 | typedef struct { 30 | KeyEventType type; 31 | KeyCode key; 32 | KeyEventModifierFlags modifiers; 33 | } KeyEvent; 34 | 35 | #endif /* Keyboard_h */ 36 | -------------------------------------------------------------------------------- /Shared/KeyboardLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // KeyboardLayout.h 3 | // Test 4 | // 5 | // Created by Robbert Klarenbeek on 18/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "Keyboard.h" 12 | 13 | @import CoreGraphics; 14 | 15 | #if TARGET_OS_IPHONE 16 | @import UIKit; 17 | #endif 18 | 19 | typedef NS_ENUM(NSInteger, KeyboardLayoutType) { 20 | KeyboardLayoutTypeUnknown = -1, 21 | KeyboardLayoutTypeANSI = 0, 22 | KeyboardLayoutTypeISO = 1, 23 | KeyboardLayoutTypeJIS = 2, 24 | }; 25 | 26 | @interface KeyboardLayout : NSObject 27 | @property (nonatomic, readonly) KeyboardLayoutType type; 28 | @property (nonatomic, readonly) UInt8 macKbdType; 29 | @property (nonatomic, readonly) CGSize size; 30 | @property (nonatomic, readonly) NSUInteger numberOfKeys; 31 | - (KeyCode)keyCodeForKeyIndex:(NSUInteger)keyIndex; 32 | - (KeyEventModifierFlags)modifierFlagForKeyIndex:(NSUInteger)keyIndex; 33 | #if TARGET_OS_IPHONE 34 | - (UIBezierPath *)bezierPathForKeyIndex:(NSUInteger)keyIndex; 35 | #endif 36 | - (CGPoint)textPositionForKeyIndex:(NSUInteger)keyIndex; 37 | - (CGFloat)fontSizeForKeyIndex:(NSUInteger)keyIndex; 38 | + (NSString *)fixedKeyCaptionForKeyCode:(KeyCode)keyCode withFnDown:(BOOL)fnDown; 39 | @end 40 | -------------------------------------------------------------------------------- /Shared/KeyboardLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // KeyboardLayout.m 3 | // Test 4 | // 5 | // Created by Robbert Klarenbeek on 18/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import "KeyboardLayout.h" 10 | 11 | @implementation KeyboardLayout 12 | 13 | - (KeyboardLayoutType)type { 14 | return KeyboardLayoutTypeUnknown; 15 | } 16 | 17 | - (UInt8)macKbdType { 18 | return 0; 19 | } 20 | 21 | - (CGSize)size { 22 | return CGSizeZero; 23 | } 24 | 25 | - (NSUInteger)numberOfKeys { 26 | return 0; 27 | } 28 | 29 | - (KeyCode)keyCodeForKeyIndex:(NSUInteger)keyIndex { 30 | return 0xFF; 31 | } 32 | 33 | - (KeyEventModifierFlags)modifierFlagForKeyIndex:(NSUInteger)keyIndex { 34 | return 0; 35 | } 36 | 37 | #if TARGET_OS_IPHONE 38 | - (UIBezierPath *)bezierPathForKeyIndex:(NSUInteger)keyIndex { 39 | return nil; 40 | } 41 | #endif 42 | 43 | - (CGPoint)textPositionForKeyIndex:(NSUInteger)keyIndex { 44 | return CGPointZero; 45 | } 46 | 47 | - (CGFloat)fontSizeForKeyIndex:(NSUInteger)keyIndex { 48 | return 0.0; 49 | } 50 | 51 | + (NSString *)fixedKeyCaptionForKeyCode:(KeyCode)keyCode withFnDown:(BOOL)fnDown { 52 | switch(keyCode) { 53 | case 0x24: return !fnDown ? @"↩\uFE0E" : @"⌤\uFE0E"; // kVK_Return 54 | case 0x30: return @"⇥\uFE0E"; // kVK_Tab 55 | case 0x33: return !fnDown ? @"⌫\uFE0E" : @"⌦\uFE0E"; // kVK_Delete 56 | case 0x35: return @"esc"; // kVK_Escape 57 | case 0x36: return @"⌘\uFE0E"; // kVK_RightCommand 58 | case 0x37: return @"⌘\uFE0E"; // kVK_Command 59 | case 0x38: return @"⇧\uFE0E"; // kVK_Shift 60 | case 0x39: return @"⇪\uFE0E"; // kVK_CapsLock 61 | case 0x3A: return @"⌥\uFE0E"; // kVK_Option 62 | case 0x3B: return @"⌃\uFE0E"; // kVK_Control 63 | case 0x3C: return @"⇧\uFE0E"; // kVK_RightShift 64 | case 0x3D: return @"⌥\uFE0E"; // kVK_RightOption 65 | case 0x3E: return @"⌃\uFE0E"; // kVK_RightControl 66 | case 0x3F: return @"fn"; // kVK_Function 67 | case 0x40: return @"F17"; // kVK_F17 68 | case 0x47: return @"⌧\uFE0E"; // kVK_ANSI_KeypadClear 69 | case 0x4C: return @"⌤\uFE0E"; // kVK_ANSI_KeypadEnter 70 | case 0x4F: return @"F18"; // kVK_F18 71 | case 0x50: return @"F19"; // kVK_F19 72 | case 0x5A: return @"F20"; // kVK_F20 73 | case 0x60: return @"F5"; // kVK_F5 74 | case 0x61: return @"F6"; // kVK_F6 75 | case 0x62: return @"F7"; // kVK_F7 76 | case 0x63: return @"F3"; // kVK_F3 77 | case 0x64: return @"F8"; // kVK_F8 78 | case 0x65: return @"F9"; // kVK_F9 79 | case 0x66: return @"英数"; // kVK_JIS_Eisu 80 | case 0x67: return @"F11"; // kVK_F11 81 | case 0x68: return @"かな"; // kVK_JIS_Kana 82 | case 0x69: return @"F13"; // kVK_F13 83 | case 0x6A: return @"F16"; // kVK_F16 84 | case 0x6B: return @"F14"; // kVK_F14 85 | case 0x6D: return @"F10"; // kVK_F10 86 | case 0x6F: return @"F12"; // kVK_F12 87 | case 0x71: return @"F15"; // kVK_F15 88 | case 0x72: return @"?⃝\uFE0E"; // kVK_Help 89 | case 0x73: return @"↖\uFE0E"; // kVK_Home 90 | case 0x74: return @"⇞\uFE0E"; // kVK_PageUp 91 | case 0x76: return @"F4"; // kVK_F4 92 | case 0x77: return @"↘\uFE0E"; // kVK_End 93 | case 0x78: return @"F2"; // kVK_F2 94 | case 0x79: return @"⇟\uFE0E"; // kVK_PageDown 95 | case 0x7A: return @"F1"; // kVK_F1 96 | case 0x7B: return !fnDown ? @"⇠\uFE0E" : @"↖\uFE0E"; // kVK_LeftArrow 97 | case 0x7C: return !fnDown ? @"⇢\uFE0E" : @"↘\uFE0E"; // kVK_RightArrow 98 | case 0x7D: return !fnDown ? @"⇣\uFE0E" : @"⇟\uFE0E"; // kVK_DownArrow 99 | case 0x7E: return !fnDown ? @"⇡\uFE0E" : @"⇞\uFE0E"; // kVK_UpArrow 100 | default: 101 | return nil; 102 | } 103 | } 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /Shared/Peertalk/PTChannel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Represents a communication channel between two endpoints talking the same 3 | // PTProtocol. 4 | // 5 | #import 6 | #import 7 | #import 8 | #import 9 | 10 | #import "PTProtocol.h" 11 | #import "PTUSBHub.h" 12 | 13 | @class PTData, PTAddress; 14 | @protocol PTChannelDelegate; 15 | 16 | @interface PTChannel : NSObject 17 | 18 | // Delegate 19 | @property (strong) id delegate; 20 | 21 | // Communication protocol. Must not be nil. 22 | @property PTProtocol *protocol; 23 | 24 | // YES if this channel is a listening server 25 | @property (readonly) BOOL isListening; 26 | 27 | // YES if this channel is a connected peer 28 | @property (readonly) BOOL isConnected; 29 | 30 | // Arbitrary attachment. Note that if you set this, the object will grow by 31 | // 8 bytes (64 bits). 32 | @property (strong) id userInfo; 33 | 34 | // Create a new channel using the shared PTProtocol for the current dispatch 35 | // queue, with *delegate*. 36 | + (PTChannel*)channelWithDelegate:(id)delegate; 37 | 38 | 39 | // Initialize a new frame channel, configuring it to use the calling queue's 40 | // protocol instance (as returned by [PTProtocol sharedProtocolForQueue: 41 | // dispatch_get_current_queue()]) 42 | - (id)init; 43 | 44 | // Initialize a new frame channel with a specific protocol. 45 | - (id)initWithProtocol:(PTProtocol*)protocol; 46 | 47 | // Initialize a new frame channel with a specific protocol and delegate. 48 | - (id)initWithProtocol:(PTProtocol*)protocol delegate:(id)delegate; 49 | 50 | 51 | // Connect to a TCP port on a device connected over USB 52 | - (void)connectToPort:(int)port overUSBHub:(PTUSBHub*)usbHub deviceID:(NSNumber*)deviceID callback:(void(^)(NSError *error))callback; 53 | 54 | // Connect to a TCP port at IPv4 address. Provided port must NOT be in network 55 | // byte order. Provided in_addr_t must NOT be in network byte order. A value returned 56 | // from inet_aton() will be in network byte order. You can use a value of inet_aton() 57 | // as the address parameter here, but you must flip the byte order before passing the 58 | // in_addr_t to this function. 59 | - (void)connectToPort:(in_port_t)port IPv4Address:(in_addr_t)address callback:(void(^)(NSError *error, PTAddress *address))callback; 60 | 61 | // Listen for connections on port and address, effectively starting a socket 62 | // server. Provided port must NOT be in network byte order. Provided in_addr_t 63 | // must NOT be in network byte order. 64 | // For this to make sense, you should provide a onAccept block handler 65 | // or a delegate implementing ioFrameChannel:didAcceptConnection:. 66 | - (void)listenOnPort:(in_port_t)port IPv4Address:(in_addr_t)address callback:(void(^)(NSError *error))callback; 67 | 68 | // Send a frame with an optional payload and optional callback. 69 | // If *callback* is not NULL, the block is invoked when either an error occured 70 | // or when the frame (and payload, if any) has been completely sent. 71 | - (void)sendFrameOfType:(uint32_t)frameType tag:(uint32_t)tag withPayload:(dispatch_data_t)payload callback:(void(^)(NSError *error))callback; 72 | 73 | // Lower-level method to assign a connected dispatch IO channel to this channel 74 | - (BOOL)startReadingFromConnectedChannel:(dispatch_io_t)channel error:(__autoreleasing NSError**)error; 75 | 76 | // Close the channel, preventing further reading and writing. Any ongoing and 77 | // queued reads and writes will be aborted. 78 | - (void)close; 79 | 80 | // "graceful" close -- any ongoing and queued reads and writes will complete 81 | // before the channel ends. 82 | - (void)cancel; 83 | 84 | @end 85 | 86 | 87 | // Wraps a mapped dispatch_data_t object. The memory pointed to by *data* is 88 | // valid until *dispatchData* is deallocated (normally when the receiver is 89 | // deallocated). 90 | @interface PTData : NSObject 91 | @property (readonly) dispatch_data_t dispatchData; 92 | @property (readonly) void *data; 93 | @property (readonly) size_t length; 94 | @end 95 | 96 | 97 | // Represents a peer's address 98 | @interface PTAddress : NSObject 99 | // For network addresses, this is the IP address in textual format 100 | @property (readonly) NSString *name; 101 | // For network addresses, this is the port number. Otherwise 0 (zero). 102 | @property (readonly) NSInteger port; 103 | @end 104 | 105 | 106 | // Protocol for PTChannel delegates 107 | @protocol PTChannelDelegate 108 | 109 | @required 110 | // Invoked when a new frame has arrived on a channel. 111 | - (void)ioFrameChannel:(PTChannel*)channel didReceiveFrameOfType:(uint32_t)type tag:(uint32_t)tag payload:(PTData*)payload; 112 | 113 | @optional 114 | // Invoked to accept an incoming frame on a channel. Reply NO ignore the 115 | // incoming frame. If not implemented by the delegate, all frames are accepted. 116 | - (BOOL)ioFrameChannel:(PTChannel*)channel shouldAcceptFrameOfType:(uint32_t)type tag:(uint32_t)tag payloadSize:(uint32_t)payloadSize; 117 | 118 | // Invoked when the channel closed. If it closed because of an error, *error* is 119 | // a non-nil NSError object. 120 | - (void)ioFrameChannel:(PTChannel*)channel didEndWithError:(NSError*)error; 121 | 122 | // For listening channels, this method is invoked when a new connection has been 123 | // accepted. 124 | - (void)ioFrameChannel:(PTChannel*)channel didAcceptConnection:(PTChannel*)otherChannel fromAddress:(PTAddress*)address; 125 | 126 | @end 127 | -------------------------------------------------------------------------------- /Shared/Peertalk/PTPrivate.h: -------------------------------------------------------------------------------- 1 | #if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && (!defined(__IPHONE_6_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0)) || \ 2 | (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (!defined(__MAC_10_8) || __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_8)) 3 | #define PT_DISPATCH_RETAIN_RELEASE 1 4 | #else 5 | #define PT_DISPATCH_RETAIN_RELEASE 0 6 | #endif 7 | 8 | #if PT_DISPATCH_RETAIN_RELEASE 9 | #define PT_PRECISE_LIFETIME 10 | #define PT_PRECISE_LIFETIME_UNUSED 11 | #else 12 | #define PT_PRECISE_LIFETIME __attribute__((objc_precise_lifetime)) 13 | #define PT_PRECISE_LIFETIME_UNUSED __attribute__((objc_precise_lifetime, unused)) 14 | #endif 15 | -------------------------------------------------------------------------------- /Shared/Peertalk/PTProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // A universal frame-based communication protocol which can be used to exchange 3 | // arbitrary structured data. 4 | // 5 | // In short: 6 | // 7 | // - Each transmission is comprised by one fixed-size frame. 8 | // - Each frame contains a protocol version number. 9 | // - Each frame contains an application frame type. 10 | // - Each frame can contain an identifying tag. 11 | // - Each frame can have application-specific data of up to UINT32_MAX size. 12 | // - Transactions style messaging can be modeled on top using frame tags. 13 | // - Lightweight API on top of libdispatch (aka GCD) -- close to the metal. 14 | // 15 | #include 16 | #import 17 | 18 | // Special frame tag that signifies "no tag". Your implementation should never 19 | // create a reply for a frame with this tag. 20 | static const uint32_t PTFrameNoTag = 0; 21 | 22 | // Special frame type that signifies that the stream has ended. 23 | static const uint32_t PTFrameTypeEndOfStream = 0; 24 | 25 | // NSError domain 26 | FOUNDATION_EXPORT NSString * const PTProtocolErrorDomain; 27 | 28 | 29 | @interface PTProtocol : NSObject 30 | 31 | // Queue on which to run data processing blocks. 32 | @property dispatch_queue_t queue; 33 | 34 | // Get the shared protocol object for *queue* 35 | + (PTProtocol*)sharedProtocolForQueue:(dispatch_queue_t)queue; 36 | 37 | // Initialize a new protocol object to use a specific queue. 38 | - (id)initWithDispatchQueue:(dispatch_queue_t)queue; 39 | 40 | // Initialize a new protocol object to use the current calling queue. 41 | - (id)init; 42 | 43 | #pragma mark Sending frames 44 | 45 | // Generate a new tag that is unique within this protocol object. 46 | - (uint32_t)newTag; 47 | 48 | // Send a frame over *channel* with an optional payload and optional callback. 49 | // If *callback* is not NULL, the block is invoked when either an error occured 50 | // or when the frame (and payload, if any) has been completely sent. 51 | - (void)sendFrameOfType:(uint32_t)frameType 52 | tag:(uint32_t)tag 53 | withPayload:(dispatch_data_t)payload 54 | overChannel:(dispatch_io_t)channel 55 | callback:(void(^)(NSError *error))callback; 56 | 57 | #pragma mark Receiving frames 58 | 59 | // Read frames over *channel* as they arrive. 60 | // The onFrame handler is responsible for reading (or discarding) any payload 61 | // and call *resumeReadingFrames* afterwards to resume reading frames. 62 | // To stop reading frames, simply do not invoke *resumeReadingFrames*. 63 | // When the stream ends, a frame of type PTFrameTypeEndOfStream is received. 64 | - (void)readFramesOverChannel:(dispatch_io_t)channel 65 | onFrame:(void(^)(NSError *error, 66 | uint32_t type, 67 | uint32_t tag, 68 | uint32_t payloadSize, 69 | dispatch_block_t resumeReadingFrames))onFrame; 70 | 71 | // Read a single frame over *channel*. A frame of type PTFrameTypeEndOfStream 72 | // denotes the stream has ended. 73 | - (void)readFrameOverChannel:(dispatch_io_t)channel 74 | callback:(void(^)(NSError *error, 75 | uint32_t frameType, 76 | uint32_t frameTag, 77 | uint32_t payloadSize))callback; 78 | 79 | #pragma mark Receiving frame payloads 80 | 81 | // Read a complete payload. It's the callers responsibility to make sure 82 | // payloadSize is not too large since memory will be automatically allocated 83 | // where only payloadSize is the limit. 84 | // The returned dispatch_data_t object owns *buffer* and thus you need to call 85 | // dispatch_retain on *contiguousData* if you plan to keep *buffer* around after 86 | // returning from the callback. 87 | - (void)readPayloadOfSize:(size_t)payloadSize 88 | overChannel:(dispatch_io_t)channel 89 | callback:(void(^)(NSError *error, 90 | dispatch_data_t contiguousData, 91 | const uint8_t *buffer, 92 | size_t bufferSize))callback; 93 | 94 | // Discard data of *size* waiting on *channel*. *callback* can be NULL. 95 | - (void)readAndDiscardDataOfSize:(size_t)size 96 | overChannel:(dispatch_io_t)channel 97 | callback:(void(^)(NSError *error, BOOL endOfStream))callback; 98 | 99 | @end 100 | 101 | @interface NSData (PTProtocol) 102 | // Creates a new dispatch_data_t object which references the receiver and uses 103 | // the receivers bytes as its backing data. The returned dispatch_data_t object 104 | // holds a reference to the recevier. It's the callers responsibility to call 105 | // dispatch_release on the returned object when done. 106 | - (dispatch_data_t)createReferencingDispatchData; 107 | + (NSData *)dataWithContentsOfDispatchData:(dispatch_data_t)data; 108 | @end 109 | 110 | @interface NSDictionary (PTProtocol) 111 | // See description of -[NSData(PTProtocol) createReferencingDispatchData] 112 | - (dispatch_data_t)createReferencingDispatchData; 113 | 114 | // Decode *data* as a peroperty list-encoded dictionary. Returns nil on failure. 115 | + (NSDictionary*)dictionaryWithContentsOfDispatchData:(dispatch_data_t)data; 116 | @end 117 | -------------------------------------------------------------------------------- /Shared/Peertalk/PTProtocol.m: -------------------------------------------------------------------------------- 1 | #import "PTProtocol.h" 2 | #import "PTPrivate.h" 3 | #import 4 | 5 | static const uint32_t PTProtocolVersion1 = 1; 6 | 7 | NSString * const PTProtocolErrorDomain = @"PTProtocolError"; 8 | 9 | // This is what we send as the header for each frame. 10 | typedef struct _PTFrame { 11 | // The version of the frame and protocol. 12 | uint32_t version; 13 | 14 | // Type of frame 15 | uint32_t type; 16 | 17 | // Unless zero, a tag is retained in frames that are responses to previous 18 | // frames. Applications can use this to build transactions or request-response 19 | // logic. 20 | uint32_t tag; 21 | 22 | // If payloadSize is larger than zero, *payloadSize* number of bytes are 23 | // following, constituting application-specific data. 24 | uint32_t payloadSize; 25 | 26 | } PTFrame; 27 | 28 | 29 | @interface PTProtocol () { 30 | uint32_t nextFrameTag_; 31 | @public 32 | dispatch_queue_t queue_; 33 | } 34 | - (dispatch_data_t)createDispatchDataWithFrameOfType:(uint32_t)type frameTag:(uint32_t)frameTag payload:(dispatch_data_t)payload; 35 | @end 36 | 37 | 38 | static void _release_queue_local_protocol(void *objcobj) { 39 | if (objcobj) { 40 | PTProtocol *protocol = (__bridge_transfer id)objcobj; 41 | protocol->queue_ = NULL; 42 | } 43 | } 44 | 45 | 46 | @interface RQueueLocalIOFrameProtocol : PTProtocol 47 | @end 48 | @implementation RQueueLocalIOFrameProtocol 49 | - (void)setQueue:(dispatch_queue_t)queue { 50 | } 51 | @end 52 | 53 | 54 | @implementation PTProtocol 55 | 56 | 57 | + (PTProtocol*)sharedProtocolForQueue:(dispatch_queue_t)queue { 58 | static const char currentQueueFrameProtocolKey; 59 | //dispatch_queue_t queue = dispatch_get_current_queue(); 60 | PTProtocol *currentQueueFrameProtocol = (__bridge PTProtocol*)dispatch_queue_get_specific(queue, ¤tQueueFrameProtocolKey); 61 | if (!currentQueueFrameProtocol) { 62 | currentQueueFrameProtocol = [[RQueueLocalIOFrameProtocol alloc] initWithDispatchQueue:NULL]; 63 | currentQueueFrameProtocol->queue_ = queue; // reference, no retain, since we would create cyclic references 64 | dispatch_queue_set_specific(queue, ¤tQueueFrameProtocolKey, (__bridge_retained void*)currentQueueFrameProtocol, &_release_queue_local_protocol); 65 | return (__bridge PTProtocol*)dispatch_queue_get_specific(queue, ¤tQueueFrameProtocolKey); // to avoid race conds 66 | } else { 67 | return currentQueueFrameProtocol; 68 | } 69 | } 70 | 71 | 72 | - (id)initWithDispatchQueue:(dispatch_queue_t)queue { 73 | if (!(self = [super init])) return nil; 74 | queue_ = queue; 75 | #if PT_DISPATCH_RETAIN_RELEASE 76 | if (queue_) dispatch_retain(queue_); 77 | #endif 78 | return self; 79 | } 80 | 81 | - (id)init { 82 | return [self initWithDispatchQueue:dispatch_get_main_queue()]; 83 | } 84 | 85 | - (void)dealloc { 86 | if (queue_) { 87 | #if PT_DISPATCH_RETAIN_RELEASE 88 | dispatch_release(queue_); 89 | #endif 90 | } 91 | } 92 | 93 | - (dispatch_queue_t)queue { 94 | return queue_; 95 | } 96 | 97 | - (void)setQueue:(dispatch_queue_t)queue { 98 | #if PT_DISPATCH_RETAIN_RELEASE 99 | dispatch_queue_t prev_queue = queue_; 100 | queue_ = queue; 101 | if (queue_) dispatch_retain(queue_); 102 | if (prev_queue) dispatch_release(prev_queue); 103 | #else 104 | queue_ = queue; 105 | #endif 106 | } 107 | 108 | 109 | - (uint32_t)newTag { 110 | return ++nextFrameTag_; 111 | } 112 | 113 | 114 | #pragma mark - 115 | #pragma mark Creating frames 116 | 117 | 118 | - (dispatch_data_t)createDispatchDataWithFrameOfType:(uint32_t)type frameTag:(uint32_t)frameTag payload:(dispatch_data_t)payload { 119 | PTFrame *frame = CFAllocatorAllocate(kCFAllocatorDefault, sizeof(PTFrame), 0); 120 | frame->version = htonl(PTProtocolVersion1); 121 | frame->type = htonl(type); 122 | frame->tag = htonl(frameTag); 123 | 124 | if (payload) { 125 | size_t payloadSize = dispatch_data_get_size(payload); 126 | assert(payloadSize <= UINT32_MAX); 127 | frame->payloadSize = htonl((uint32_t)payloadSize); 128 | } else { 129 | frame->payloadSize = 0; 130 | } 131 | 132 | dispatch_data_t frameData = dispatch_data_create((const void*)frame, sizeof(PTFrame), queue_, ^{ 133 | CFAllocatorDeallocate(kCFAllocatorDefault, (void*)frame); 134 | }); 135 | 136 | if (payload && frame->payloadSize != 0) { 137 | // chain frame + payload 138 | dispatch_data_t data = dispatch_data_create_concat(frameData, payload); 139 | #if PT_DISPATCH_RETAIN_RELEASE 140 | dispatch_release(frameData); 141 | #endif 142 | frameData = data; 143 | } 144 | 145 | return frameData; 146 | } 147 | 148 | 149 | #pragma mark - 150 | #pragma mark Sending frames 151 | 152 | 153 | - (void)sendFrameOfType:(uint32_t)frameType tag:(uint32_t)tag withPayload:(dispatch_data_t)payload overChannel:(dispatch_io_t)channel callback:(void(^)(NSError*))callback { 154 | dispatch_data_t frame = [self createDispatchDataWithFrameOfType:frameType frameTag:tag payload:payload]; 155 | dispatch_io_write(channel, 0, frame, queue_, ^(bool done, dispatch_data_t data, int _errno) { 156 | if (done && callback) { 157 | callback(_errno == 0 ? nil : [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:_errno userInfo:nil]); 158 | } 159 | }); 160 | #if PT_DISPATCH_RETAIN_RELEASE 161 | dispatch_release(frame); 162 | #endif 163 | } 164 | 165 | 166 | #pragma mark - 167 | #pragma mark Receiving frames 168 | 169 | 170 | - (void)readFrameOverChannel:(dispatch_io_t)channel callback:(void(^)(NSError *error, uint32_t frameType, uint32_t frameTag, uint32_t payloadSize))callback { 171 | __block dispatch_data_t allData = NULL; 172 | 173 | dispatch_io_read(channel, 0, sizeof(PTFrame), queue_, ^(bool done, dispatch_data_t data, int error) { 174 | //NSLog(@"dispatch_io_read: done=%d data=%p error=%d", done, data, error); 175 | size_t dataSize = data ? dispatch_data_get_size(data) : 0; 176 | 177 | if (dataSize) { 178 | if (!allData) { 179 | allData = data; 180 | #if PT_DISPATCH_RETAIN_RELEASE 181 | dispatch_retain(allData); 182 | #endif 183 | } else { 184 | #if PT_DISPATCH_RETAIN_RELEASE 185 | dispatch_data_t allDataPrev = allData; 186 | allData = dispatch_data_create_concat(allData, data); 187 | dispatch_release(allDataPrev); 188 | #else 189 | allData = dispatch_data_create_concat(allData, data); 190 | #endif 191 | } 192 | } 193 | 194 | if (done) { 195 | if (error != 0) { 196 | callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], 0, 0, 0); 197 | return; 198 | } 199 | 200 | if (dataSize == 0) { 201 | callback(nil, PTFrameTypeEndOfStream, 0, 0); 202 | return; 203 | } 204 | 205 | if (!allData || dispatch_data_get_size(allData) < sizeof(PTFrame)) { 206 | #if PT_DISPATCH_RETAIN_RELEASE 207 | if (allData) dispatch_release(allData); 208 | #endif 209 | callback([[NSError alloc] initWithDomain:PTProtocolErrorDomain code:0 userInfo:nil], 0, 0, 0); 210 | return; 211 | } 212 | 213 | PTFrame *frame = NULL; 214 | size_t size = 0; 215 | 216 | PT_PRECISE_LIFETIME dispatch_data_t contiguousData = dispatch_data_create_map(allData, (const void **)&frame, &size); // precise lifetime guarantees bytes in frame will stay valid till the end of scope 217 | #if PT_DISPATCH_RETAIN_RELEASE 218 | dispatch_release(allData); 219 | #endif 220 | if (!contiguousData) { 221 | callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:ENOMEM userInfo:nil], 0, 0, 0); 222 | return; 223 | } 224 | 225 | frame->version = ntohl(frame->version); 226 | if (frame->version != PTProtocolVersion1) { 227 | callback([[NSError alloc] initWithDomain:PTProtocolErrorDomain code:0 userInfo:nil], 0, 0, 0); 228 | } else { 229 | frame->type = ntohl(frame->type); 230 | frame->tag = ntohl(frame->tag); 231 | frame->payloadSize = ntohl(frame->payloadSize); 232 | callback(nil, frame->type, frame->tag, frame->payloadSize); 233 | } 234 | 235 | #if PT_DISPATCH_RETAIN_RELEASE 236 | dispatch_release(contiguousData); 237 | #endif 238 | } 239 | }); 240 | } 241 | 242 | 243 | - (void)readPayloadOfSize:(size_t)payloadSize overChannel:(dispatch_io_t)channel callback:(void(^)(NSError *error, dispatch_data_t contiguousData, const uint8_t *buffer, size_t bufferSize))callback { 244 | __block dispatch_data_t allData = NULL; 245 | dispatch_io_read(channel, 0, payloadSize, queue_, ^(bool done, dispatch_data_t data, int error) { 246 | //NSLog(@"dispatch_io_read: done=%d data=%p error=%d", done, data, error); 247 | size_t dataSize = dispatch_data_get_size(data); 248 | 249 | if (dataSize) { 250 | if (!allData) { 251 | allData = data; 252 | #if PT_DISPATCH_RETAIN_RELEASE 253 | dispatch_retain(allData); 254 | #endif 255 | } else { 256 | #if PT_DISPATCH_RETAIN_RELEASE 257 | dispatch_data_t allDataPrev = allData; 258 | allData = dispatch_data_create_concat(allData, data); 259 | dispatch_release(allDataPrev); 260 | #else 261 | allData = dispatch_data_create_concat(allData, data); 262 | #endif 263 | } 264 | } 265 | 266 | if (done) { 267 | if (error != 0) { 268 | #if PT_DISPATCH_RETAIN_RELEASE 269 | if (allData) dispatch_release(allData); 270 | #endif 271 | callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], NULL, NULL, 0); 272 | return; 273 | } 274 | 275 | if (dataSize == 0) { 276 | #if PT_DISPATCH_RETAIN_RELEASE 277 | if (allData) dispatch_release(allData); 278 | #endif 279 | callback(nil, NULL, NULL, 0); 280 | return; 281 | } 282 | 283 | uint8_t *buffer = NULL; 284 | size_t bufferSize = 0; 285 | PT_PRECISE_LIFETIME dispatch_data_t contiguousData = NULL; 286 | 287 | if (allData) { 288 | contiguousData = dispatch_data_create_map(allData, (const void **)&buffer, &bufferSize); 289 | #if PT_DISPATCH_RETAIN_RELEASE 290 | dispatch_release(allData); allData = NULL; 291 | #endif 292 | if (!contiguousData) { 293 | callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:ENOMEM userInfo:nil], NULL, NULL, 0); 294 | return; 295 | } 296 | } 297 | 298 | callback(nil, contiguousData, buffer, bufferSize); 299 | #if PT_DISPATCH_RETAIN_RELEASE 300 | if (contiguousData) dispatch_release(contiguousData); 301 | #endif 302 | } 303 | }); 304 | } 305 | 306 | 307 | - (void)readAndDiscardDataOfSize:(size_t)size overChannel:(dispatch_io_t)channel callback:(void(^)(NSError*, BOOL))callback { 308 | dispatch_io_read(channel, 0, size, queue_, ^(bool done, dispatch_data_t data, int error) { 309 | if (done && callback) { 310 | size_t dataSize = dispatch_data_get_size(data); 311 | callback(error == 0 ? nil : [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], dataSize == 0); 312 | } 313 | }); 314 | } 315 | 316 | 317 | - (void)readFramesOverChannel:(dispatch_io_t)channel onFrame:(void(^)(NSError*, uint32_t, uint32_t, uint32_t, dispatch_block_t))onFrame { 318 | [self readFrameOverChannel:channel callback:^(NSError *error, uint32_t type, uint32_t tag, uint32_t payloadSize) { 319 | onFrame(error, type, tag, payloadSize, ^{ 320 | if (type != PTFrameTypeEndOfStream) { 321 | [self readFramesOverChannel:channel onFrame:onFrame]; 322 | } 323 | }); 324 | }]; 325 | } 326 | 327 | 328 | @end 329 | 330 | 331 | @interface _PTDispatchData : NSObject { 332 | dispatch_data_t dispatchData_; 333 | } 334 | @end 335 | @implementation _PTDispatchData 336 | - (id)initWithDispatchData:(dispatch_data_t)dispatchData { 337 | if (!(self = [super init])) return nil; 338 | dispatchData_ = dispatchData; 339 | #if PT_DISPATCH_RETAIN_RELEASE 340 | dispatch_retain(dispatchData_); 341 | #endif 342 | return self; 343 | } 344 | - (void)dealloc { 345 | #if PT_DISPATCH_RETAIN_RELEASE 346 | if (dispatchData_) dispatch_release(dispatchData_); 347 | #endif 348 | } 349 | @end 350 | 351 | @implementation NSData (PTProtocol) 352 | 353 | #pragma clang diagnostic push 354 | #pragma clang diagnostic ignored "-Wunused-getter-return-value" 355 | 356 | - (dispatch_data_t)createReferencingDispatchData { 357 | // Note: The queue is used to submit the destructor. Since we only perform an 358 | // atomic release of self, it doesn't really matter which queue is used, thus 359 | // we use the current calling queue. 360 | return dispatch_data_create((const void*)self.bytes, self.length, dispatch_get_main_queue(), ^{ 361 | // trick to have the block capture the data, thus retain/releasing 362 | [self length]; 363 | }); 364 | } 365 | 366 | #pragma clang diagnostic pop 367 | 368 | + (NSData *)dataWithContentsOfDispatchData:(dispatch_data_t)data { 369 | if (!data) { 370 | return nil; 371 | } 372 | uint8_t *buffer = NULL; 373 | size_t bufferSize = 0; 374 | PT_PRECISE_LIFETIME dispatch_data_t contiguousData = dispatch_data_create_map(data, (const void **)&buffer, &bufferSize); 375 | if (!contiguousData) { 376 | return nil; 377 | } 378 | 379 | _PTDispatchData *dispatchDataRef = [[_PTDispatchData alloc] initWithDispatchData:contiguousData]; 380 | NSData *newData = [NSData dataWithBytesNoCopy:(void*)buffer length:bufferSize freeWhenDone:NO]; 381 | #if PT_DISPATCH_RETAIN_RELEASE 382 | dispatch_release(contiguousData); 383 | #endif 384 | static const bool kDispatchDataRefKey; 385 | objc_setAssociatedObject(newData, (const void*)kDispatchDataRefKey, dispatchDataRef, OBJC_ASSOCIATION_RETAIN); 386 | 387 | return newData; 388 | } 389 | 390 | @end 391 | 392 | 393 | @implementation NSDictionary (PTProtocol) 394 | 395 | - (dispatch_data_t)createReferencingDispatchData { 396 | NSError *error = nil; 397 | NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:self format:NSPropertyListBinaryFormat_v1_0 options:0 error:&error]; 398 | if (!plistData) { 399 | NSLog(@"Failed to serialize property list: %@", error); 400 | return nil; 401 | } else { 402 | return [plistData createReferencingDispatchData]; 403 | } 404 | } 405 | 406 | // Decode *data* as a peroperty list-encoded dictionary. Returns nil on failure. 407 | + (NSDictionary*)dictionaryWithContentsOfDispatchData:(dispatch_data_t)data { 408 | if (!data) { 409 | return nil; 410 | } 411 | uint8_t *buffer = NULL; 412 | size_t bufferSize = 0; 413 | PT_PRECISE_LIFETIME dispatch_data_t contiguousData = dispatch_data_create_map(data, (const void **)&buffer, &bufferSize); 414 | if (!contiguousData) { 415 | return nil; 416 | } 417 | NSDictionary *dict = [NSPropertyListSerialization propertyListWithData:[NSData dataWithBytesNoCopy:(void*)buffer length:bufferSize freeWhenDone:NO] options:NSPropertyListImmutable format:NULL error:nil]; 418 | #if PT_DISPATCH_RETAIN_RELEASE 419 | dispatch_release(contiguousData); 420 | #endif 421 | return dict; 422 | } 423 | 424 | @end 425 | -------------------------------------------------------------------------------- /Shared/Peertalk/PTUSBHub.h: -------------------------------------------------------------------------------- 1 | #include 2 | #import 3 | 4 | // PTUSBDeviceDidAttachNotification 5 | // Posted when a device has been attached. Also posted for each device that is 6 | // already attached when the PTUSBHub starts listening. 7 | // 8 | // .userInfo = { 9 | // DeviceID = 3; 10 | // MessageType = Attached; 11 | // Properties = { 12 | // ConnectionSpeed = 480000000; 13 | // ConnectionType = USB; 14 | // DeviceID = 3; 15 | // LocationID = 1234567890; 16 | // ProductID = 1234; 17 | // SerialNumber = 0123456789abcdef0123456789abcdef01234567; 18 | // }; 19 | // } 20 | // 21 | FOUNDATION_EXPORT NSString * const PTUSBDeviceDidAttachNotification; 22 | 23 | // PTUSBDeviceDidDetachNotification 24 | // Posted when a device has been detached. 25 | // 26 | // .userInfo = { 27 | // DeviceID = 3; 28 | // MessageType = Detached; 29 | // } 30 | // 31 | FOUNDATION_EXPORT NSString * const PTUSBDeviceDidDetachNotification; 32 | 33 | // NSError domain 34 | FOUNDATION_EXPORT NSString * const PTUSBHubErrorDomain; 35 | 36 | // Error codes returned with NSError.code for NSError domain PTUSBHubErrorDomain 37 | typedef enum { 38 | PTUSBHubErrorBadDevice = 2, 39 | PTUSBHubErrorConnectionRefused = 3, 40 | } PTUSBHubError; 41 | 42 | @interface PTUSBHub : NSObject 43 | 44 | // Shared, implicitly opened hub. 45 | + (PTUSBHub*)sharedHub; 46 | 47 | // Connect to a TCP *port* on a device, while the actual transport is over USB. 48 | // Upon success, *error* is nil and *channel* is a duplex I/O channel. 49 | // You can retrieve the underlying file descriptor using 50 | // dispatch_io_get_descriptor(channel). The dispatch_io_t channel behaves just 51 | // like any stream type dispatch_io_t, making it possible to use the same logic 52 | // for both USB bridged connections and e.g. ethernet-based connections. 53 | // 54 | // *onStart* is called either when a connection failed, in which case the error 55 | // argument is non-nil, or when the connection was successfully established (the 56 | // error argument is nil). Must not be NULL. 57 | // 58 | // *onEnd* is called when a connection was open and just did close. If the error 59 | // argument is non-nil, the channel closed because of an error. Pass NULL for no 60 | // callback. 61 | // 62 | - (void)connectToDevice:(NSNumber*)deviceID 63 | port:(int)port 64 | onStart:(void(^)(NSError *error, dispatch_io_t channel))onStart 65 | onEnd:(void(^)(NSError *error))onEnd; 66 | 67 | // Start listening for devices. You only need to invoke this method on custom 68 | // instances to start receiving notifications. The shared instance returned from 69 | // +sharedHub is always in listening mode. 70 | // 71 | // *onStart* is called either when the system failed to start listening, in 72 | // which case the error argument is non-nil, or when the receiver is listening. 73 | // Pass NULL for no callback. 74 | // 75 | // *onEnd* is called when listening stopped. If the error argument is non-nil, 76 | // listening stopped because of an error. Pass NULL for no callback. 77 | // 78 | - (void)listenOnQueue:(dispatch_queue_t)queue 79 | onStart:(void(^)(NSError*))onStart 80 | onEnd:(void(^)(NSError*))onEnd; 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /Shared/Peertalk/Peertalk.h: -------------------------------------------------------------------------------- 1 | // 2 | // Peertalk.h 3 | // Peertalk 4 | // 5 | // Created by Marek Cirkos on 12/04/2016. 6 | // 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Peertalk. 12 | FOUNDATION_EXPORT double PeertalkVersionNumber; 13 | 14 | //! Project version string for Peertalk. 15 | FOUNDATION_EXPORT const unsigned char PeertalkVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | #import "PTChannel.h" 21 | #import "PTProtocol.h" 22 | #import "PTUSBHub.h" 23 | -------------------------------------------------------------------------------- /Shared/Peertalk/prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | -------------------------------------------------------------------------------- /Shared/Protocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // Protocol.h 3 | // TouchBar 4 | // 5 | // Created by Robbert Klarenbeek on 02/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #ifndef Protocol_h 10 | #define Protocol_h 11 | 12 | static const int kProtocolPort = 1337; 13 | 14 | typedef uint64_t Version; 15 | 16 | // Up this every time you want the iOS client require updated code 17 | // (so basically every versioned release or in case of protocol changes) 18 | static const Version kServerVersion = 2; 19 | 20 | static const uint32_t kProtocolFrameTypeServerMin = 1000; 21 | static const uint32_t kProtocolFrameTypeServerMax = 1999; 22 | static const uint32_t kProtocolFrameTypeClientMin = 2000; 23 | static const uint32_t kProtocolFrameTypeClientMax = 2999; 24 | 25 | typedef NS_ENUM(uint32_t, ProtocolFrameType) { 26 | ProtocolFrameTypeServerVersion = 1000, 27 | ProtocolFrameTypeServerImage = 1001, 28 | // ProtocolFrameTypeServerKeyboardHtml = 1002, 29 | ProtocolFrameTypeServerSystemKeyEvent = 1003, 30 | ProtocolFrameTypeServerModeChange = 1004, 31 | ProtocolFrameTypeServerAlignChange = 1005, 32 | ProtocolFrameTypeServerKeyboardLayout = 1006, 33 | 34 | ProtocolFrameTypeClientTouchBarMouseEvent = 2000, 35 | ProtocolFrameTypeClientKeyboardKeyEvent = 2001, 36 | }; 37 | 38 | typedef NS_ENUM(uint64_t, MouseEventType) { 39 | MouseEventTypeDown = 1, 40 | MouseEventTypeUp = 2, 41 | MouseEventTypeDragged = 6, 42 | }; 43 | 44 | #include "Keyboard.h" 45 | 46 | typedef struct { 47 | MouseEventType type; 48 | double x; 49 | double y; 50 | } MouseEvent; 51 | 52 | typedef NS_ENUM(uint64_t, OperatingMode) { 53 | OperatingModeTouchBarOnly = 0, 54 | OperatingModeKeyboard = 1, 55 | OperatingModeDemo1 = 2, 56 | OperatingModeDemo2 = 3, 57 | OperatingModeDemo3 = 4, 58 | OperatingModeDemo4 = 5, 59 | OperatingModeDemo5 = 6, 60 | }; 61 | 62 | typedef NS_ENUM(uint64_t, Alignment) { 63 | AlignmentBottom = 0, 64 | AlignmentMiddle = 1, 65 | AlignmentTop = 2, 66 | }; 67 | 68 | #endif /* Protocol_h */ 69 | -------------------------------------------------------------------------------- /TouchBar.xcodeproj/xcshareddata/xcschemes/TouchBarClient.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /TouchBar.xcodeproj/xcshareddata/xcschemes/TouchBarServer Helper.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /TouchBar.xcodeproj/xcshareddata/xcschemes/TouchBarServer.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /TouchBarClient/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // TouchBarClient 4 | // 5 | // Created by Robbert Klarenbeek on 02/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /TouchBarClient/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // TouchBarClient 4 | // 5 | // Created by Robbert Klarenbeek on 02/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "NotificationIcon@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "NotificationIcon@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-Small.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-Small@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-Small@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "57x57", 47 | "idiom" : "iphone", 48 | "filename" : "Icon.png", 49 | "scale" : "1x" 50 | }, 51 | { 52 | "size" : "57x57", 53 | "idiom" : "iphone", 54 | "filename" : "Icon@2x.png", 55 | "scale" : "2x" 56 | }, 57 | { 58 | "size" : "60x60", 59 | "idiom" : "iphone", 60 | "filename" : "Icon-60@2x.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "60x60", 65 | "idiom" : "iphone", 66 | "filename" : "Icon-60@3x.png", 67 | "scale" : "3x" 68 | }, 69 | { 70 | "size" : "20x20", 71 | "idiom" : "ipad", 72 | "filename" : "NotificationIcon~ipad.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "20x20", 77 | "idiom" : "ipad", 78 | "filename" : "NotificationIcon~ipad@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "29x29", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-Small.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "29x29", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-Small@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "40x40", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-40.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "40x40", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-40@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "50x50", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-Small-50.png", 109 | "scale" : "1x" 110 | }, 111 | { 112 | "size" : "50x50", 113 | "idiom" : "ipad", 114 | "filename" : "Icon-Small-50@2x.png", 115 | "scale" : "2x" 116 | }, 117 | { 118 | "size" : "72x72", 119 | "idiom" : "ipad", 120 | "filename" : "Icon-72.png", 121 | "scale" : "1x" 122 | }, 123 | { 124 | "size" : "72x72", 125 | "idiom" : "ipad", 126 | "filename" : "Icon-72@2x.png", 127 | "scale" : "2x" 128 | }, 129 | { 130 | "size" : "76x76", 131 | "idiom" : "ipad", 132 | "filename" : "Icon-76.png", 133 | "scale" : "1x" 134 | }, 135 | { 136 | "size" : "76x76", 137 | "idiom" : "ipad", 138 | "filename" : "Icon-76@2x.png", 139 | "scale" : "2x" 140 | }, 141 | { 142 | "size" : "83.5x83.5", 143 | "idiom" : "ipad", 144 | "filename" : "Icon-83.5@2x.png", 145 | "scale" : "2x" 146 | } 147 | ], 148 | "info" : { 149 | "version" : 1, 150 | "author" : "xcode" 151 | } 152 | } -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-40.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-72.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/Icon@2x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/NotificationIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/NotificationIcon@2x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/NotificationIcon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/NotificationIcon@3x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad@2x.png -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/DemoImage1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "DemoImage1.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/DemoImage1.imageset/DemoImage1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/DemoImage1.imageset/DemoImage1.jpg -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/DemoImage2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "DemoImage2.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/DemoImage2.imageset/DemoImage2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/DemoImage2.imageset/DemoImage2.jpg -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/DemoImage3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "DemoImage3.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/DemoImage3.imageset/DemoImage3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/DemoImage3.imageset/DemoImage3.jpg -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/DemoImage4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "DemoImage4.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/DemoImage4.imageset/DemoImage4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/DemoImage4.imageset/DemoImage4.jpg -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/DemoImage5.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "DemoImage5.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TouchBarClient/Assets.xcassets/DemoImage5.imageset/DemoImage5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarClient/Assets.xcassets/DemoImage5.imageset/DemoImage5.jpg -------------------------------------------------------------------------------- /TouchBarClient/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /TouchBarClient/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /TouchBarClient/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Touch Bar 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UIStatusBarHidden 34 | 35 | UIStatusBarStyle 36 | UIStatusBarStyleDefault 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | UIInterfaceOrientationPortraitUpsideDown 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | UIViewControllerBasedStatusBarAppearance 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /TouchBarClient/KeyboardView.h: -------------------------------------------------------------------------------- 1 | // 2 | // KeyboardView.h 3 | // TouchBarClient 4 | // 5 | // Created by Robbert Klarenbeek on 18/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "KeyboardLayout.h" 12 | #import "Keyboard.h" 13 | 14 | @class KeyboardView; 15 | @protocol KeyboardViewDelegate 16 | @optional 17 | - (void)keyboardView:(KeyboardView *)keyboardView keyEvent:(KeyEvent)keyEvent; 18 | @end 19 | 20 | IB_DESIGNABLE 21 | @interface KeyboardView : UIView 22 | @property (nonatomic, weak) id delegate; 23 | @property (nonatomic, readonly) CGFloat aspectRatio; 24 | @property (nonatomic, strong) KeyboardLayout *layout; 25 | @property (nonatomic, strong) NSDictionary *keyCaptions; 26 | #if TARGET_INTERFACE_BUILDER 27 | @property (nonatomic, assign) IBInspectable NSInteger layoutType; 28 | #else 29 | @property (nonatomic, assign) KeyboardLayoutType layoutType; 30 | #endif 31 | @property (nonatomic, assign) IBInspectable BOOL preserveAspectRatio; 32 | @property (nonatomic, assign) IBInspectable CGFloat borderWidth; 33 | @property (nonatomic, strong) IBInspectable UIColor *normalKeyColor; 34 | @property (nonatomic, strong) IBInspectable UIColor *normalCaptionColor; 35 | @property (nonatomic, strong) IBInspectable UIColor *normalBorderColor; 36 | @property (nonatomic, strong) IBInspectable UIColor *activeKeyColor; 37 | @property (nonatomic, strong) IBInspectable UIColor *activeCaptionColor; 38 | @property (nonatomic, strong) IBInspectable UIColor *activeBorderColor; 39 | - (void)externalKeyEvent:(KeyEvent)keyCode; 40 | @end 41 | -------------------------------------------------------------------------------- /TouchBarClient/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // TouchBarClient 4 | // 5 | // Created by Robbert Klarenbeek on 02/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /TouchBarClient/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TouchBarClient 4 | // 5 | // Created by Robbert Klarenbeek on 02/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TouchBarServer Helper/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // TouchBarServer Helper 4 | // 5 | // Created by Robbert Klarenbeek on 03/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : NSObject 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /TouchBarServer Helper/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // TouchBarServer Helper 4 | // 5 | // Created by Robbert Klarenbeek on 03/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 14 | NSString *appPath = [[[[[[NSBundle mainBundle] bundlePath] 15 | stringByDeletingLastPathComponent] 16 | stringByDeletingLastPathComponent] 17 | stringByDeletingLastPathComponent] 18 | stringByDeletingLastPathComponent]; 19 | [[NSWorkspace sharedWorkspace] launchApplication:appPath]; 20 | [NSApp terminate:nil]; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /TouchBarServer Helper/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | LSUIElement 26 | 27 | NSHumanReadableCopyright 28 | Copyright © 2016 Bikkelbroeders. All rights reserved. 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /TouchBarServer Helper/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TouchBarServer Helper 4 | // 5 | // Created by Robbert Klarenbeek on 03/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, const char * argv[]) { 13 | AppDelegate *delegate = [[AppDelegate alloc] init]; 14 | [[NSApplication sharedApplication] setDelegate:delegate]; 15 | [NSApp run]; 16 | } 17 | -------------------------------------------------------------------------------- /TouchBarServer/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // TouchBarServer 4 | // 5 | // Created by Robbert Klarenbeek on 02/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : NSObject 12 | 13 | - (void)globalEvent:(NSEvent *)event; 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /TouchBarServer/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "icon_16x16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon_16x16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "icon_32x32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "icon_32x32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "icon_128x128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "icon_128x128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "icon_256x256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "icon_256x256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "icon_512x512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "icon_512x512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikkelbroeders/TouchBarDemoApp/03323b722a8bce08d48ae5136d57778b1cf74b82/TouchBarServer/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /TouchBarServer/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /TouchBarServer/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /TouchBarServer/GlobalEventApplication.h: -------------------------------------------------------------------------------- 1 | // 2 | // Application.h 3 | // TouchBarServer 4 | // 5 | // Created by Robbert Klarenbeek on 07/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface GlobalEventApplication : NSApplication 12 | 13 | @property (nonatomic, assign) int globalEventMask; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /TouchBarServer/GlobalEventApplication.m: -------------------------------------------------------------------------------- 1 | // 2 | // Application.m 3 | // TouchBarServer 4 | // 5 | // Created by Robbert Klarenbeek on 07/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import "GlobalEventApplication.h" 10 | 11 | #import "AppDelegate.h" 12 | 13 | @import Carbon; 14 | 15 | typedef int CGSConnectionID; 16 | CG_EXTERN void CGSGetKeys(KeyMap keymap); 17 | CG_EXTERN CGSConnectionID CGSMainConnectionID(void); 18 | CG_EXTERN void CGSGetBackgroundEventMask(CGSConnectionID cid, int *outMask); 19 | CG_EXTERN CGError CGSSetBackgroundEventMask(CGSConnectionID cid, int mask); 20 | 21 | @implementation GlobalEventApplication { 22 | int _defaultBackgroundEventMask; 23 | NSTimer *_ensureBackgroundEventMaskTimer; 24 | 25 | NSEventModifierFlags _modifierFlags; 26 | NSMutableSet *_keysDown; 27 | NSTimer *_detectMissingKeyUpTimer; 28 | } 29 | 30 | - (instancetype)init { 31 | self = [super init]; 32 | if (self) { 33 | CGSConnectionID connectionId = CGSMainConnectionID(); 34 | CGSGetBackgroundEventMask(connectionId, &_defaultBackgroundEventMask); 35 | 36 | _keysDown = [NSMutableSet new]; 37 | } 38 | return self; 39 | } 40 | 41 | - (void)updateBackgroundEventMask { 42 | CGSConnectionID connectionId = CGSMainConnectionID(); 43 | int mask; 44 | CGSGetBackgroundEventMask(connectionId, &mask); 45 | if (mask != (_defaultBackgroundEventMask | _globalEventMask)) { 46 | CGSSetBackgroundEventMask(connectionId, _defaultBackgroundEventMask | _globalEventMask); 47 | } 48 | } 49 | 50 | - (void)setGlobalEventMask:(int)globalEventMask { 51 | if (_globalEventMask != globalEventMask) { 52 | _globalEventMask = globalEventMask; 53 | [self updateBackgroundEventMask]; 54 | 55 | if (_ensureBackgroundEventMaskTimer) { 56 | [_ensureBackgroundEventMaskTimer invalidate]; 57 | _ensureBackgroundEventMaskTimer = nil; 58 | } 59 | _ensureBackgroundEventMaskTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateBackgroundEventMask) userInfo:nil repeats:YES]; 60 | } 61 | } 62 | 63 | - (BOOL)isKeyPressed:(CGKeyCode)key inKeyMap:(KeyMap *)keymap { 64 | unsigned char element = key / 32; 65 | UInt32 mask = 1 << (key % 32); 66 | return ((*keymap)[element].bigEndianValue & mask) != 0; 67 | } 68 | 69 | - (void)detectKeyUpsWithoutEvents:(NSEvent *)event { 70 | switch (event.type) { 71 | case NSEventTypeKeyDown: { 72 | BOOL firstKeyDown = (_keysDown.count == 0); 73 | [_keysDown addObject:@(event.keyCode)]; 74 | if (firstKeyDown && !_detectMissingKeyUpTimer && [NSTimer respondsToSelector:@selector(scheduledTimerWithTimeInterval:repeats:block:)]) { 75 | _detectMissingKeyUpTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 repeats:YES block:^(NSTimer *timer){ 76 | KeyMap keymap; 77 | CGSGetKeys(keymap); 78 | for (NSNumber *keyDown in [_keysDown copy]) { 79 | CGKeyCode key = [keyDown integerValue]; 80 | if (![self isKeyPressed:key inKeyMap:&keymap]) { 81 | NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyUp location:NSZeroPoint modifierFlags:_modifierFlags timestamp:0 windowNumber:0 context:nil characters:@"" charactersIgnoringModifiers:@"" isARepeat:NO keyCode:key]; 82 | [self globalEvent:event]; 83 | } 84 | } 85 | }]; 86 | } 87 | break; 88 | } 89 | case NSEventTypeKeyUp: { 90 | [_keysDown removeObject:@(event.keyCode)]; 91 | if (_keysDown.count == 0 && _detectMissingKeyUpTimer) { 92 | [_detectMissingKeyUpTimer invalidate]; 93 | _detectMissingKeyUpTimer = nil; 94 | } 95 | break; 96 | } 97 | case NSEventTypeFlagsChanged: 98 | _modifierFlags = event.modifierFlags; 99 | break; 100 | default: 101 | break; 102 | } 103 | } 104 | 105 | - (void)globalEvent:(NSEvent *)event { 106 | [self detectKeyUpsWithoutEvents:event]; 107 | if ([self.delegate respondsToSelector:@selector(globalEvent:)]) { 108 | [self.delegate performSelector:@selector(globalEvent:) withObject:event]; 109 | } 110 | } 111 | 112 | - (NSEvent *)nextEventMatchingMask:(NSEventMask)mask untilDate:(NSDate *)expiration inMode:(NSRunLoopMode)mode dequeue:(BOOL)deqFlag { 113 | NSEvent *event = [super nextEventMatchingMask:mask untilDate:expiration inMode:mode dequeue:deqFlag]; 114 | if ((1 << event.type) & _globalEventMask) { 115 | [self globalEvent:event]; 116 | } 117 | return event; 118 | } 119 | 120 | - (void)sendEvent:(NSEvent *)event { 121 | if (!event.window && ((1 << event.type) & _globalEventMask)) { 122 | return; 123 | } 124 | 125 | [super sendEvent:event]; 126 | } 127 | 128 | @end 129 | -------------------------------------------------------------------------------- /TouchBarServer/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.6 21 | CFBundleVersion 22 | 1 23 | LSApplicationCategoryType 24 | public.app-category.utilities 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | LSUIElement 28 | 29 | NSHumanReadableCopyright 30 | Copyright © 2016 Bikkelbroeders. All rights reserved. 31 | NSMainNibFile 32 | MainMenu 33 | NSPrincipalClass 34 | GlobalEventApplication 35 | 36 | 37 | -------------------------------------------------------------------------------- /TouchBarServer/ModifierKeyController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ModifierKeyController.h 3 | // TouchBar 4 | // 5 | // Created by Robbert Klarenbeek on 16/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @import AppKit; 12 | 13 | typedef NS_ENUM(NSInteger, ModifierKey) { 14 | ModifierKeyFn = 0, 15 | ModifierKeyShift = 1, 16 | ModifierKeyCommand = 2, 17 | ModifierKeyControl = 3, 18 | ModifierKeyOption = 4, 19 | }; 20 | 21 | @protocol ModifierKeyControllerDelegate 22 | - (void)didPressModifierKey; 23 | @end 24 | 25 | @interface ModifierKeyController : NSObject 26 | @property (nonatomic, weak) id delegate; 27 | @property (nonatomic, assign) BOOL enabled; 28 | @property (nonatomic, assign) ModifierKey modifierKey; 29 | - (instancetype)init; 30 | - (instancetype)initWithModifierKey:(ModifierKey)modifierKey; 31 | - (void)processEvent:(NSEvent *)event; 32 | @end 33 | -------------------------------------------------------------------------------- /TouchBarServer/ModifierKeyController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ModifierKeyController.m 3 | // TouchBar 4 | // 5 | // Created by Robbert Klarenbeek on 16/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import "ModifierKeyController.h" 10 | 11 | @import AppKit; 12 | @import Carbon; 13 | 14 | CG_EXTERN void CGSGetKeys(KeyMap keymap); 15 | 16 | static const NSTimeInterval kModifierKeyPressMaxDuration = 0.3; 17 | 18 | @implementation ModifierKeyController { 19 | BOOL _couldBeSoleModifierKeyPress; 20 | NSEventModifierFlags _modifierFlags; 21 | } 22 | 23 | - (instancetype)init { 24 | self = [super init]; 25 | if (self) { 26 | _enabled = NO; 27 | _modifierKey = ModifierKeyFn; 28 | 29 | _couldBeSoleModifierKeyPress = NO; 30 | _modifierFlags = 0; 31 | } 32 | return self; 33 | } 34 | 35 | - (instancetype)initWithModifierKey:(ModifierKey)modifierKey { 36 | self = [self init]; 37 | if (self) { 38 | _modifierKey = modifierKey; 39 | } 40 | return self; 41 | } 42 | 43 | - (void)setModifierKey:(ModifierKey)modifierKey { 44 | if (_modifierKey != modifierKey) { 45 | _modifierKey = modifierKey; 46 | _couldBeSoleModifierKeyPress = NO; 47 | } 48 | } 49 | 50 | - (CGKeyCode)modifierKeyCode { 51 | switch (_modifierKey) { 52 | case ModifierKeyFn: 53 | return kVK_Function; 54 | case ModifierKeyShift: 55 | return kVK_Shift; 56 | case ModifierKeyCommand: 57 | return kVK_Command; 58 | case ModifierKeyControl: 59 | return kVK_Control; 60 | case ModifierKeyOption: 61 | return kVK_Option; 62 | } 63 | } 64 | 65 | - (NSEventModifierFlags)modifierEventFlag { 66 | switch (_modifierKey) { 67 | case ModifierKeyFn: 68 | return NSEventModifierFlagFunction; 69 | case ModifierKeyShift: 70 | return NSEventModifierFlagShift; 71 | case ModifierKeyCommand: 72 | return NSEventModifierFlagCommand; 73 | case ModifierKeyControl: 74 | return NSEventModifierFlagControl; 75 | case ModifierKeyOption: 76 | return NSEventModifierFlagOption; 77 | } 78 | } 79 | 80 | - (void)pressedTooLong { 81 | _couldBeSoleModifierKeyPress = NO; 82 | } 83 | 84 | - (void)processEvent:(NSEvent *)event { 85 | if (_enabled) { 86 | switch(event.type) { 87 | case NSEventTypeLeftMouseDown: 88 | case NSEventTypeLeftMouseUp: 89 | case NSEventTypeRightMouseDown: 90 | case NSEventTypeRightMouseUp: 91 | case NSEventTypeOtherMouseDown: 92 | case NSEventTypeOtherMouseUp: 93 | case NSEventTypeKeyDown: 94 | case NSEventTypeKeyUp: 95 | _couldBeSoleModifierKeyPress = NO; 96 | break; 97 | 98 | case NSEventTypeFlagsChanged: { 99 | BOOL toggleKeyWasDown = (_modifierFlags & [self modifierEventFlag]) != 0; 100 | BOOL toggleKeyIsDown = (event.modifierFlags & [self modifierEventFlag]) != 0; 101 | 102 | if(toggleKeyIsDown != toggleKeyWasDown) { 103 | KeyMap keymap; 104 | CGSGetKeys(keymap); 105 | if (toggleKeyIsDown) { 106 | _couldBeSoleModifierKeyPress = [self isOnlyKeyPressed:[self modifierKeyCode] inKeyMap:&keymap]; 107 | } else if (_couldBeSoleModifierKeyPress && [self isAnyKeyPressedInKeyMap:&keymap] == NO) { 108 | _couldBeSoleModifierKeyPress = NO; 109 | if ([_delegate respondsToSelector:@selector(didPressModifierKey)]) { 110 | [_delegate didPressModifierKey]; 111 | } 112 | } 113 | } else { 114 | _couldBeSoleModifierKeyPress = NO; 115 | } 116 | } 117 | 118 | default: 119 | break; 120 | } 121 | 122 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(pressedTooLong) object:nil]; 123 | if (_couldBeSoleModifierKeyPress) { 124 | [self performSelector:@selector(pressedTooLong) withObject:nil afterDelay:kModifierKeyPressMaxDuration]; 125 | } 126 | } 127 | 128 | if (event.type == NSFlagsChanged) { 129 | _modifierFlags = (event.modifierFlags & NSDeviceIndependentModifierFlagsMask); 130 | } 131 | } 132 | 133 | - (BOOL)isOnlyKeyPressed:(CGKeyCode)key inKeyMap:(KeyMap *)keymap { 134 | unsigned char element = key / 32; 135 | UInt32 mask = 1 << (key % 32); 136 | for (unsigned char i = 0; i < 4; i++) { 137 | if (i == element) { 138 | if ((*keymap)[i].bigEndianValue != mask) return NO; 139 | } else { 140 | if ((*keymap)[i].bigEndianValue != 0) return NO; 141 | } 142 | } 143 | 144 | return YES; 145 | } 146 | 147 | - (BOOL)isAnyKeyPressedInKeyMap:(KeyMap *)keymap { 148 | return !( 149 | (*keymap)[0].bigEndianValue == 0 && 150 | (*keymap)[1].bigEndianValue == 0 && 151 | (*keymap)[2].bigEndianValue == 0 && 152 | (*keymap)[3].bigEndianValue == 0 153 | ); 154 | } 155 | 156 | @end 157 | -------------------------------------------------------------------------------- /TouchBarServer/StartAtLoginController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 Alex Zielenski 2 | // Copyright (c) 2012 Travis Tilley 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining 5 | // a copy of this software and associated documentation files (the 6 | // "Software"), to deal in the Software without restriction, including 7 | // without limitation the rights to use, copy, modify, merge, publish, 8 | // distribute, sublicense, and/or sell copies of the Software, and to 9 | // permit persons to whom the Software is furnished to do so, subject to 10 | // the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be 13 | // included in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import 24 | 25 | @interface StartAtLoginController : NSObject { 26 | NSString *_identifier; 27 | NSURL *_url; 28 | BOOL _enabled; 29 | } 30 | 31 | @property (assign, nonatomic, readwrite) BOOL startAtLogin; 32 | @property (assign, nonatomic, readwrite) BOOL enabled; 33 | @property (copy, nonatomic, readwrite) NSString *identifier; 34 | 35 | -(id)initWithIdentifier:(NSString*)identifier; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /TouchBarServer/StartAtLoginController.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 Alex Zielenski 2 | // Copyright (c) 2012 Travis Tilley 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining 5 | // a copy of this software and associated documentation files (the 6 | // "Software"), to deal in the Software without restriction, including 7 | // without limitation the rights to use, copy, modify, merge, publish, 8 | // distribute, sublicense, and/or sell copies of the Software, and to 9 | // permit persons to whom the Software is furnished to do so, subject to 10 | // the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be 13 | // included in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import "StartAtLoginController.h" 24 | #import 25 | 26 | @implementation StartAtLoginController 27 | 28 | @synthesize identifier = _identifier; 29 | 30 | #if !__has_feature(objc_arc) 31 | - (void)dealloc { 32 | self.identifier = nil; 33 | [super dealloc]; 34 | } 35 | #endif 36 | 37 | + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey { 38 | BOOL automatic = NO; 39 | 40 | if ([theKey isEqualToString:@"startAtLogin"]) { 41 | automatic = NO; 42 | } else if ([theKey isEqualToString:@"enabled"]) { 43 | automatic = NO; 44 | } else { 45 | automatic=[super automaticallyNotifiesObserversForKey:theKey]; 46 | } 47 | 48 | return automatic; 49 | } 50 | 51 | -(id)initWithIdentifier:(NSString*)identifier { 52 | self = [self init]; 53 | if(self) { 54 | self.identifier = identifier; 55 | } 56 | return self; 57 | } 58 | 59 | -(void)setIdentifier:(NSString *)identifier { 60 | _identifier = identifier; 61 | [self startAtLogin]; 62 | #if !defined(NDEBUG) 63 | NSLog(@"Launcher '%@' %@ configured to start at login", 64 | self.identifier, (_enabled ? @"is" : @"is not")); 65 | #endif 66 | } 67 | 68 | #pragma clang diagnostic push 69 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 70 | - (BOOL)startAtLogin { 71 | if (!_identifier) 72 | return NO; 73 | 74 | BOOL isEnabled = NO; 75 | 76 | // the easy and sane method (SMJobCopyDictionary) can pose problems when sandboxed. -_- 77 | CFArrayRef cfJobDicts = SMCopyAllJobDictionaries(kSMDomainUserLaunchd); 78 | NSArray* jobDicts = CFBridgingRelease(cfJobDicts); 79 | 80 | if (jobDicts && [jobDicts count] > 0) { 81 | for (NSDictionary* job in jobDicts) { 82 | if ([_identifier isEqualToString:[job objectForKey:@"Label"]]) { 83 | isEnabled = [[job objectForKey:@"OnDemand"] boolValue]; 84 | break; 85 | } 86 | } 87 | } 88 | 89 | if (isEnabled != _enabled) { 90 | [self willChangeValueForKey:@"enabled"]; 91 | _enabled = isEnabled; 92 | [self didChangeValueForKey:@"enabled"]; 93 | } 94 | 95 | return isEnabled; 96 | } 97 | #pragma clang diagnostic pop 98 | 99 | - (void)setStartAtLogin:(BOOL)flag { 100 | if (!_identifier) 101 | return; 102 | 103 | [self willChangeValueForKey:@"startAtLogin"]; 104 | 105 | if (!SMLoginItemSetEnabled((__bridge CFStringRef)_identifier, (flag) ? true : false)) { 106 | NSLog(@"SMLoginItemSetEnabled failed!"); 107 | 108 | [self willChangeValueForKey:@"enabled"]; 109 | _enabled = NO; 110 | [self didChangeValueForKey:@"enabled"]; 111 | } else { 112 | [self willChangeValueForKey:@"enabled"]; 113 | _enabled = YES; 114 | [self didChangeValueForKey:@"enabled"]; 115 | } 116 | 117 | [self didChangeValueForKey:@"startAtLogin"]; 118 | } 119 | 120 | - (BOOL)enabled 121 | { 122 | return _enabled; 123 | } 124 | 125 | - (void)setEnabled:(BOOL)enabled 126 | { 127 | [self setStartAtLogin:enabled]; 128 | } 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /TouchBarServer/TouchBarView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TouchBarView.h 3 | // TouchBar 4 | // 5 | // Created by Robbert Klarenbeek on 12/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TouchBarView : NSView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TouchBarServer/TouchBarView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TouchBarView.m 3 | // TouchBar 4 | // 5 | // Created by Robbert Klarenbeek on 12/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import "TouchBarView.h" 10 | 11 | extern CGDisplayStreamRef SLSDFRDisplayStreamCreate(void *, dispatch_queue_t, CGDisplayStreamFrameAvailableHandler); 12 | extern BOOL DFRSetStatus(int); 13 | extern BOOL DFRFoundationPostEventWithMouseActivity(NSEventType type, NSPoint p); 14 | 15 | @implementation TouchBarView { 16 | CGDisplayStreamRef _stream; 17 | NSView *_displayView; 18 | } 19 | 20 | - (instancetype) init { 21 | self = [super init]; 22 | if(self != nil) { 23 | _displayView = [NSView new]; 24 | _displayView.frame = NSMakeRect(5, 5, 1085, 30); 25 | _displayView.wantsLayer = YES; 26 | [self addSubview:_displayView]; 27 | 28 | _stream = SLSDFRDisplayStreamCreate(NULL, dispatch_get_main_queue(), ^(CGDisplayStreamFrameStatus status, 29 | uint64_t displayTime, 30 | IOSurfaceRef frameSurface, 31 | CGDisplayStreamUpdateRef updateRef) { 32 | if (status != kCGDisplayStreamFrameStatusFrameComplete) return; 33 | _displayView.layer.contents = (__bridge id)(frameSurface); 34 | }); 35 | 36 | DFRSetStatus(2); 37 | CGDisplayStreamStart(_stream); 38 | } 39 | 40 | return self; 41 | } 42 | 43 | - (void)commonMouseEvent:(NSEvent *)event { 44 | NSPoint location = [_displayView convertPoint:[event locationInWindow] fromView:nil]; 45 | DFRFoundationPostEventWithMouseActivity(event.type, location); 46 | } 47 | 48 | - (void)mouseDown:(NSEvent *)event { 49 | [self commonMouseEvent:event]; 50 | } 51 | 52 | - (void)mouseUp:(NSEvent *)event { 53 | [self commonMouseEvent:event]; 54 | } 55 | 56 | - (void)mouseDragged:(NSEvent *)event { 57 | [self commonMouseEvent:event]; 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /TouchBarServer/TouchBarWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // TouchBarWindow.h 3 | // TouchBar 4 | // 5 | // Created by Robbert Klarenbeek on 12/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TouchBarWindow : NSWindow 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TouchBarServer/TouchBarWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // TouchBarWindow.m 3 | // TouchBar 4 | // 5 | // Created by Robbert Klarenbeek on 12/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import "TouchBarWindow.h" 10 | 11 | #import "TouchBarView.h" 12 | 13 | @interface NSWindow (Private) 14 | - (void )_setPreventsActivation:(bool)preventsActivation; 15 | @end 16 | 17 | @implementation TouchBarWindow 18 | 19 | - (instancetype)init { 20 | self = [super init]; 21 | if(self != nil) { 22 | self.styleMask = NSTitledWindowMask | NSFullSizeContentViewWindowMask; 23 | self.titlebarAppearsTransparent = YES; 24 | self.titleVisibility = NSWindowTitleHidden; 25 | [self standardWindowButton:NSWindowCloseButton].hidden = YES; 26 | [self standardWindowButton:NSWindowFullScreenButton].hidden = YES; 27 | [self standardWindowButton:NSWindowZoomButton].hidden = YES; 28 | [self standardWindowButton:NSWindowMiniaturizeButton].hidden = YES; 29 | 30 | self.movable = NO; 31 | self.acceptsMouseMovedEvents = YES; 32 | self.movableByWindowBackground = NO; 33 | self.level = CGWindowLevelForKey(kCGAssistiveTechHighWindowLevelKey); 34 | self.collectionBehavior = (NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorStationary | NSWindowCollectionBehaviorIgnoresCycle | NSWindowCollectionBehaviorFullScreenDisallowsTiling); 35 | self.backgroundColor = [NSColor blackColor]; 36 | [self _setPreventsActivation:YES]; 37 | [self setFrame:NSMakeRect(0, 0, 1085 + 10, 30 + 10) display:YES]; 38 | 39 | self.contentView = [TouchBarView new]; 40 | } 41 | 42 | return self; 43 | } 44 | 45 | - (BOOL)canBecomeMainWindow { 46 | return NO; 47 | } 48 | 49 | - (BOOL)canBecomeKeyWindow { 50 | return NO; 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /TouchBarServer/UsbDeviceController.h: -------------------------------------------------------------------------------- 1 | // 2 | // UsbDeviceController.h 3 | // TouchBar 4 | // 5 | // Created by Robbert Klarenbeek on 06/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | extern NSErrorDomain const UsbDeviceControllerErrorDomain; 12 | enum { 13 | UsbDeviceControllerDeviceNotAttachedError, 14 | UsbDeviceControllerNotConnectedError, 15 | }; 16 | 17 | @protocol UsbDeviceControllerDelegate 18 | @optional 19 | - (void)deviceDidConnect:(NSNumber *)deviceId ; 20 | - (void)deviceDidDisconnect:(NSNumber *)deviceId; 21 | - (void)device:(NSNumber *)deviceId didReceiveMessageOfType:(uint32_t)type data:(NSData*)data; 22 | @end 23 | 24 | @interface UsbDeviceController : NSObject 25 | @property (nonatomic, assign) int port; 26 | @property (nonatomic, assign) NSTimeInterval retryInterval; 27 | @property (nonatomic, weak) id delegate; 28 | @property (nonatomic, readonly) NSArray *connectedDeviceIds; 29 | - (instancetype)init; 30 | - (instancetype)initWithPort:(int)port; 31 | - (void)startConnectingToUsbDevices; 32 | - (void)stopConnectingToUsbDevices; 33 | - (void)sendMessageToDevice:(NSNumber *)deviceId type:(uint32_t)type data:(NSData *)payload callback:(void(^)(NSError *error))callback; 34 | - (void)broadcastMessageOfType:(uint32_t)type data:(NSData *)data callback:(void(^)(NSDictionary *errors))callback; 35 | @end 36 | -------------------------------------------------------------------------------- /TouchBarServer/UsbDeviceController.m: -------------------------------------------------------------------------------- 1 | // 2 | // UsbDeviceController.m 3 | // TouchBar 4 | // 5 | // Created by Robbert Klarenbeek on 06/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import "UsbDeviceController.h" 10 | 11 | #import "Peertalk.h" 12 | 13 | NSErrorDomain const UsbDeviceControllerErrorDomain = @"com.bikkelbroeders.usbdevicecontroller"; 14 | 15 | @interface NSData (DispatchData) 16 | @property (nonatomic, readonly) dispatch_data_t dispatchData; 17 | @end 18 | 19 | @implementation NSData (DispatchData) 20 | - (dispatch_data_t)dispatchData { 21 | NSData* immutableSelf = [self copy]; 22 | CFDataRef immutableSelfRef = CFBridgingRetain(immutableSelf); 23 | return dispatch_data_create(immutableSelf.bytes, immutableSelf.length, dispatch_get_main_queue(), ^{ 24 | CFRelease(immutableSelfRef); 25 | }); 26 | } 27 | @end 28 | 29 | typedef NS_ENUM(NSUInteger, ConnectionState) { 30 | ConnectionStateNotConnected, 31 | ConnectionStateConnecting, 32 | ConnectionStateConnected, 33 | }; 34 | 35 | @interface AttachedDevice : NSObject 36 | @property (nonatomic, strong) NSNumber *deviceId; 37 | @property (nonatomic, assign) ConnectionState connectionState; 38 | @property (nonatomic, strong) PTChannel *channel; 39 | @end 40 | 41 | @implementation AttachedDevice 42 | - (instancetype)initWithDeviceId:(NSNumber *)deviceId { 43 | self = [self init]; 44 | if (self) { 45 | _deviceId = deviceId; 46 | _connectionState = ConnectionStateNotConnected; 47 | _channel = nil; 48 | } 49 | return self; 50 | } 51 | @end 52 | 53 | @interface UsbDeviceController () 54 | @end 55 | 56 | @implementation UsbDeviceController { 57 | BOOL _isConnecting; 58 | NSMutableDictionary *_attachedDevices; 59 | NSTimer *_connectTimer; 60 | } 61 | 62 | - (instancetype)init { 63 | self = [super init]; 64 | if (self) { 65 | _port = 0; 66 | _retryInterval = 1.0; 67 | _isConnecting = NO; 68 | _attachedDevices = [NSMutableDictionary new]; 69 | _connectTimer = nil; 70 | 71 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 72 | [notificationCenter addObserverForName:PTUSBDeviceDidAttachNotification object:PTUSBHub.sharedHub queue:nil usingBlock:^(NSNotification *note) { 73 | NSNumber *deviceId = note.userInfo[@"DeviceID"]; 74 | if (!_attachedDevices[deviceId]) { 75 | _attachedDevices[deviceId] = [[AttachedDevice alloc] initWithDeviceId:deviceId]; 76 | } 77 | [self restartConnectTimer]; 78 | }]; 79 | [notificationCenter addObserverForName:PTUSBDeviceDidDetachNotification object:PTUSBHub.sharedHub queue:nil usingBlock:^(NSNotification *note) { 80 | NSNumber *deviceId = note.userInfo[@"DeviceID"]; 81 | AttachedDevice *device = _attachedDevices[deviceId]; 82 | if (device) { 83 | if (device.connectionState == ConnectionStateConnected && device.channel) { 84 | [device.channel close]; 85 | } 86 | [_attachedDevices removeObjectForKey:deviceId]; 87 | } 88 | }]; 89 | } 90 | return self; 91 | } 92 | 93 | - (instancetype)initWithPort:(int)port { 94 | self = [self init]; 95 | if (self) { 96 | _port = port; 97 | } 98 | return self; 99 | } 100 | 101 | - (void)setRetryInterval:(NSTimeInterval)retryInterval { 102 | _retryInterval = retryInterval; 103 | [self restartConnectTimer]; 104 | } 105 | 106 | - (void)startConnectingToUsbDevices { 107 | if (_isConnecting) return; 108 | [self startConnectTimer]; 109 | _isConnecting = YES; 110 | } 111 | 112 | - (void)stopConnectingToUsbDevices { 113 | if (!_isConnecting) return; 114 | [self stopConnectTimer]; 115 | _isConnecting = NO; 116 | 117 | for (NSNumber *deviceId in _attachedDevices) { 118 | AttachedDevice *device = _attachedDevices[deviceId]; 119 | if (device.connectionState == ConnectionStateConnected && device.channel) { 120 | [device.channel close]; 121 | } 122 | device.connectionState = ConnectionStateNotConnected; 123 | } 124 | } 125 | 126 | - (NSArray *)connectedDeviceIds { 127 | NSSet *deviceIds = [_attachedDevices keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) { 128 | return [obj connectionState] == ConnectionStateConnected; 129 | }]; 130 | return [deviceIds allObjects]; 131 | } 132 | 133 | - (void)sendMessageToDevice:(NSNumber *)deviceId type:(uint32_t)type data:(NSData *)data callback:(void(^)(NSError *error))callback { 134 | AttachedDevice *device = _attachedDevices[deviceId]; 135 | [self sendToDevice:device type:type payload:[data dispatchData] callback:callback]; 136 | } 137 | 138 | - (void)broadcastMessageOfType:(uint32_t)type data:(NSData *)data callback:(void(^)(NSDictionary *errors))callback { 139 | dispatch_data_t payload = [data dispatchData]; 140 | 141 | NSArray *connectedDeviceIds = self.connectedDeviceIds; 142 | if (connectedDeviceIds.count > 0) { 143 | NSMutableDictionary *results = [NSMutableDictionary new]; 144 | for (NSNumber *deviceId in connectedDeviceIds) { 145 | AttachedDevice *device = _attachedDevices[deviceId]; 146 | if (!device) continue; 147 | [self sendToDevice:device type:type payload:payload callback:^(NSError *error) { 148 | results[device.deviceId] = error ? error : [NSNull null]; 149 | if (results.count == connectedDeviceIds.count && callback) { 150 | NSSet *nullResults = [results keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) { 151 | return [obj isEqual:[NSNull null]]; 152 | }]; 153 | [results removeObjectsForKeys:[nullResults allObjects]]; 154 | callback(results.count > 0 ? results : nil); 155 | } 156 | }]; 157 | } 158 | } else { 159 | callback(nil); 160 | } 161 | } 162 | 163 | #pragma mark - private 164 | 165 | - (void)sendToDevice:(AttachedDevice *)device type:(uint32_t)type payload:(dispatch_data_t)payload callback:(void(^)(NSError *error))callback { 166 | if (!device) { 167 | if (callback) { 168 | NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Device is not attached" }; 169 | callback([NSError errorWithDomain:UsbDeviceControllerErrorDomain code:UsbDeviceControllerDeviceNotAttachedError userInfo:userInfo]); 170 | } 171 | return; 172 | } 173 | 174 | if (device.connectionState != ConnectionStateConnected || !device.channel) { 175 | if (callback) { 176 | NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Device is not connected" }; 177 | callback([NSError errorWithDomain:UsbDeviceControllerErrorDomain code:UsbDeviceControllerNotConnectedError userInfo:userInfo]); 178 | } 179 | return; 180 | } 181 | 182 | [device.channel sendFrameOfType:type tag:PTFrameNoTag withPayload:payload callback:callback]; 183 | } 184 | 185 | - (void)startConnectTimer { 186 | if (!_connectTimer) { 187 | SEL selector = @selector(connectDevices); 188 | _connectTimer = [NSTimer scheduledTimerWithTimeInterval:_retryInterval target:self selector:selector userInfo:nil repeats:YES]; 189 | [self performSelectorOnMainThread:selector withObject:nil waitUntilDone:NO]; 190 | } 191 | } 192 | 193 | - (void)stopConnectTimer { 194 | if (_connectTimer) { 195 | [_connectTimer invalidate]; 196 | _connectTimer = nil; 197 | } 198 | } 199 | 200 | - (void)restartConnectTimer { 201 | // Only restart if we were already running 202 | if (_connectTimer) { 203 | [self stopConnectTimer]; 204 | [self startConnectTimer]; 205 | } 206 | } 207 | 208 | - (void)connectDevices { 209 | for (NSNumber *deviceId in _attachedDevices) { 210 | AttachedDevice *device = _attachedDevices[deviceId]; 211 | if (device.connectionState == ConnectionStateNotConnected) { 212 | device.connectionState = ConnectionStateConnecting; 213 | PTChannel *channel = [PTChannel channelWithDelegate:self]; 214 | channel.userInfo = device; 215 | [channel connectToPort:_port overUSBHub:PTUSBHub.sharedHub deviceID:device.deviceId callback:^(NSError *error) { 216 | if (device.connectionState != ConnectionStateConnecting) return; 217 | 218 | if (error) { 219 | if (error.domain != PTUSBHubErrorDomain || error.code != PTUSBHubErrorConnectionRefused) { 220 | NSLog(@"Failed to connect to device %@: %@", device.deviceId, error); 221 | } 222 | device.connectionState = ConnectionStateNotConnected; 223 | return; 224 | } 225 | device.channel = channel; 226 | device.connectionState = ConnectionStateConnected; 227 | 228 | if([self.delegate respondsToSelector:@selector(deviceDidConnect:)]) { 229 | [self.delegate deviceDidConnect:device.deviceId]; 230 | } 231 | }]; 232 | } 233 | } 234 | } 235 | 236 | #pragma mark - PTChannelDelegate 237 | 238 | - (void)ioFrameChannel:(PTChannel*)channel didReceiveFrameOfType:(uint32_t)type tag:(uint32_t)tag payload:(PTData*)payload { 239 | AttachedDevice *device = channel.userInfo; 240 | if([self.delegate respondsToSelector:@selector(device:didReceiveMessageOfType:data:)]) { 241 | [self.delegate device:device.deviceId didReceiveMessageOfType:type data:[NSData dataWithBytes:payload.data length:payload.length]]; 242 | } 243 | } 244 | 245 | - (void)ioFrameChannel:(PTChannel*)channel didEndWithError:(NSError*)error { 246 | AttachedDevice *device = channel.userInfo; 247 | device.connectionState = ConnectionStateNotConnected; 248 | device.channel = nil; 249 | 250 | if([self.delegate respondsToSelector:@selector(deviceDidDisconnect:)]) { 251 | [self.delegate deviceDidDisconnect:device.deviceId]; 252 | } 253 | } 254 | 255 | @end 256 | -------------------------------------------------------------------------------- /TouchBarServer/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TouchBarServer 4 | // 5 | // Created by Robbert Klarenbeek on 02/11/2016. 6 | // Copyright © 2016 Bikkelbroeders. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) { 12 | return NSApplicationMain(argc, argv); 13 | } 14 | --------------------------------------------------------------------------------