├── .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 | 
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 |
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 |
--------------------------------------------------------------------------------