Changes of Revision 71
obs-studio.changes
Changed
x
1
2
-------------------------------------------------------------------
3
+Fri Dec 13 21:17:57 UTC 2019 - jimmy@boombatower.com
4
+
5
+- Update to version 24.0.5:
6
+ * libobs: Update version to 24.0.5
7
+ * CI: Don't run clang format on some submodule plugins
8
+ * Merge pull request #2010 from wanhongqing123/master
9
+ * Merge pull request #2042 from WizardCM/custom-twitch-docks
10
+ * Merge pull request #2183 from ratwithacompiler/macos-python-fix-2
11
+ * Merge pull request #2085 from ratwithacompiler/macos-python-fix
12
+ * Merge pull request #2090 from jpark37/dxgi-refresh-rate
13
+ * Merge pull request #2089 from jpark37/dxgi-driver-version
14
+ * UI: Delete cookies before connecting account
15
+ * UI: Fix bug in untested/unused function code path
16
+ * deps/media-playback: Don't use interrupt cb for local files
17
+ * deps/media-playback: Don't exit thread on AVERROR_EXIT
18
+ * deps/obs-scripting: Fix formatting
19
+ * Merge pull request #2152 from Rosuav/fix-cursor-position
20
+ * UI: Fix Twitch panels not using dark first time
21
+ * Merge pull request #1914 from YouNow/master
22
+ * Merge pull request #2140 from DevWolk/avn-obs
23
+ * Merge pull request #2045 from wolf247/master
24
+ * Merge pull request #2179 from WizardCM/remove-help-interact
25
+ * Merge pull request #2125 from DDRBoxman/appbundle
26
+ * Merge pull request #2168 from kkartaltepe/vaapi-profile-fix
27
+ * Merge pull request #2148 from eulertour/master
28
+ * Merge pull request #2146 from Fenrirthviti/recording-bitrate-fix
29
+ * libobs: Fix race condition
30
+ * Merge pull request #2147 from JohannMG/vscode-ignore
31
+ * Merge pull request #2134 from WizardCM/wasapi-samplerate
32
+ * Merge pull request #2129 from Fenrirthviti/win-blacklist-update
33
+ * Merge pull request #2131 from jpark37/input-layout-error
34
+ * Merge pull request #2128 from Xaymar/return-to-break
35
+ * Merge pull request #2121 from cg2121/fix-warning
36
+ * Merge pull request #2110 from derrod/ffmpeg-output-fix
37
+ * Merge pull request #2106 from cg2121/fix-preview-bug
38
+ * Merge pull request #2126 from Fenrirthviti/linux-ci-fix
39
+ * Merge pull request #2091 from Programatic/xshm_wrong_windows
40
+ * Merge pull request #2120 from jpark37/objc-msgsend
41
+
42
+-------------------------------------------------------------------
43
Tue Oct 15 14:33:53 UTC 2019 - jimmy@boombatower.com
44
45
- Update to version 24.0.3:
46
obs-studio.spec
Changed
8
1
2
Name: obs-studio
3
-Version: 24.0.3
4
+Version: 24.0.5
5
Release: 0
6
Summary: A recording/broadcasting program
7
Group: Productivity/Multimedia/Video/Editors and Convertors
8
_service
Changed
10
1
2
<services>
3
<service name="tar_scm" mode="disabled">
4
<param name="versionformat">@PARENT_TAG@</param>
5
- <param name="revision">refs/tags/24.0.3</param>
6
+ <param name="revision">refs/tags/24.0.5</param>
7
<param name="url">git://github.com/jp9000/obs-studio.git</param>
8
<param name="scm">git</param>
9
<param name="changesgenerate">enable</param>
10
_servicedata
Changed
9
1
2
<servicedata>
3
<service name="tar_scm">
4
<param name="url">git://github.com/jp9000/obs-studio.git</param>
5
- <param name="changesrevision">d88a5a5a60bcdcbdde6d5dc54dc352ae8d431070</param>
6
+ <param name="changesrevision">99638ba69782bdb10531a305093bbd25e5d3baef</param>
7
</service>
8
</servicedata>
9
obs-studio-24.0.3.tar.xz/libobs/obs-cocoa.c
Deleted
1723
1
2
-/******************************************************************************
3
- Copyright (C) 2013 by Ruwen Hahn <palana@stunned.de>
4
-
5
- This program is free software: you can redistribute it and/or modify
6
- it under the terms of the GNU General Public License as published by
7
- the Free Software Foundation, either version 2 of the License, or
8
- (at your option) any later version.
9
-
10
- This program is distributed in the hope that it will be useful,
11
- but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- GNU General Public License for more details.
14
-
15
- You should have received a copy of the GNU General Public License
16
- along with this program. If not, see <http://www.gnu.org/licenses/>.
17
-******************************************************************************/
18
-
19
-#include "util/platform.h"
20
-#include "util/dstr.h"
21
-#include "obs.h"
22
-#include "obs-internal.h"
23
-
24
-#include <unistd.h>
25
-#include <sys/types.h>
26
-#include <sys/sysctl.h>
27
-
28
-#include <objc/objc.h>
29
-#include <Carbon/Carbon.h>
30
-#include <IOKit/hid/IOHIDDevice.h>
31
-#include <IOKit/hid/IOHIDManager.h>
32
-
33
-const char *get_module_extension(void)
34
-{
35
- return ".so";
36
-}
37
-
38
-static const char *module_bin[] = {
39
- "../obs-plugins",
40
- OBS_INSTALL_PREFIX "obs-plugins",
41
-};
42
-
43
-static const char *module_data[] = {
44
- "../data/obs-plugins/%module%",
45
- OBS_INSTALL_DATA_PATH "obs-plugins/%module%",
46
-};
47
-
48
-static const int module_patterns_size =
49
- sizeof(module_bin) / sizeof(module_bin[0]);
50
-
51
-void add_default_module_paths(void)
52
-{
53
- for (int i = 0; i < module_patterns_size; i++)
54
- obs_add_module_path(module_bin[i], module_data[i]);
55
-}
56
-
57
-char *find_libobs_data_file(const char *file)
58
-{
59
- struct dstr path;
60
- dstr_init_copy(&path, OBS_INSTALL_DATA_PATH "/libobs/");
61
- dstr_cat(&path, file);
62
- return path.array;
63
-}
64
-
65
-static void log_processor_name(void)
66
-{
67
- char *name = NULL;
68
- size_t size;
69
- int ret;
70
-
71
- ret = sysctlbyname("machdep.cpu.brand_string", NULL, &size, NULL, 0);
72
- if (ret != 0)
73
- return;
74
-
75
- name = malloc(size);
76
-
77
- ret = sysctlbyname("machdep.cpu.brand_string", name, &size, NULL, 0);
78
- if (ret == 0)
79
- blog(LOG_INFO, "CPU Name: %s", name);
80
-
81
- free(name);
82
-}
83
-
84
-static void log_processor_speed(void)
85
-{
86
- size_t size;
87
- long long freq;
88
- int ret;
89
-
90
- size = sizeof(freq);
91
- ret = sysctlbyname("hw.cpufrequency", &freq, &size, NULL, 0);
92
- if (ret == 0)
93
- blog(LOG_INFO, "CPU Speed: %lldMHz", freq / 1000000);
94
-}
95
-
96
-static void log_processor_cores(void)
97
-{
98
- blog(LOG_INFO, "Physical Cores: %d, Logical Cores: %d",
99
- os_get_physical_cores(), os_get_logical_cores());
100
-}
101
-
102
-static void log_available_memory(void)
103
-{
104
- size_t size;
105
- long long memory_available;
106
- int ret;
107
-
108
- size = sizeof(memory_available);
109
- ret = sysctlbyname("hw.memsize", &memory_available, &size, NULL, 0);
110
- if (ret == 0)
111
- blog(LOG_INFO, "Physical Memory: %lldMB Total",
112
- memory_available / 1024 / 1024);
113
-}
114
-
115
-static void log_os_name(id pi, SEL UTF8String)
116
-{
117
- unsigned long os_id = (unsigned long)objc_msgSend(
118
- pi, sel_registerName("operatingSystem"));
119
-
120
- id os = objc_msgSend(pi, sel_registerName("operatingSystemName"));
121
- const char *name = (const char *)objc_msgSend(os, UTF8String);
122
-
123
- if (os_id == 5 /*NSMACHOperatingSystem*/) {
124
- blog(LOG_INFO, "OS Name: Mac OS X (%s)", name);
125
- return;
126
- }
127
-
128
- blog(LOG_INFO, "OS Name: %s", name ? name : "Unknown");
129
-}
130
-
131
-static void log_os_version(id pi, SEL UTF8String)
132
-{
133
- id vs = objc_msgSend(pi,
134
- sel_registerName("operatingSystemVersionString"));
135
- const char *version = (const char *)objc_msgSend(vs, UTF8String);
136
-
137
- blog(LOG_INFO, "OS Version: %s", version ? version : "Unknown");
138
-}
139
-
140
-static void log_os(void)
141
-{
142
- Class NSProcessInfo = objc_getClass("NSProcessInfo");
143
- id pi = objc_msgSend((id)NSProcessInfo,
144
- sel_registerName("processInfo"));
145
-
146
- SEL UTF8String = sel_registerName("UTF8String");
147
-
148
- log_os_name(pi, UTF8String);
149
- log_os_version(pi, UTF8String);
150
-}
151
-
152
-static void log_kernel_version(void)
153
-{
154
- char kernel_version[1024];
155
- size_t size = sizeof(kernel_version);
156
- int ret;
157
-
158
- ret = sysctlbyname("kern.osrelease", kernel_version, &size, NULL, 0);
159
- if (ret == 0)
160
- blog(LOG_INFO, "Kernel Version: %s", kernel_version);
161
-}
162
-
163
-void log_system_info(void)
164
-{
165
- log_processor_name();
166
- log_processor_speed();
167
- log_processor_cores();
168
- log_available_memory();
169
- log_os();
170
- log_kernel_version();
171
-}
172
-
173
-static bool dstr_from_cfstring(struct dstr *str, CFStringRef ref)
174
-{
175
- CFIndex length = CFStringGetLength(ref);
176
- CFIndex max_size = CFStringGetMaximumSizeForEncoding(
177
- length, kCFStringEncodingUTF8);
178
- dstr_reserve(str, max_size);
179
-
180
- if (!CFStringGetCString(ref, str->array, max_size,
181
- kCFStringEncodingUTF8))
182
- return false;
183
-
184
- str->len = strlen(str->array);
185
- return true;
186
-}
187
-
188
-struct obs_hotkeys_platform {
189
- volatile long refs;
190
- TISInputSourceRef tis;
191
- CFDataRef layout_data;
192
- UCKeyboardLayout *layout;
193
- IOHIDManagerRef manager;
194
- DARRAY(IOHIDElementRef) keys[OBS_KEY_LAST_VALUE];
195
-};
196
-
197
-static void hotkeys_retain(struct obs_hotkeys_platform *plat)
198
-{
199
- os_atomic_inc_long(&plat->refs);
200
-}
201
-
202
-static inline void free_hotkeys_platform(obs_hotkeys_platform_t *plat);
203
-static void hotkeys_release(struct obs_hotkeys_platform *plat)
204
-{
205
- if (os_atomic_dec_long(&plat->refs) == -1)
206
- free_hotkeys_platform(plat);
207
-}
208
-
209
-#define INVALID_KEY 0xff
210
-
211
-int obs_key_to_virtual_key(obs_key_t code)
212
-{
213
- switch (code) {
214
- case OBS_KEY_A:
215
- return kVK_ANSI_A;
216
- case OBS_KEY_B:
217
- return kVK_ANSI_B;
218
- case OBS_KEY_C:
219
- return kVK_ANSI_C;
220
- case OBS_KEY_D:
221
- return kVK_ANSI_D;
222
- case OBS_KEY_E:
223
- return kVK_ANSI_E;
224
- case OBS_KEY_F:
225
- return kVK_ANSI_F;
226
- case OBS_KEY_G:
227
- return kVK_ANSI_G;
228
- case OBS_KEY_H:
229
- return kVK_ANSI_H;
230
- case OBS_KEY_I:
231
- return kVK_ANSI_I;
232
- case OBS_KEY_J:
233
- return kVK_ANSI_J;
234
- case OBS_KEY_K:
235
- return kVK_ANSI_K;
236
- case OBS_KEY_L:
237
- return kVK_ANSI_L;
238
- case OBS_KEY_M:
239
- return kVK_ANSI_M;
240
- case OBS_KEY_N:
241
- return kVK_ANSI_N;
242
- case OBS_KEY_O:
243
- return kVK_ANSI_O;
244
- case OBS_KEY_P:
245
- return kVK_ANSI_P;
246
- case OBS_KEY_Q:
247
- return kVK_ANSI_Q;
248
- case OBS_KEY_R:
249
- return kVK_ANSI_R;
250
- case OBS_KEY_S:
251
- return kVK_ANSI_S;
252
- case OBS_KEY_T:
253
- return kVK_ANSI_T;
254
- case OBS_KEY_U:
255
- return kVK_ANSI_U;
256
- case OBS_KEY_V:
257
- return kVK_ANSI_V;
258
- case OBS_KEY_W:
259
- return kVK_ANSI_W;
260
- case OBS_KEY_X:
261
- return kVK_ANSI_X;
262
- case OBS_KEY_Y:
263
- return kVK_ANSI_Y;
264
- case OBS_KEY_Z:
265
- return kVK_ANSI_Z;
266
-
267
- case OBS_KEY_1:
268
- return kVK_ANSI_1;
269
- case OBS_KEY_2:
270
- return kVK_ANSI_2;
271
- case OBS_KEY_3:
272
- return kVK_ANSI_3;
273
- case OBS_KEY_4:
274
- return kVK_ANSI_4;
275
- case OBS_KEY_5:
276
- return kVK_ANSI_5;
277
- case OBS_KEY_6:
278
- return kVK_ANSI_6;
279
- case OBS_KEY_7:
280
- return kVK_ANSI_7;
281
- case OBS_KEY_8:
282
- return kVK_ANSI_8;
283
- case OBS_KEY_9:
284
- return kVK_ANSI_9;
285
- case OBS_KEY_0:
286
- return kVK_ANSI_0;
287
-
288
- case OBS_KEY_RETURN:
289
- return kVK_Return;
290
- case OBS_KEY_ESCAPE:
291
- return kVK_Escape;
292
- case OBS_KEY_BACKSPACE:
293
- return kVK_Delete;
294
- case OBS_KEY_TAB:
295
- return kVK_Tab;
296
- case OBS_KEY_SPACE:
297
- return kVK_Space;
298
- case OBS_KEY_MINUS:
299
- return kVK_ANSI_Minus;
300
- case OBS_KEY_EQUAL:
301
- return kVK_ANSI_Equal;
302
- case OBS_KEY_BRACKETLEFT:
303
- return kVK_ANSI_LeftBracket;
304
- case OBS_KEY_BRACKETRIGHT:
305
- return kVK_ANSI_RightBracket;
306
- case OBS_KEY_BACKSLASH:
307
- return kVK_ANSI_Backslash;
308
- case OBS_KEY_SEMICOLON:
309
- return kVK_ANSI_Semicolon;
310
- case OBS_KEY_QUOTE:
311
- return kVK_ANSI_Quote;
312
- case OBS_KEY_DEAD_GRAVE:
313
- return kVK_ANSI_Grave;
314
- case OBS_KEY_COMMA:
315
- return kVK_ANSI_Comma;
316
- case OBS_KEY_PERIOD:
317
- return kVK_ANSI_Period;
318
- case OBS_KEY_SLASH:
319
- return kVK_ANSI_Slash;
320
- case OBS_KEY_CAPSLOCK:
321
- return kVK_CapsLock;
322
- case OBS_KEY_SECTION:
323
- return kVK_ISO_Section;
324
-
325
- case OBS_KEY_F1:
326
- return kVK_F1;
327
- case OBS_KEY_F2:
328
- return kVK_F2;
329
- case OBS_KEY_F3:
330
- return kVK_F3;
331
- case OBS_KEY_F4:
332
- return kVK_F4;
333
- case OBS_KEY_F5:
334
- return kVK_F5;
335
- case OBS_KEY_F6:
336
- return kVK_F6;
337
- case OBS_KEY_F7:
338
- return kVK_F7;
339
- case OBS_KEY_F8:
340
- return kVK_F8;
341
- case OBS_KEY_F9:
342
- return kVK_F9;
343
- case OBS_KEY_F10:
344
- return kVK_F10;
345
- case OBS_KEY_F11:
346
- return kVK_F11;
347
- case OBS_KEY_F12:
348
- return kVK_F12;
349
-
350
- case OBS_KEY_HELP:
351
- return kVK_Help;
352
- case OBS_KEY_HOME:
353
- return kVK_Home;
354
- case OBS_KEY_PAGEUP:
355
- return kVK_PageUp;
356
- case OBS_KEY_DELETE:
357
- return kVK_ForwardDelete;
358
- case OBS_KEY_END:
359
- return kVK_End;
360
- case OBS_KEY_PAGEDOWN:
361
- return kVK_PageDown;
362
-
363
- case OBS_KEY_RIGHT:
364
- return kVK_RightArrow;
365
- case OBS_KEY_LEFT:
366
- return kVK_LeftArrow;
367
- case OBS_KEY_DOWN:
368
- return kVK_DownArrow;
369
- case OBS_KEY_UP:
370
- return kVK_UpArrow;
371
-
372
- case OBS_KEY_CLEAR:
373
- return kVK_ANSI_KeypadClear;
374
- case OBS_KEY_NUMSLASH:
375
- return kVK_ANSI_KeypadDivide;
376
- case OBS_KEY_NUMASTERISK:
377
- return kVK_ANSI_KeypadMultiply;
378
- case OBS_KEY_NUMMINUS:
379
- return kVK_ANSI_KeypadMinus;
380
- case OBS_KEY_NUMPLUS:
381
- return kVK_ANSI_KeypadPlus;
382
- case OBS_KEY_ENTER:
383
- return kVK_ANSI_KeypadEnter;
384
-
385
- case OBS_KEY_NUM1:
386
- return kVK_ANSI_Keypad1;
387
- case OBS_KEY_NUM2:
388
- return kVK_ANSI_Keypad2;
389
- case OBS_KEY_NUM3:
390
- return kVK_ANSI_Keypad3;
391
- case OBS_KEY_NUM4:
392
- return kVK_ANSI_Keypad4;
393
- case OBS_KEY_NUM5:
394
- return kVK_ANSI_Keypad5;
395
- case OBS_KEY_NUM6:
396
- return kVK_ANSI_Keypad6;
397
- case OBS_KEY_NUM7:
398
- return kVK_ANSI_Keypad7;
399
- case OBS_KEY_NUM8:
400
- return kVK_ANSI_Keypad8;
401
- case OBS_KEY_NUM9:
402
- return kVK_ANSI_Keypad9;
403
- case OBS_KEY_NUM0:
404
- return kVK_ANSI_Keypad0;
405
-
406
- case OBS_KEY_NUMPERIOD:
407
- return kVK_ANSI_KeypadDecimal;
408
- case OBS_KEY_NUMEQUAL:
409
- return kVK_ANSI_KeypadEquals;
410
-
411
- case OBS_KEY_F13:
412
- return kVK_F13;
413
- case OBS_KEY_F14:
414
- return kVK_F14;
415
- case OBS_KEY_F15:
416
- return kVK_F15;
417
- case OBS_KEY_F16:
418
- return kVK_F16;
419
- case OBS_KEY_F17:
420
- return kVK_F17;
421
- case OBS_KEY_F18:
422
- return kVK_F18;
423
- case OBS_KEY_F19:
424
- return kVK_F19;
425
- case OBS_KEY_F20:
426
- return kVK_F20;
427
-
428
- case OBS_KEY_CONTROL:
429
- return kVK_Control;
430
- case OBS_KEY_SHIFT:
431
- return kVK_Shift;
432
- case OBS_KEY_ALT:
433
- return kVK_Option;
434
- case OBS_KEY_META:
435
- return kVK_Command;
436
- //case OBS_KEY_CONTROL: return kVK_RightControl;
437
- //case OBS_KEY_SHIFT: return kVK_RightShift;
438
- //case OBS_KEY_ALT: return kVK_RightOption;
439
- //case OBS_KEY_META: return 0x36;
440
-
441
- case OBS_KEY_NONE:
442
- case OBS_KEY_LAST_VALUE:
443
- default:
444
- break;
445
- }
446
- return INVALID_KEY;
447
-}
448
-
449
-static bool localized_key_to_str(obs_key_t key, struct dstr *str)
450
-{
451
-#define MAP_KEY(k, s) \
452
- case k: \
453
- dstr_copy(str, obs_get_hotkey_translation(k, s)); \
454
- return true
455
-
456
-#define MAP_BUTTON(i) \
457
- case OBS_KEY_MOUSE##i: \
458
- dstr_copy(str, obs_get_hotkey_translation(key, "Mouse " #i)); \
459
- return true
460
-
461
- switch (key) {
462
- MAP_KEY(OBS_KEY_SPACE, "Space");
463
- MAP_KEY(OBS_KEY_NUMEQUAL, "= (Keypad)");
464
- MAP_KEY(OBS_KEY_NUMASTERISK, "* (Keypad)");
465
- MAP_KEY(OBS_KEY_NUMPLUS, "+ (Keypad)");
466
- MAP_KEY(OBS_KEY_NUMMINUS, "- (Keypad)");
467
- MAP_KEY(OBS_KEY_NUMPERIOD, ". (Keypad)");
468
- MAP_KEY(OBS_KEY_NUMSLASH, "/ (Keypad)");
469
- MAP_KEY(OBS_KEY_NUM0, "0 (Keypad)");
470
- MAP_KEY(OBS_KEY_NUM1, "1 (Keypad)");
471
- MAP_KEY(OBS_KEY_NUM2, "2 (Keypad)");
472
- MAP_KEY(OBS_KEY_NUM3, "3 (Keypad)");
473
- MAP_KEY(OBS_KEY_NUM4, "4 (Keypad)");
474
- MAP_KEY(OBS_KEY_NUM5, "5 (Keypad)");
475
- MAP_KEY(OBS_KEY_NUM6, "6 (Keypad)");
476
- MAP_KEY(OBS_KEY_NUM7, "7 (Keypad)");
477
- MAP_KEY(OBS_KEY_NUM8, "8 (Keypad)");
478
- MAP_KEY(OBS_KEY_NUM9, "9 (Keypad)");
479
-
480
- MAP_BUTTON(1);
481
- MAP_BUTTON(2);
482
- MAP_BUTTON(3);
483
- MAP_BUTTON(4);
484
- MAP_BUTTON(5);
485
- MAP_BUTTON(6);
486
- MAP_BUTTON(7);
487
- MAP_BUTTON(8);
488
- MAP_BUTTON(9);
489
- MAP_BUTTON(10);
490
- MAP_BUTTON(11);
491
- MAP_BUTTON(12);
492
- MAP_BUTTON(13);
493
- MAP_BUTTON(14);
494
- MAP_BUTTON(15);
495
- MAP_BUTTON(16);
496
- MAP_BUTTON(17);
497
- MAP_BUTTON(18);
498
- MAP_BUTTON(19);
499
- MAP_BUTTON(20);
500
- MAP_BUTTON(21);
501
- MAP_BUTTON(22);
502
- MAP_BUTTON(23);
503
- MAP_BUTTON(24);
504
- MAP_BUTTON(25);
505
- MAP_BUTTON(26);
506
- MAP_BUTTON(27);
507
- MAP_BUTTON(28);
508
- MAP_BUTTON(29);
509
- default:
510
- break;
511
- }
512
-#undef MAP_BUTTON
513
-#undef MAP_KEY
514
-
515
- return false;
516
-}
517
-
518
-static bool code_to_str(int code, struct dstr *str)
519
-{
520
-#define MAP_GLYPH(c, g) \
521
- case c: \
522
- dstr_from_wcs(str, (wchar_t[]){g, 0}); \
523
- return true
524
-#define MAP_STR(c, s) \
525
- case c: \
526
- dstr_copy(str, s); \
527
- return true
528
- switch (code) {
529
- MAP_GLYPH(kVK_Return, 0x21A9);
530
- MAP_GLYPH(kVK_Escape, 0x238B);
531
- MAP_GLYPH(kVK_Delete, 0x232B);
532
- MAP_GLYPH(kVK_Tab, 0x21e5);
533
- MAP_GLYPH(kVK_CapsLock, 0x21EA);
534
- MAP_GLYPH(kVK_ANSI_KeypadClear, 0x2327);
535
- MAP_GLYPH(kVK_ANSI_KeypadEnter, 0x2305);
536
- MAP_GLYPH(kVK_Help, 0x003F);
537
- MAP_GLYPH(kVK_Home, 0x2196);
538
- MAP_GLYPH(kVK_PageUp, 0x21de);
539
- MAP_GLYPH(kVK_ForwardDelete, 0x2326);
540
- MAP_GLYPH(kVK_End, 0x2198);
541
- MAP_GLYPH(kVK_PageDown, 0x21df);
542
-
543
- MAP_GLYPH(kVK_RightArrow, 0x2192);
544
- MAP_GLYPH(kVK_LeftArrow, 0x2190);
545
- MAP_GLYPH(kVK_DownArrow, 0x2193);
546
- MAP_GLYPH(kVK_UpArrow, 0x2191);
547
-
548
- MAP_STR(kVK_F1, "F1");
549
- MAP_STR(kVK_F2, "F2");
550
- MAP_STR(kVK_F3, "F3");
551
- MAP_STR(kVK_F4, "F4");
552
- MAP_STR(kVK_F5, "F5");
553
- MAP_STR(kVK_F6, "F6");
554
- MAP_STR(kVK_F7, "F7");
555
- MAP_STR(kVK_F8, "F8");
556
- MAP_STR(kVK_F9, "F9");
557
- MAP_STR(kVK_F10, "F10");
558
- MAP_STR(kVK_F11, "F11");
559
- MAP_STR(kVK_F12, "F12");
560
- MAP_STR(kVK_F13, "F13");
561
- MAP_STR(kVK_F14, "F14");
562
- MAP_STR(kVK_F15, "F15");
563
- MAP_STR(kVK_F16, "F16");
564
- MAP_STR(kVK_F17, "F17");
565
- MAP_STR(kVK_F18, "F18");
566
- MAP_STR(kVK_F19, "F19");
567
- MAP_STR(kVK_F20, "F20");
568
- MAP_GLYPH(kVK_Control, kControlUnicode);
569
- MAP_GLYPH(kVK_Shift, kShiftUnicode);
570
- MAP_GLYPH(kVK_Option, kOptionUnicode);
571
- MAP_GLYPH(kVK_Command, kCommandUnicode);
572
- MAP_GLYPH(kVK_RightControl, kControlUnicode);
573
- MAP_GLYPH(kVK_RightShift, kShiftUnicode);
574
- MAP_GLYPH(kVK_RightOption, kOptionUnicode);
575
- }
576
-#undef MAP_STR
577
-#undef MAP_GLYPH
578
-
579
- return false;
580
-}
581
-
582
-void obs_key_to_str(obs_key_t key, struct dstr *str)
583
-{
584
- if (localized_key_to_str(key, str))
585
- return;
586
-
587
- int code = obs_key_to_virtual_key(key);
588
- if (code_to_str(code, str))
589
- return;
590
-
591
- if (code == INVALID_KEY) {
592
- blog(LOG_ERROR,
593
- "hotkey-cocoa: Got invalid key while "
594
- "translating key '%d' (%s)",
595
- key, obs_key_to_name(key));
596
- goto err;
597
- }
598
-
599
- struct obs_hotkeys_platform *plat = NULL;
600
-
601
- if (obs) {
602
- pthread_mutex_lock(&obs->hotkeys.mutex);
603
- plat = obs->hotkeys.platform_context;
604
- hotkeys_retain(plat);
605
- pthread_mutex_unlock(&obs->hotkeys.mutex);
606
- }
607
-
608
- if (!plat) {
609
- blog(LOG_ERROR,
610
- "hotkey-cocoa: Could not get hotkey platform "
611
- "while translating key '%d' (%s)",
612
- key, obs_key_to_name(key));
613
- goto err;
614
- }
615
-
616
- const UniCharCount max_length = 16;
617
- UInt32 dead_key_state = 0;
618
- UniChar buffer[max_length];
619
- UniCharCount len = 0;
620
-
621
- OSStatus err =
622
- UCKeyTranslate(plat->layout, code, kUCKeyActionDown,
623
- 0x104, //caps lock for upper case letters
624
- LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit,
625
- &dead_key_state, max_length, &len, buffer);
626
-
627
- if (err == noErr && len <= 0 && dead_key_state) {
628
- err = UCKeyTranslate(plat->layout, kVK_Space, kUCKeyActionDown,
629
- 0x104, LMGetKbdType(),
630
- kUCKeyTranslateNoDeadKeysBit,
631
- &dead_key_state, max_length, &len, buffer);
632
- }
633
-
634
- hotkeys_release(plat);
635
-
636
- if (err != noErr) {
637
- blog(LOG_ERROR,
638
- "hotkey-cocoa: Error while translating key '%d'"
639
- " (0x%x, %s) to string: %d",
640
- key, code, obs_key_to_name(key), err);
641
- goto err;
642
- }
643
-
644
- if (len == 0) {
645
- blog(LOG_ERROR,
646
- "hotkey-cocoa: Got 0 length string while "
647
- "translating '%d' (0x%x, %s) to string",
648
- key, code, obs_key_to_name(key));
649
- goto err;
650
- }
651
-
652
- CFStringRef string = CFStringCreateWithCharactersNoCopy(
653
- NULL, buffer, len, kCFAllocatorNull);
654
- if (!string) {
655
- blog(LOG_ERROR,
656
- "hotkey-cocoa: Could not create CFStringRef "
657
- "while translating '%d' (0x%x, %s) to string",
658
- key, code, obs_key_to_name(key));
659
- goto err;
660
- }
661
-
662
- if (!dstr_from_cfstring(str, string)) {
663
- blog(LOG_ERROR,
664
- "hotkey-cocoa: Could not translate CFStringRef "
665
- "to CString while translating '%d' (0x%x, %s)",
666
- key, code, obs_key_to_name(key));
667
-
668
- goto release;
669
- }
670
-
671
- CFRelease(string);
672
- return;
673
-
674
-release:
675
- CFRelease(string);
676
-err:
677
- dstr_copy(str, obs_key_to_name(key));
678
-}
679
-
680
-#define OBS_COCOA_MODIFIER_SIZE 7
681
-static void unichar_to_utf8(const UniChar *c, char *buff)
682
-{
683
- CFStringRef string = CFStringCreateWithCharactersNoCopy(
684
- NULL, c, 2, kCFAllocatorNull);
685
- if (!string) {
686
- blog(LOG_ERROR, "hotkey-cocoa: Could not create CFStringRef "
687
- "while populating modifier strings");
688
- return;
689
- }
690
-
691
- if (!CFStringGetCString(string, buff, OBS_COCOA_MODIFIER_SIZE,
692
- kCFStringEncodingUTF8))
693
- blog(LOG_ERROR,
694
- "hotkey-cocoa: Error while populating "
695
- " modifier string with glyph %d (0x%x)",
696
- c[0], c[0]);
697
-
698
- CFRelease(string);
699
-}
700
-
701
-static char ctrl_str[OBS_COCOA_MODIFIER_SIZE];
702
-static char opt_str[OBS_COCOA_MODIFIER_SIZE];
703
-static char shift_str[OBS_COCOA_MODIFIER_SIZE];
704
-static char cmd_str[OBS_COCOA_MODIFIER_SIZE];
705
-static void init_utf_8_strings(void)
706
-{
707
- const UniChar ctrl_uni[] = {kControlUnicode, 0};
708
- const UniChar opt_uni[] = {kOptionUnicode, 0};
709
- const UniChar shift_uni[] = {kShiftUnicode, 0};
710
- const UniChar cmd_uni[] = {kCommandUnicode, 0};
711
-
712
- unichar_to_utf8(ctrl_uni, ctrl_str);
713
- unichar_to_utf8(opt_uni, opt_str);
714
- unichar_to_utf8(shift_uni, shift_str);
715
- unichar_to_utf8(cmd_uni, cmd_str);
716
-}
717
-
718
-static pthread_once_t strings_token = PTHREAD_ONCE_INIT;
719
-void obs_key_combination_to_str(obs_key_combination_t key, struct dstr *str)
720
-{
721
- struct dstr key_str = {0};
722
- if (key.key != OBS_KEY_NONE)
723
- obs_key_to_str(key.key, &key_str);
724
-
725
- int res = pthread_once(&strings_token, init_utf_8_strings);
726
- if (res) {
727
- blog(LOG_ERROR,
728
- "hotkeys-cocoa: Error while translating "
729
- "modifiers %d (0x%x)",
730
- res, res);
731
- dstr_move(str, &key_str);
732
- return;
733
- }
734
-
735
-#define CHECK_MODIFIER(mod, str) ((key.modifiers & mod) ? str : "")
736
- dstr_printf(str, "%s%s%s%s%s",
737
- CHECK_MODIFIER(INTERACT_CONTROL_KEY, ctrl_str),
738
- CHECK_MODIFIER(INTERACT_ALT_KEY, opt_str),
739
- CHECK_MODIFIER(INTERACT_SHIFT_KEY, shift_str),
740
- CHECK_MODIFIER(INTERACT_COMMAND_KEY, cmd_str),
741
- key_str.len ? key_str.array : "");
742
-#undef CHECK_MODIFIER
743
-
744
- dstr_free(&key_str);
745
-}
746
-
747
-static inline CFDictionaryRef copy_device_mask(UInt32 page, UInt32 usage)
748
-{
749
- CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
750
- kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks,
751
- &kCFTypeDictionaryValueCallBacks);
752
-
753
- CFNumberRef value;
754
- // Add the page value.
755
- value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
756
- CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), value);
757
- CFRelease(value);
758
-
759
- // Add the usage value (which is only valid if page value exists).
760
- value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
761
- CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), value);
762
- CFRelease(value);
763
-
764
- return dict;
765
-}
766
-
767
-static CFSetRef copy_devices(obs_hotkeys_platform_t *plat, UInt32 page,
768
- UInt32 usage)
769
-{
770
- CFDictionaryRef mask = copy_device_mask(page, usage);
771
- IOHIDManagerSetDeviceMatching(plat->manager, mask);
772
- CFRelease(mask);
773
-
774
- CFSetRef devices = IOHIDManagerCopyDevices(plat->manager);
775
- if (!devices)
776
- return NULL;
777
-
778
- if (CFSetGetCount(devices) < 1) {
779
- CFRelease(devices);
780
- return NULL;
781
- }
782
-
783
- return devices;
784
-}
785
-
786
-static UInt16 usage_to_carbon(UInt32 usage)
787
-{
788
- switch (usage) {
789
- case kHIDUsage_KeyboardErrorRollOver:
790
- return INVALID_KEY;
791
- case kHIDUsage_KeyboardPOSTFail:
792
- return INVALID_KEY;
793
- case kHIDUsage_KeyboardErrorUndefined:
794
- return INVALID_KEY;
795
-
796
- case kHIDUsage_KeyboardA:
797
- return kVK_ANSI_A;
798
- case kHIDUsage_KeyboardB:
799
- return kVK_ANSI_B;
800
- case kHIDUsage_KeyboardC:
801
- return kVK_ANSI_C;
802
- case kHIDUsage_KeyboardD:
803
- return kVK_ANSI_D;
804
- case kHIDUsage_KeyboardE:
805
- return kVK_ANSI_E;
806
- case kHIDUsage_KeyboardF:
807
- return kVK_ANSI_F;
808
- case kHIDUsage_KeyboardG:
809
- return kVK_ANSI_G;
810
- case kHIDUsage_KeyboardH:
811
- return kVK_ANSI_H;
812
- case kHIDUsage_KeyboardI:
813
- return kVK_ANSI_I;
814
- case kHIDUsage_KeyboardJ:
815
- return kVK_ANSI_J;
816
- case kHIDUsage_KeyboardK:
817
- return kVK_ANSI_K;
818
- case kHIDUsage_KeyboardL:
819
- return kVK_ANSI_L;
820
- case kHIDUsage_KeyboardM:
821
- return kVK_ANSI_M;
822
- case kHIDUsage_KeyboardN:
823
- return kVK_ANSI_N;
824
- case kHIDUsage_KeyboardO:
825
- return kVK_ANSI_O;
826
- case kHIDUsage_KeyboardP:
827
- return kVK_ANSI_P;
828
- case kHIDUsage_KeyboardQ:
829
- return kVK_ANSI_Q;
830
- case kHIDUsage_KeyboardR:
831
- return kVK_ANSI_R;
832
- case kHIDUsage_KeyboardS:
833
- return kVK_ANSI_S;
834
- case kHIDUsage_KeyboardT:
835
- return kVK_ANSI_T;
836
- case kHIDUsage_KeyboardU:
837
- return kVK_ANSI_U;
838
- case kHIDUsage_KeyboardV:
839
- return kVK_ANSI_V;
840
- case kHIDUsage_KeyboardW:
841
- return kVK_ANSI_W;
842
- case kHIDUsage_KeyboardX:
843
- return kVK_ANSI_X;
844
- case kHIDUsage_KeyboardY:
845
- return kVK_ANSI_Y;
846
- case kHIDUsage_KeyboardZ:
847
- return kVK_ANSI_Z;
848
-
849
- case kHIDUsage_Keyboard1:
850
- return kVK_ANSI_1;
851
- case kHIDUsage_Keyboard2:
852
- return kVK_ANSI_2;
853
- case kHIDUsage_Keyboard3:
854
- return kVK_ANSI_3;
855
- case kHIDUsage_Keyboard4:
856
- return kVK_ANSI_4;
857
- case kHIDUsage_Keyboard5:
858
- return kVK_ANSI_5;
859
- case kHIDUsage_Keyboard6:
860
- return kVK_ANSI_6;
861
- case kHIDUsage_Keyboard7:
862
- return kVK_ANSI_7;
863
- case kHIDUsage_Keyboard8:
864
- return kVK_ANSI_8;
865
- case kHIDUsage_Keyboard9:
866
- return kVK_ANSI_9;
867
- case kHIDUsage_Keyboard0:
868
- return kVK_ANSI_0;
869
-
870
- case kHIDUsage_KeyboardReturnOrEnter:
871
- return kVK_Return;
872
- case kHIDUsage_KeyboardEscape:
873
- return kVK_Escape;
874
- case kHIDUsage_KeyboardDeleteOrBackspace:
875
- return kVK_Delete;
876
- case kHIDUsage_KeyboardTab:
877
- return kVK_Tab;
878
- case kHIDUsage_KeyboardSpacebar:
879
- return kVK_Space;
880
- case kHIDUsage_KeyboardHyphen:
881
- return kVK_ANSI_Minus;
882
- case kHIDUsage_KeyboardEqualSign:
883
- return kVK_ANSI_Equal;
884
- case kHIDUsage_KeyboardOpenBracket:
885
- return kVK_ANSI_LeftBracket;
886
- case kHIDUsage_KeyboardCloseBracket:
887
- return kVK_ANSI_RightBracket;
888
- case kHIDUsage_KeyboardBackslash:
889
- return kVK_ANSI_Backslash;
890
- case kHIDUsage_KeyboardNonUSPound:
891
- return INVALID_KEY;
892
- case kHIDUsage_KeyboardSemicolon:
893
- return kVK_ANSI_Semicolon;
894
- case kHIDUsage_KeyboardQuote:
895
- return kVK_ANSI_Quote;
896
- case kHIDUsage_KeyboardGraveAccentAndTilde:
897
- return kVK_ANSI_Grave;
898
- case kHIDUsage_KeyboardComma:
899
- return kVK_ANSI_Comma;
900
- case kHIDUsage_KeyboardPeriod:
901
- return kVK_ANSI_Period;
902
- case kHIDUsage_KeyboardSlash:
903
- return kVK_ANSI_Slash;
904
- case kHIDUsage_KeyboardCapsLock:
905
- return kVK_CapsLock;
906
-
907
- case kHIDUsage_KeyboardF1:
908
- return kVK_F1;
909
- case kHIDUsage_KeyboardF2:
910
- return kVK_F2;
911
- case kHIDUsage_KeyboardF3:
912
- return kVK_F3;
913
- case kHIDUsage_KeyboardF4:
914
- return kVK_F4;
915
- case kHIDUsage_KeyboardF5:
916
- return kVK_F5;
917
- case kHIDUsage_KeyboardF6:
918
- return kVK_F6;
919
- case kHIDUsage_KeyboardF7:
920
- return kVK_F7;
921
- case kHIDUsage_KeyboardF8:
922
- return kVK_F8;
923
- case kHIDUsage_KeyboardF9:
924
- return kVK_F9;
925
- case kHIDUsage_KeyboardF10:
926
- return kVK_F10;
927
- case kHIDUsage_KeyboardF11:
928
- return kVK_F11;
929
- case kHIDUsage_KeyboardF12:
930
- return kVK_F12;
931
-
932
- case kHIDUsage_KeyboardPrintScreen:
933
- return INVALID_KEY;
934
- case kHIDUsage_KeyboardScrollLock:
935
- return INVALID_KEY;
936
- case kHIDUsage_KeyboardPause:
937
- return INVALID_KEY;
938
- case kHIDUsage_KeyboardInsert:
939
- return kVK_Help;
940
- case kHIDUsage_KeyboardHome:
941
- return kVK_Home;
942
- case kHIDUsage_KeyboardPageUp:
943
- return kVK_PageUp;
944
- case kHIDUsage_KeyboardDeleteForward:
945
- return kVK_ForwardDelete;
946
- case kHIDUsage_KeyboardEnd:
947
- return kVK_End;
948
- case kHIDUsage_KeyboardPageDown:
949
- return kVK_PageDown;
950
-
951
- case kHIDUsage_KeyboardRightArrow:
952
- return kVK_RightArrow;
953
- case kHIDUsage_KeyboardLeftArrow:
954
- return kVK_LeftArrow;
955
- case kHIDUsage_KeyboardDownArrow:
956
- return kVK_DownArrow;
957
- case kHIDUsage_KeyboardUpArrow:
958
- return kVK_UpArrow;
959
-
960
- case kHIDUsage_KeypadNumLock:
961
- return kVK_ANSI_KeypadClear;
962
- case kHIDUsage_KeypadSlash:
963
- return kVK_ANSI_KeypadDivide;
964
- case kHIDUsage_KeypadAsterisk:
965
- return kVK_ANSI_KeypadMultiply;
966
- case kHIDUsage_KeypadHyphen:
967
- return kVK_ANSI_KeypadMinus;
968
- case kHIDUsage_KeypadPlus:
969
- return kVK_ANSI_KeypadPlus;
970
- case kHIDUsage_KeypadEnter:
971
- return kVK_ANSI_KeypadEnter;
972
-
973
- case kHIDUsage_Keypad1:
974
- return kVK_ANSI_Keypad1;
975
- case kHIDUsage_Keypad2:
976
- return kVK_ANSI_Keypad2;
977
- case kHIDUsage_Keypad3:
978
- return kVK_ANSI_Keypad3;
979
- case kHIDUsage_Keypad4:
980
- return kVK_ANSI_Keypad4;
981
- case kHIDUsage_Keypad5:
982
- return kVK_ANSI_Keypad5;
983
- case kHIDUsage_Keypad6:
984
- return kVK_ANSI_Keypad6;
985
- case kHIDUsage_Keypad7:
986
- return kVK_ANSI_Keypad7;
987
- case kHIDUsage_Keypad8:
988
- return kVK_ANSI_Keypad8;
989
- case kHIDUsage_Keypad9:
990
- return kVK_ANSI_Keypad9;
991
- case kHIDUsage_Keypad0:
992
- return kVK_ANSI_Keypad0;
993
-
994
- case kHIDUsage_KeypadPeriod:
995
- return kVK_ANSI_KeypadDecimal;
996
- case kHIDUsage_KeyboardNonUSBackslash:
997
- return INVALID_KEY;
998
- case kHIDUsage_KeyboardApplication:
999
- return kVK_F13;
1000
- case kHIDUsage_KeyboardPower:
1001
- return INVALID_KEY;
1002
- case kHIDUsage_KeypadEqualSign:
1003
- return kVK_ANSI_KeypadEquals;
1004
-
1005
- case kHIDUsage_KeyboardF13:
1006
- return kVK_F13;
1007
- case kHIDUsage_KeyboardF14:
1008
- return kVK_F14;
1009
- case kHIDUsage_KeyboardF15:
1010
- return kVK_F15;
1011
- case kHIDUsage_KeyboardF16:
1012
- return kVK_F16;
1013
- case kHIDUsage_KeyboardF17:
1014
- return kVK_F17;
1015
- case kHIDUsage_KeyboardF18:
1016
- return kVK_F18;
1017
- case kHIDUsage_KeyboardF19:
1018
- return kVK_F19;
1019
- case kHIDUsage_KeyboardF20:
1020
- return kVK_F20;
1021
- case kHIDUsage_KeyboardF21:
1022
- return INVALID_KEY;
1023
- case kHIDUsage_KeyboardF22:
1024
- return INVALID_KEY;
1025
- case kHIDUsage_KeyboardF23:
1026
- return INVALID_KEY;
1027
- case kHIDUsage_KeyboardF24:
1028
- return INVALID_KEY;
1029
-
1030
- case kHIDUsage_KeyboardExecute:
1031
- return INVALID_KEY;
1032
- case kHIDUsage_KeyboardHelp:
1033
- return INVALID_KEY;
1034
- case kHIDUsage_KeyboardMenu:
1035
- return 0x7F;
1036
- case kHIDUsage_KeyboardSelect:
1037
- return kVK_ANSI_KeypadEnter;
1038
- case kHIDUsage_KeyboardStop:
1039
- return INVALID_KEY;
1040
- case kHIDUsage_KeyboardAgain:
1041
- return INVALID_KEY;
1042
- case kHIDUsage_KeyboardUndo:
1043
- return INVALID_KEY;
1044
- case kHIDUsage_KeyboardCut:
1045
- return INVALID_KEY;
1046
- case kHIDUsage_KeyboardCopy:
1047
- return INVALID_KEY;
1048
- case kHIDUsage_KeyboardPaste:
1049
- return INVALID_KEY;
1050
- case kHIDUsage_KeyboardFind:
1051
- return INVALID_KEY;
1052
-
1053
- case kHIDUsage_KeyboardMute:
1054
- return kVK_Mute;
1055
- case kHIDUsage_KeyboardVolumeUp:
1056
- return kVK_VolumeUp;
1057
- case kHIDUsage_KeyboardVolumeDown:
1058
- return kVK_VolumeDown;
1059
-
1060
- case kHIDUsage_KeyboardLockingCapsLock:
1061
- return INVALID_KEY;
1062
- case kHIDUsage_KeyboardLockingNumLock:
1063
- return INVALID_KEY;
1064
- case kHIDUsage_KeyboardLockingScrollLock:
1065
- return INVALID_KEY;
1066
-
1067
- case kHIDUsage_KeypadComma:
1068
- return INVALID_KEY;
1069
- case kHIDUsage_KeypadEqualSignAS400:
1070
- return INVALID_KEY;
1071
- case kHIDUsage_KeyboardInternational1:
1072
- return INVALID_KEY;
1073
- case kHIDUsage_KeyboardInternational2:
1074
- return INVALID_KEY;
1075
- case kHIDUsage_KeyboardInternational3:
1076
- return INVALID_KEY;
1077
- case kHIDUsage_KeyboardInternational4:
1078
- return INVALID_KEY;
1079
- case kHIDUsage_KeyboardInternational5:
1080
- return INVALID_KEY;
1081
- case kHIDUsage_KeyboardInternational6:
1082
- return INVALID_KEY;
1083
- case kHIDUsage_KeyboardInternational7:
1084
- return INVALID_KEY;
1085
- case kHIDUsage_KeyboardInternational8:
1086
- return INVALID_KEY;
1087
- case kHIDUsage_KeyboardInternational9:
1088
- return INVALID_KEY;
1089
-
1090
- case kHIDUsage_KeyboardLANG1:
1091
- return INVALID_KEY;
1092
- case kHIDUsage_KeyboardLANG2:
1093
- return INVALID_KEY;
1094
- case kHIDUsage_KeyboardLANG3:
1095
- return INVALID_KEY;
1096
- case kHIDUsage_KeyboardLANG4:
1097
- return INVALID_KEY;
1098
- case kHIDUsage_KeyboardLANG5:
1099
- return INVALID_KEY;
1100
- case kHIDUsage_KeyboardLANG6:
1101
- return INVALID_KEY;
1102
- case kHIDUsage_KeyboardLANG7:
1103
- return INVALID_KEY;
1104
- case kHIDUsage_KeyboardLANG8:
1105
- return INVALID_KEY;
1106
- case kHIDUsage_KeyboardLANG9:
1107
- return INVALID_KEY;
1108
-
1109
- case kHIDUsage_KeyboardAlternateErase:
1110
- return INVALID_KEY;
1111
- case kHIDUsage_KeyboardSysReqOrAttention:
1112
- return INVALID_KEY;
1113
- case kHIDUsage_KeyboardCancel:
1114
- return INVALID_KEY;
1115
- case kHIDUsage_KeyboardClear:
1116
- return INVALID_KEY;
1117
- case kHIDUsage_KeyboardPrior:
1118
- return INVALID_KEY;
1119
- case kHIDUsage_KeyboardReturn:
1120
- return INVALID_KEY;
1121
- case kHIDUsage_KeyboardSeparator:
1122
- return INVALID_KEY;
1123
- case kHIDUsage_KeyboardOut:
1124
- return INVALID_KEY;
1125
- case kHIDUsage_KeyboardOper:
1126
- return INVALID_KEY;
1127
- case kHIDUsage_KeyboardClearOrAgain:
1128
- return INVALID_KEY;
1129
- case kHIDUsage_KeyboardCrSelOrProps:
1130
- return INVALID_KEY;
1131
- case kHIDUsage_KeyboardExSel:
1132
- return INVALID_KEY;
1133
-
1134
- /* 0xa5-0xdf Reserved */
1135
-
1136
- case kHIDUsage_KeyboardLeftControl:
1137
- return kVK_Control;
1138
- case kHIDUsage_KeyboardLeftShift:
1139
- return kVK_Shift;
1140
- case kHIDUsage_KeyboardLeftAlt:
1141
- return kVK_Option;
1142
- case kHIDUsage_KeyboardLeftGUI:
1143
- return kVK_Command;
1144
- case kHIDUsage_KeyboardRightControl:
1145
- return kVK_RightControl;
1146
- case kHIDUsage_KeyboardRightShift:
1147
- return kVK_RightShift;
1148
- case kHIDUsage_KeyboardRightAlt:
1149
- return kVK_RightOption;
1150
- case kHIDUsage_KeyboardRightGUI:
1151
- return 0x36; //??
1152
-
1153
- /* 0xe8-0xffff Reserved */
1154
-
1155
- case kHIDUsage_Keyboard_Reserved:
1156
- return INVALID_KEY;
1157
- default:
1158
- return INVALID_KEY;
1159
- }
1160
- return INVALID_KEY;
1161
-}
1162
-
1163
-obs_key_t obs_key_from_virtual_key(int code)
1164
-{
1165
- switch (code) {
1166
- case kVK_ANSI_A:
1167
- return OBS_KEY_A;
1168
- case kVK_ANSI_B:
1169
- return OBS_KEY_B;
1170
- case kVK_ANSI_C:
1171
- return OBS_KEY_C;
1172
- case kVK_ANSI_D:
1173
- return OBS_KEY_D;
1174
- case kVK_ANSI_E:
1175
- return OBS_KEY_E;
1176
- case kVK_ANSI_F:
1177
- return OBS_KEY_F;
1178
- case kVK_ANSI_G:
1179
- return OBS_KEY_G;
1180
- case kVK_ANSI_H:
1181
- return OBS_KEY_H;
1182
- case kVK_ANSI_I:
1183
- return OBS_KEY_I;
1184
- case kVK_ANSI_J:
1185
- return OBS_KEY_J;
1186
- case kVK_ANSI_K:
1187
- return OBS_KEY_K;
1188
- case kVK_ANSI_L:
1189
- return OBS_KEY_L;
1190
- case kVK_ANSI_M:
1191
- return OBS_KEY_M;
1192
- case kVK_ANSI_N:
1193
- return OBS_KEY_N;
1194
- case kVK_ANSI_O:
1195
- return OBS_KEY_O;
1196
- case kVK_ANSI_P:
1197
- return OBS_KEY_P;
1198
- case kVK_ANSI_Q:
1199
- return OBS_KEY_Q;
1200
- case kVK_ANSI_R:
1201
- return OBS_KEY_R;
1202
- case kVK_ANSI_S:
1203
- return OBS_KEY_S;
1204
- case kVK_ANSI_T:
1205
- return OBS_KEY_T;
1206
- case kVK_ANSI_U:
1207
- return OBS_KEY_U;
1208
- case kVK_ANSI_V:
1209
- return OBS_KEY_V;
1210
- case kVK_ANSI_W:
1211
- return OBS_KEY_W;
1212
- case kVK_ANSI_X:
1213
- return OBS_KEY_X;
1214
- case kVK_ANSI_Y:
1215
- return OBS_KEY_Y;
1216
- case kVK_ANSI_Z:
1217
- return OBS_KEY_Z;
1218
-
1219
- case kVK_ANSI_1:
1220
- return OBS_KEY_1;
1221
- case kVK_ANSI_2:
1222
- return OBS_KEY_2;
1223
- case kVK_ANSI_3:
1224
- return OBS_KEY_3;
1225
- case kVK_ANSI_4:
1226
- return OBS_KEY_4;
1227
- case kVK_ANSI_5:
1228
- return OBS_KEY_5;
1229
- case kVK_ANSI_6:
1230
- return OBS_KEY_6;
1231
- case kVK_ANSI_7:
1232
- return OBS_KEY_7;
1233
- case kVK_ANSI_8:
1234
- return OBS_KEY_8;
1235
- case kVK_ANSI_9:
1236
- return OBS_KEY_9;
1237
- case kVK_ANSI_0:
1238
- return OBS_KEY_0;
1239
-
1240
- case kVK_Return:
1241
- return OBS_KEY_RETURN;
1242
- case kVK_Escape:
1243
- return OBS_KEY_ESCAPE;
1244
- case kVK_Delete:
1245
- return OBS_KEY_BACKSPACE;
1246
- case kVK_Tab:
1247
- return OBS_KEY_TAB;
1248
- case kVK_Space:
1249
- return OBS_KEY_SPACE;
1250
- case kVK_ANSI_Minus:
1251
- return OBS_KEY_MINUS;
1252
- case kVK_ANSI_Equal:
1253
- return OBS_KEY_EQUAL;
1254
- case kVK_ANSI_LeftBracket:
1255
- return OBS_KEY_BRACKETLEFT;
1256
- case kVK_ANSI_RightBracket:
1257
- return OBS_KEY_BRACKETRIGHT;
1258
- case kVK_ANSI_Backslash:
1259
- return OBS_KEY_BACKSLASH;
1260
- case kVK_ANSI_Semicolon:
1261
- return OBS_KEY_SEMICOLON;
1262
- case kVK_ANSI_Quote:
1263
- return OBS_KEY_QUOTE;
1264
- case kVK_ANSI_Grave:
1265
- return OBS_KEY_DEAD_GRAVE;
1266
- case kVK_ANSI_Comma:
1267
- return OBS_KEY_COMMA;
1268
- case kVK_ANSI_Period:
1269
- return OBS_KEY_PERIOD;
1270
- case kVK_ANSI_Slash:
1271
- return OBS_KEY_SLASH;
1272
- case kVK_CapsLock:
1273
- return OBS_KEY_CAPSLOCK;
1274
- case kVK_ISO_Section:
1275
- return OBS_KEY_SECTION;
1276
-
1277
- case kVK_F1:
1278
- return OBS_KEY_F1;
1279
- case kVK_F2:
1280
- return OBS_KEY_F2;
1281
- case kVK_F3:
1282
- return OBS_KEY_F3;
1283
- case kVK_F4:
1284
- return OBS_KEY_F4;
1285
- case kVK_F5:
1286
- return OBS_KEY_F5;
1287
- case kVK_F6:
1288
- return OBS_KEY_F6;
1289
- case kVK_F7:
1290
- return OBS_KEY_F7;
1291
- case kVK_F8:
1292
- return OBS_KEY_F8;
1293
- case kVK_F9:
1294
- return OBS_KEY_F9;
1295
- case kVK_F10:
1296
- return OBS_KEY_F10;
1297
- case kVK_F11:
1298
- return OBS_KEY_F11;
1299
- case kVK_F12:
1300
- return OBS_KEY_F12;
1301
-
1302
- case kVK_Help:
1303
- return OBS_KEY_HELP;
1304
- case kVK_Home:
1305
- return OBS_KEY_HOME;
1306
- case kVK_PageUp:
1307
- return OBS_KEY_PAGEUP;
1308
- case kVK_ForwardDelete:
1309
- return OBS_KEY_DELETE;
1310
- case kVK_End:
1311
- return OBS_KEY_END;
1312
- case kVK_PageDown:
1313
- return OBS_KEY_PAGEDOWN;
1314
-
1315
- case kVK_RightArrow:
1316
- return OBS_KEY_RIGHT;
1317
- case kVK_LeftArrow:
1318
- return OBS_KEY_LEFT;
1319
- case kVK_DownArrow:
1320
- return OBS_KEY_DOWN;
1321
- case kVK_UpArrow:
1322
- return OBS_KEY_UP;
1323
-
1324
- case kVK_ANSI_KeypadClear:
1325
- return OBS_KEY_CLEAR;
1326
- case kVK_ANSI_KeypadDivide:
1327
- return OBS_KEY_NUMSLASH;
1328
- case kVK_ANSI_KeypadMultiply:
1329
- return OBS_KEY_NUMASTERISK;
1330
- case kVK_ANSI_KeypadMinus:
1331
- return OBS_KEY_NUMMINUS;
1332
- case kVK_ANSI_KeypadPlus:
1333
- return OBS_KEY_NUMPLUS;
1334
- case kVK_ANSI_KeypadEnter:
1335
- return OBS_KEY_ENTER;
1336
-
1337
- case kVK_ANSI_Keypad1:
1338
- return OBS_KEY_NUM1;
1339
- case kVK_ANSI_Keypad2:
1340
- return OBS_KEY_NUM2;
1341
- case kVK_ANSI_Keypad3:
1342
- return OBS_KEY_NUM3;
1343
- case kVK_ANSI_Keypad4:
1344
- return OBS_KEY_NUM4;
1345
- case kVK_ANSI_Keypad5:
1346
- return OBS_KEY_NUM5;
1347
- case kVK_ANSI_Keypad6:
1348
- return OBS_KEY_NUM6;
1349
- case kVK_ANSI_Keypad7:
1350
- return OBS_KEY_NUM7;
1351
- case kVK_ANSI_Keypad8:
1352
- return OBS_KEY_NUM8;
1353
- case kVK_ANSI_Keypad9:
1354
- return OBS_KEY_NUM9;
1355
- case kVK_ANSI_Keypad0:
1356
- return OBS_KEY_NUM0;
1357
-
1358
- case kVK_ANSI_KeypadDecimal:
1359
- return OBS_KEY_NUMPERIOD;
1360
- case kVK_ANSI_KeypadEquals:
1361
- return OBS_KEY_NUMEQUAL;
1362
-
1363
- case kVK_F13:
1364
- return OBS_KEY_F13;
1365
- case kVK_F14:
1366
- return OBS_KEY_F14;
1367
- case kVK_F15:
1368
- return OBS_KEY_F15;
1369
- case kVK_F16:
1370
- return OBS_KEY_F16;
1371
- case kVK_F17:
1372
- return OBS_KEY_F17;
1373
- case kVK_F18:
1374
- return OBS_KEY_F18;
1375
- case kVK_F19:
1376
- return OBS_KEY_F19;
1377
- case kVK_F20:
1378
- return OBS_KEY_F20;
1379
-
1380
- case kVK_Control:
1381
- return OBS_KEY_CONTROL;
1382
- case kVK_Shift:
1383
- return OBS_KEY_SHIFT;
1384
- case kVK_Option:
1385
- return OBS_KEY_ALT;
1386
- case kVK_Command:
1387
- return OBS_KEY_META;
1388
- case kVK_RightControl:
1389
- return OBS_KEY_CONTROL;
1390
- case kVK_RightShift:
1391
- return OBS_KEY_SHIFT;
1392
- case kVK_RightOption:
1393
- return OBS_KEY_ALT;
1394
- case 0x36:
1395
- return OBS_KEY_META;
1396
-
1397
- case kVK_Function:
1398
- case kVK_Mute:
1399
- case kVK_VolumeDown:
1400
- case kVK_VolumeUp:
1401
- break;
1402
- }
1403
- return OBS_KEY_NONE;
1404
-}
1405
-
1406
-static inline void load_key(obs_hotkeys_platform_t *plat, IOHIDElementRef key)
1407
-{
1408
- UInt32 usage_code = IOHIDElementGetUsage(key);
1409
- UInt16 carbon_code = usage_to_carbon(usage_code);
1410
-
1411
- if (carbon_code == INVALID_KEY)
1412
- return;
1413
-
1414
- obs_key_t obs_key = obs_key_from_virtual_key(carbon_code);
1415
- if (obs_key == OBS_KEY_NONE)
1416
- return;
1417
-
1418
- da_push_back(plat->keys[obs_key], &key);
1419
- CFRetain(*(IOHIDElementRef *)da_end(plat->keys[obs_key]));
1420
-}
1421
-
1422
-static inline void load_keyboard(obs_hotkeys_platform_t *plat,
1423
- IOHIDDeviceRef keyboard)
1424
-{
1425
- CFArrayRef keys = IOHIDDeviceCopyMatchingElements(
1426
- keyboard, NULL, kIOHIDOptionsTypeNone);
1427
-
1428
- if (!keys) {
1429
- blog(LOG_ERROR, "hotkeys-cocoa: Getting keyboard keys failed");
1430
- return;
1431
- }
1432
-
1433
- CFIndex count = CFArrayGetCount(keys);
1434
- if (!count) {
1435
- blog(LOG_ERROR, "hotkeys-cocoa: Keyboard has no keys");
1436
- CFRelease(keys);
1437
- return;
1438
- }
1439
-
1440
- for (CFIndex i = 0; i < count; i++) {
1441
- IOHIDElementRef key =
1442
- (IOHIDElementRef)CFArrayGetValueAtIndex(keys, i);
1443
-
1444
- // Skip non-matching keys elements
1445
- if (IOHIDElementGetUsagePage(key) != kHIDPage_KeyboardOrKeypad)
1446
- continue;
1447
-
1448
- load_key(plat, key);
1449
- }
1450
-
1451
- CFRelease(keys);
1452
-}
1453
-
1454
-static bool init_keyboard(obs_hotkeys_platform_t *plat)
1455
-{
1456
- CFSetRef keyboards = copy_devices(plat, kHIDPage_GenericDesktop,
1457
- kHIDUsage_GD_Keyboard);
1458
- if (!keyboards)
1459
- return false;
1460
-
1461
- CFIndex count = CFSetGetCount(keyboards);
1462
-
1463
- CFTypeRef devices[count];
1464
- CFSetGetValues(keyboards, devices);
1465
-
1466
- for (CFIndex i = 0; i < count; i++)
1467
- load_keyboard(plat, (IOHIDDeviceRef)devices[i]);
1468
-
1469
- CFRelease(keyboards);
1470
- return true;
1471
-}
1472
-
1473
-static inline void free_hotkeys_platform(obs_hotkeys_platform_t *plat)
1474
-{
1475
- if (!plat)
1476
- return;
1477
-
1478
- if (plat->tis) {
1479
- CFRelease(plat->tis);
1480
- plat->tis = NULL;
1481
- }
1482
-
1483
- if (plat->layout_data) {
1484
- CFRelease(plat->layout_data);
1485
- plat->layout_data = NULL;
1486
- }
1487
-
1488
- if (plat->manager) {
1489
- CFRelease(plat->manager);
1490
- plat->manager = NULL;
1491
- }
1492
-
1493
- for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++) {
1494
- for (size_t j = 0; j < plat->keys[i].num; j++)
1495
- CFRelease(plat->keys[i].array[j]);
1496
-
1497
- da_free(plat->keys[i]);
1498
- }
1499
-
1500
- bfree(plat);
1501
-}
1502
-
1503
-static bool log_layout_name(TISInputSourceRef tis)
1504
-{
1505
- struct dstr layout_name = {0};
1506
- CFStringRef sid = (CFStringRef)TISGetInputSourceProperty(
1507
- tis, kTISPropertyInputSourceID);
1508
- if (!sid) {
1509
- blog(LOG_ERROR, "hotkeys-cocoa: Failed getting InputSourceID");
1510
- return false;
1511
- }
1512
-
1513
- if (!dstr_from_cfstring(&layout_name, sid)) {
1514
- blog(LOG_ERROR, "hotkeys-cocoa: Could not convert InputSourceID"
1515
- " to CString");
1516
- goto fail;
1517
- }
1518
-
1519
- blog(LOG_INFO, "hotkeys-cocoa: Using layout '%s'", layout_name.array);
1520
-
1521
- dstr_free(&layout_name);
1522
- return true;
1523
-
1524
-fail:
1525
- dstr_free(&layout_name);
1526
- return false;
1527
-}
1528
-
1529
-static bool init_hotkeys_platform(obs_hotkeys_platform_t **plat_)
1530
-{
1531
- if (!plat_)
1532
- return false;
1533
-
1534
- *plat_ = bzalloc(sizeof(obs_hotkeys_platform_t));
1535
- obs_hotkeys_platform_t *plat = *plat_;
1536
- if (!plat) {
1537
- *plat_ = NULL;
1538
- return false;
1539
- }
1540
-
1541
- plat->tis = TISCopyCurrentKeyboardLayoutInputSource();
1542
- plat->layout_data = (CFDataRef)TISGetInputSourceProperty(
1543
- plat->tis, kTISPropertyUnicodeKeyLayoutData);
1544
-
1545
- if (!plat->layout_data) {
1546
- blog(LOG_ERROR, "hotkeys-cocoa: Failed getting LayoutData");
1547
- goto fail;
1548
- }
1549
-
1550
- CFRetain(plat->layout_data);
1551
- plat->layout = (UCKeyboardLayout *)CFDataGetBytePtr(plat->layout_data);
1552
-
1553
- plat->manager =
1554
- IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
1555
-
1556
- IOReturn openStatus =
1557
- IOHIDManagerOpen(plat->manager, kIOHIDOptionsTypeNone);
1558
- if (openStatus != kIOReturnSuccess) {
1559
- blog(LOG_ERROR, "hotkeys-cocoa: Failed opening HIDManager");
1560
- goto fail;
1561
- }
1562
-
1563
- init_keyboard(plat);
1564
-
1565
- return true;
1566
-
1567
-fail:
1568
- hotkeys_release(plat);
1569
- *plat_ = NULL;
1570
- return false;
1571
-}
1572
-
1573
-static void input_method_changed(CFNotificationCenterRef nc, void *observer,
1574
- CFStringRef name, const void *object,
1575
- CFDictionaryRef user_info)
1576
-{
1577
- UNUSED_PARAMETER(nc);
1578
- UNUSED_PARAMETER(name);
1579
- UNUSED_PARAMETER(object);
1580
- UNUSED_PARAMETER(user_info);
1581
-
1582
- struct obs_core_hotkeys *hotkeys = observer;
1583
- obs_hotkeys_platform_t *new_plat;
1584
-
1585
- if (init_hotkeys_platform(&new_plat)) {
1586
- obs_hotkeys_platform_t *plat;
1587
-
1588
- pthread_mutex_lock(&hotkeys->mutex);
1589
- plat = hotkeys->platform_context;
1590
-
1591
- if (new_plat && plat &&
1592
- new_plat->layout_data == plat->layout_data) {
1593
- pthread_mutex_unlock(&hotkeys->mutex);
1594
- hotkeys_release(new_plat);
1595
- return;
1596
- }
1597
-
1598
- hotkeys->platform_context = new_plat;
1599
- if (new_plat)
1600
- log_layout_name(new_plat->tis);
1601
- pthread_mutex_unlock(&hotkeys->mutex);
1602
-
1603
- calldata_t params = {0};
1604
- signal_handler_signal(hotkeys->signals, "hotkey_layout_change",
1605
- ¶ms);
1606
- if (plat)
1607
- hotkeys_release(plat);
1608
- }
1609
-}
1610
-
1611
-bool obs_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys)
1612
-{
1613
- CFNotificationCenterAddObserver(
1614
- CFNotificationCenterGetDistributedCenter(), hotkeys,
1615
- input_method_changed,
1616
- kTISNotifySelectedKeyboardInputSourceChanged, NULL,
1617
- CFNotificationSuspensionBehaviorDeliverImmediately);
1618
-
1619
- input_method_changed(NULL, hotkeys, NULL, NULL, NULL);
1620
- return hotkeys->platform_context != NULL;
1621
-}
1622
-
1623
-void obs_hotkeys_platform_free(struct obs_core_hotkeys *hotkeys)
1624
-{
1625
- CFNotificationCenterRemoveEveryObserver(
1626
- CFNotificationCenterGetDistributedCenter(), hotkeys);
1627
-
1628
- hotkeys_release(hotkeys->platform_context);
1629
-}
1630
-
1631
-typedef unsigned long NSUInteger;
1632
-static bool mouse_button_pressed(obs_key_t key, bool *pressed)
1633
-{
1634
- int button = 0;
1635
- switch (key) {
1636
-#define MAP_BUTTON(n) \
1637
- case OBS_KEY_MOUSE##n: \
1638
- button = n - 1; \
1639
- break
1640
- MAP_BUTTON(1);
1641
- MAP_BUTTON(2);
1642
- MAP_BUTTON(3);
1643
- MAP_BUTTON(4);
1644
- MAP_BUTTON(5);
1645
- MAP_BUTTON(6);
1646
- MAP_BUTTON(7);
1647
- MAP_BUTTON(8);
1648
- MAP_BUTTON(9);
1649
- MAP_BUTTON(10);
1650
- MAP_BUTTON(11);
1651
- MAP_BUTTON(12);
1652
- MAP_BUTTON(13);
1653
- MAP_BUTTON(14);
1654
- MAP_BUTTON(15);
1655
- MAP_BUTTON(16);
1656
- MAP_BUTTON(17);
1657
- MAP_BUTTON(18);
1658
- MAP_BUTTON(19);
1659
- MAP_BUTTON(20);
1660
- MAP_BUTTON(21);
1661
- MAP_BUTTON(22);
1662
- MAP_BUTTON(23);
1663
- MAP_BUTTON(24);
1664
- MAP_BUTTON(25);
1665
- MAP_BUTTON(26);
1666
- MAP_BUTTON(27);
1667
- MAP_BUTTON(28);
1668
- MAP_BUTTON(29);
1669
- break;
1670
-#undef MAP_BUTTON
1671
-
1672
- default:
1673
- return false;
1674
- }
1675
-
1676
- Class NSEvent = objc_getClass("NSEvent");
1677
- SEL pressedMouseButtons = sel_registerName("pressedMouseButtons");
1678
- NSUInteger buttons =
1679
- (NSUInteger)objc_msgSend((id)NSEvent, pressedMouseButtons);
1680
-
1681
- *pressed = (buttons & (1 << button)) != 0;
1682
- return true;
1683
-}
1684
-
1685
-bool obs_hotkeys_platform_is_pressed(obs_hotkeys_platform_t *plat,
1686
- obs_key_t key)
1687
-{
1688
- bool mouse_pressed = false;
1689
- if (mouse_button_pressed(key, &mouse_pressed))
1690
- return mouse_pressed;
1691
-
1692
- if (!plat)
1693
- return false;
1694
-
1695
- if (key >= OBS_KEY_LAST_VALUE)
1696
- return false;
1697
-
1698
- for (size_t i = 0; i < plat->keys[key].num;) {
1699
- IOHIDElementRef element = plat->keys[key].array[i];
1700
- IOHIDValueRef value = 0;
1701
- IOHIDDeviceRef device = IOHIDElementGetDevice(element);
1702
-
1703
- if (IOHIDDeviceGetValue(device, element, &value) !=
1704
- kIOReturnSuccess) {
1705
- i += 1;
1706
- continue;
1707
- }
1708
-
1709
- if (!value) {
1710
- CFRelease(element);
1711
- da_erase(plat->keys[key], i);
1712
- continue;
1713
- }
1714
-
1715
- if (IOHIDValueGetIntegerValue(value) == 1)
1716
- return true;
1717
-
1718
- i += 1;
1719
- }
1720
-
1721
- return false;
1722
-}
1723
obs-studio-24.0.3.tar.xz/CI/before-deploy-osx.sh -> obs-studio-24.0.5.tar.xz/CI/before-deploy-osx.sh
Changed
109
1
2
set -e
3
4
# Generate file name variables
5
+export GIT_TAG=$(git describe --abbrev=0)
6
export GIT_HASH=$(git rev-parse --short HEAD)
7
export FILE_DATE=$(date +%Y-%m-%d.%H-%M-%S)
8
-export FILENAME=$FILE_DATE-$GIT_HASH-$TRAVIS_BRANCH-osx.pkg
9
+export FILENAME=$FILE_DATE-$GIT_HASH-$TRAVIS_BRANCH-osx.dmg
10
+
11
+echo "git tag: $GIT_TAG"
12
13
cd ./build
14
15
16
mv ./rundir/RelWithDebInfo/data/obs-scripting/obslua.so ./rundir/RelWithDebInfo/bin/
17
18
# Move obspython
19
-# hr "Moving OBS Python"
20
-# mv ./rundir/RelWithDebInfo/data/obs-scripting/_obspython.so ./rundir/RelWithDebInfo/bin/
21
-# mv ./rundir/RelWithDebInfo/data/obs-scripting/obspython.py ./rundir/RelWithDebInfo/bin/
22
+hr "Moving OBS Python"
23
+mv ./rundir/RelWithDebInfo/data/obs-scripting/_obspython.so ./rundir/RelWithDebInfo/bin/
24
+mv ./rundir/RelWithDebInfo/data/obs-scripting/obspython.py ./rundir/RelWithDebInfo/bin/
25
26
# Package everything into a nice .app
27
hr "Packaging .app"
28
29
STABLE=true
30
fi
31
32
-sudo python ../CI/install/osx/build_app.py --public-key ../CI/install/osx/OBSPublicDSAKey.pem --sparkle-framework ../../sparkle/Sparkle.framework --stable=$STABLE
33
+#sudo python ../CI/install/osx/build_app.py --public-key ../CI/install/osx/OBSPublicDSAKey.pem --sparkle-framework ../../sparkle/Sparkle.framework --stable=$STABLE
34
+
35
+../CI/install/osx/packageApp.sh
36
+
37
+# fix obs outputs
38
+cp /usr/local/opt/mbedtls/lib/libmbedtls.12.dylib ./OBS.app/Contents/Frameworks/
39
+cp /usr/local/opt/mbedtls/lib/libmbedcrypto.3.dylib ./OBS.app/Contents/Frameworks/
40
+cp /usr/local/opt/mbedtls/lib/libmbedx509.0.dylib ./OBS.app/Contents/Frameworks/
41
+install_name_tool -change /usr/local/opt/mbedtls/lib/libmbedtls.12.dylib @executable_path/../Frameworks/libmbedtls.12.dylib ./OBS.app/Contents/Plugins/obs-outputs.so
42
+install_name_tool -change /usr/local/opt/mbedtls/lib/libmbedcrypto.3.dylib @executable_path/../Frameworks/libmbedcrypto.3.dylib ./OBS.app/Contents/Plugins/obs-outputs.so
43
+install_name_tool -change /usr/local/opt/mbedtls/lib/libmbedx509.0.dylib @executable_path/../Frameworks/libmbedx509.0.dylib ./OBS.app/Contents/Plugins/obs-outputs.so
44
+install_name_tool -change /usr/local/opt/curl/lib/libcurl.4.dylib @executable_path/../Frameworks/libcurl.4.dylib ./OBS.app/Contents/Plugins/obs-outputs.so
45
+install_name_tool -change @rpath/libobs.0.dylib @executable_path/../Frameworks/libobs.0.dylib ./OBS.app/Contents/Plugins/obs-outputs.so
46
+
47
+# copy sparkle into the app
48
+hr "Copying Sparkle.framework"
49
+cp -r ../../sparkle/Sparkle.framework ./OBS.app/Contents/Frameworks/
50
+install_name_tool -change @rpath/Sparkle.framework/Versions/A/Sparkle @executable_path/../Frameworks/Sparkle.framework/Versions/A/Sparkle ./OBS.app/Contents/MacOS/obs
51
52
# Copy Chromium embedded framework to app Frameworks directory
53
hr "Copying Chromium Embedded Framework.framework"
54
sudo mkdir -p OBS.app/Contents/Frameworks
55
sudo cp -r ../../cef_binary_${CEF_BUILD_VERSION}_macosx64/Release/Chromium\ Embedded\ Framework.framework OBS.app/Contents/Frameworks/
56
-sudo install_name_tool -change \
57
- @rpath/Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
58
- ../../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
59
- OBS.app/Contents/Resources/obs-plugins/obs-browser.so
60
-sudo install_name_tool -change \
61
- @executable_path/../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
62
- ../../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
63
- OBS.app/Contents/Resources/obs-plugins/obs-browser.so
64
-sudo install_name_tool -change \
65
- @rpath/Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
66
- ../../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
67
- OBS.app/Contents/Resources/obs-plugins/obs-browser-page
68
-sudo install_name_tool -change \
69
- @executable_path/../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
70
- ../../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
71
- OBS.app/Contents/Resources/obs-plugins/obs-browser-page
72
-
73
-# Package app
74
-hr "Generating .pkg"
75
-packagesbuild ../CI/install/osx/CMakeLists.pkgproj
76
+
77
+install_name_tool -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ./OBS.app/Contents/Plugins/obs-browser.so
78
+install_name_tool -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/Plugins/obs-browser.so
79
+install_name_tool -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ./OBS.app/Contents/Plugins/obs-browser.so
80
+
81
+cp ../CI/install/osx/OBSPublicDSAKey.pem OBS.app/Contents/Resources
82
+
83
+# edit plist
84
+plutil -insert CFBundleVersion -string $GIT_TAG ./OBS.app/Contents/Info.plist
85
+plutil -insert CFBundleShortVersionString -string $GIT_TAG ./OBS.app/Contents/Info.plist
86
+plutil -insert OBSFeedsURL -string https://obsproject.com/osx_update/feeds.xml ./OBS.app/Contents/Info.plist
87
+plutil -insert SUFeedURL -string https://obsproject.com/osx_update/stable/updates.xml ./OBS.app/Contents/Info.plist
88
+plutil -insert SUPublicDSAKeyFile -string OBSPublicDSAKey.pem ./OBS.app/Contents/Info.plist
89
+
90
+dmgbuild -s ../CI/install/osx/settings.json "OBS" obs.dmg
91
92
if [ -v "$TRAVIS" ]; then
93
# Signing stuff
94
95
security import ./Certificates.p12 -k build.keychain -T /usr/bin/productsign -P ""
96
# macOS 10.12+
97
security set-key-partition-list -S apple-tool:,apple: -s -k mysecretpassword build.keychain
98
- hr "Signing Package"
99
- productsign --sign 2MMRE5MTB8 ./OBS.pkg ./$FILENAME
100
-else
101
- cp ./OBS.pkg ./$FILENAME
102
fi
103
104
+cp ./OBS.dmg ./$FILENAME
105
+
106
# Move to the folder that travis uses to upload artifacts from
107
hr "Moving package to nightly folder for distribution"
108
mkdir ../nightly
109
obs-studio-24.0.3.tar.xz/CI/install-dependencies-linux.sh -> obs-studio-24.0.5.tar.xz/CI/install-dependencies-linux.sh
Changed
9
1
2
#!/bin/sh
3
set -ex
4
5
-sudo add-apt-repository ppa:jonathonf/ffmpeg-3 -y
6
curl -L https://packagecloud.io/github/git-lfs/gpgkey | sudo apt-key add -
7
8
# gets us newer clang
9
obs-studio-24.0.3.tar.xz/CI/install-dependencies-osx.sh -> obs-studio-24.0.5.tar.xz/CI/install-dependencies-osx.sh
Changed
24
1
2
/bin/bash -c "sudo xcode-select -s /Applications/Xcode_9.4.1.app/Contents/Developer"
3
fi
4
5
+git fetch origin --tags
6
+
7
# Leave obs-studio folder
8
cd ../
9
10
11
brew update
12
13
#Base OBS Deps and ccache
14
-brew install jack speexdsp ccache mbedtls clang-format
15
+brew install jack speexdsp ccache mbedtls clang-format freetype fdk-aac
16
brew install https://gist.githubusercontent.com/DDRBoxman/b3956fab6073335a4bf151db0dcbd4ad/raw/ed1342a8a86793ea8c10d8b4d712a654da121ace/qt.rb
17
brew install https://gist.githubusercontent.com/DDRBoxman/4cada55c51803a2f963fa40ce55c9d3e/raw/572c67e908bfbc1bcb8c476ea77ea3935133f5b5/swig.rb
18
19
+pip install dmgbuild
20
+
21
export PATH=/usr/local/opt/ccache/libexec:$PATH
22
ccache -s || echo "CCache is not available."
23
24
obs-studio-24.0.5.tar.xz/CI/install/osx/Info.plist
Added
32
1
2
+<?xml version="1.0" encoding="UTF-8"?>
3
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
4
+<plist version="1.0">
5
+<dict>
6
+ <key>CFBundleIconFile</key>
7
+ <string>obs.icns</string>
8
+ <key>CFBundleName</key>
9
+ <string>OBS</string>
10
+ <key>CFBundleGetInfoString</key>
11
+ <string>OBS - Free and Open Source Streaming/Recording Software</string>
12
+ <key>CFBundleExecutable</key>
13
+ <string>OBS</string>
14
+ <key>CFBundleIdentifier</key>
15
+ <string>com.obsproject.obs-studio</string>
16
+ <key>CFBundlePackageType</key>
17
+ <string>APPL</string>
18
+ <key>CFBundleSignature</key>
19
+ <string>????</string>
20
+ <key>LSMinimumSystemVersion</key>
21
+ <string>10.8.5</string>
22
+ <key>NSHighResolutionCapable</key>
23
+ <true/>
24
+ <key>LSAppNapIsDisabled</key>
25
+ <true/>
26
+ <key>NSCameraUsageDescription</key>
27
+ <string>OBS needs to access the camera to enable camera sources to work.</string>
28
+ <key>NSMicrophoneUsageDescription</key>
29
+ <string>OBS needs to access the microphone to enable audio input.</string>
30
+</dict>
31
+</plist>
32
obs-studio-24.0.5.tar.xz/CI/install/osx/background.png
Added
obs-studio-24.0.5.tar.xz/CI/install/osx/background.pxd
Added
2
1
+(directory)
2
obs-studio-24.0.5.tar.xz/CI/install/osx/background.pxd/QuickLook
Added
2
1
+(directory)
2
obs-studio-24.0.5.tar.xz/CI/install/osx/background.pxd/QuickLook/Icon.tiff
Added
obs-studio-24.0.5.tar.xz/CI/install/osx/background.pxd/QuickLook/Preview.tiff
Added
obs-studio-24.0.5.tar.xz/CI/install/osx/background.pxd/QuickLook/Thumbnail.tiff
Added
obs-studio-24.0.5.tar.xz/CI/install/osx/background.pxd/data
Added
2
1
+(directory)
2
obs-studio-24.0.5.tar.xz/CI/install/osx/background.pxd/data/556CF265-5721-4F18-BE83-8CF39483B4C2
Added
obs-studio-24.0.5.tar.xz/CI/install/osx/background.pxd/data/8CA689C3-ED2A-459E-952C-E08026CFCD07
Added
obs-studio-24.0.5.tar.xz/CI/install/osx/background.pxd/metadata.info
Added
obs-studio-24.0.5.tar.xz/CI/install/osx/background.tiff
Added
obs-studio-24.0.5.tar.xz/CI/install/osx/background@2x.png
Added
obs-studio-24.0.5.tar.xz/CI/install/osx/buildDMG
Added
3
1
2
+dmgbuild -s ./settings.json "OBS" obs.dmg
3
obs-studio-24.0.5.tar.xz/CI/install/osx/dylibBundler
Added
obs-studio-24.0.5.tar.xz/CI/install/osx/makeRetinaBG
Added
3
1
2
+tiffutil -cathidpicheck background.png background@2x.png -out background.tiff
3
obs-studio-24.0.5.tar.xz/CI/install/osx/obs.icns
Added
obs-studio-24.0.5.tar.xz/CI/install/osx/packageApp.sh
Added
69
1
2
+rm -rf ./OBS.app
3
+
4
+mkdir OBS.app
5
+mkdir OBS.app/Contents
6
+mkdir OBS.app/Contents/MacOS
7
+mkdir OBS.app/Contents/Plugins
8
+mkdir OBS.app/Contents/Resources
9
+
10
+cp -r rundir/RelWithDebInfo/bin/ ./OBS.app/Contents/MacOS
11
+cp -r rundir/RelWithDebInfo/data ./OBS.app/Contents/Resources
12
+cp ../CI/install/osx/obs.icns ./OBS.app/Contents/Resources
13
+cp -r rundir/RelWithDebInfo/obs-plugins/ ./OBS.app/Contents/Plugins
14
+cp ../CI/install/osx/Info.plist ./OBS.app/Contents
15
+
16
+../CI/install/osx/dylibBundler -b -cd -d ./OBS.app/Contents/Frameworks -p @executable_path/../Frameworks/ \
17
+-s ./OBS.app/Contents/MacOS \
18
+-s /usr/local/opt/mbedtls/lib/ \
19
+-x ./OBS.app/Contents/Plugins/coreaudio-encoder.so \
20
+-x ./OBS.app/Contents/Plugins/decklink-ouput-ui.so \
21
+-x ./OBS.app/Contents/Plugins/frontend-tools.so \
22
+-x ./OBS.app/Contents/Plugins/image-source.so \
23
+-x ./OBS.app/Contents/Plugins/linux-jack.so \
24
+-x ./OBS.app/Contents/Plugins/mac-avcapture.so \
25
+-x ./OBS.app/Contents/Plugins/mac-capture.so \
26
+-x ./OBS.app/Contents/Plugins/mac-decklink.so \
27
+-x ./OBS.app/Contents/Plugins/mac-syphon.so \
28
+-x ./OBS.app/Contents/Plugins/mac-vth264.so \
29
+-x ./OBS.app/Contents/Plugins/obs-browser.so \
30
+-x ./OBS.app/Contents/Plugins/obs-browser-page \
31
+-x ./OBS.app/Contents/Plugins/obs-ffmpeg.so \
32
+-x ./OBS.app/Contents/Plugins/obs-filters.so \
33
+-x ./OBS.app/Contents/Plugins/obs-transitions.so \
34
+-x ./OBS.app/Contents/Plugins/obs-vst.so \
35
+-x ./OBS.app/Contents/Plugins/rtmp-services.so \
36
+-x ./OBS.app/Contents/MacOS/obs \
37
+-x ./OBS.app/Contents/MacOS/obs-ffmpeg-mux \
38
+-x ./OBS.app/Contents/MacOS/obslua.so \
39
+-x ./OBS.app/Contents/MacOS/_obspython.so \
40
+-x ./OBS.app/Contents/Plugins/obs-x264.so \
41
+-x ./OBS.app/Contents/Plugins/text-freetype2.so \
42
+-x ./OBS.app/Contents/Plugins/obs-libfdk.so
43
+# -x ./OBS.app/Contents/Plugins/obs-outputs.so \
44
+
45
+/usr/local/Cellar/qt/5.10.1/bin/macdeployqt ./OBS.app
46
+
47
+mv ./OBS.app/Contents/MacOS/libobs-opengl.so ./OBS.app/Contents/Frameworks
48
+
49
+# put qt network in here becasuse streamdeck uses it
50
+cp -r /usr/local/opt/qt/lib/QtNetwork.framework ./OBS.app/Contents/Frameworks
51
+chmod +w ./OBS.app/Contents/Frameworks/QtNetwork.framework/Versions/5/QtNetwork
52
+install_name_tool -change /usr/local/Cellar/qt/5.10.1/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/Frameworks/QtNetwork.framework/Versions/5/QtNetwork
53
+
54
+# decklink ui qt
55
+install_name_tool -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ./OBS.app/Contents/Plugins/decklink-ouput-ui.so
56
+install_name_tool -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/Plugins/decklink-ouput-ui.so
57
+install_name_tool -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ./OBS.app/Contents/Plugins/decklink-ouput-ui.so
58
+
59
+# frontend tools qt
60
+install_name_tool -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ./OBS.app/Contents/Plugins/frontend-tools.so
61
+install_name_tool -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/Plugins/frontend-tools.so
62
+install_name_tool -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ./OBS.app/Contents/Plugins/frontend-tools.so
63
+
64
+# vst qt
65
+install_name_tool -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ./OBS.app/Contents/Plugins/obs-vst.so
66
+install_name_tool -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ./OBS.app/Contents/Plugins/obs-vst.so
67
+install_name_tool -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ./OBS.app/Contents/Plugins/obs-vst.so
68
+install_name_tool -change /usr/local/opt/qt/lib/QtMacExtras.framework/Versions/5/QtMacExtras @executable_path/../Frameworks/QtMacExtras.framework/Versions/5/QtMacExtras ./OBS.app/Contents/Plugins/obs-vst.so
69
obs-studio-24.0.5.tar.xz/CI/install/osx/settings.json
Added
15
1
2
+{
3
+ "title": "OBS",
4
+ "background": "../CI/install/osx/background.tiff",
5
+ "format": "UDZO",
6
+ "compression-level": 9,
7
+ "window": { "position": { "x": 100, "y": 100 },
8
+ "size": { "width": 540, "height": 380 } },
9
+ "contents": [
10
+ { "x": 120, "y": 180, "type": "file",
11
+ "path": "./OBS.app" },
12
+ { "x": 420, "y": 180, "type": "link", "path": "/Applications" }
13
+ ]
14
+}
15
obs-studio-24.0.3.tar.xz/UI/CMakeLists.txt -> obs-studio-24.0.5.tar.xz/UI/CMakeLists.txt
Changed
16
1
2
target_link_libraries(obs
3
Qt5::MacExtras)
4
set_target_properties(obs PROPERTIES LINK_FLAGS "-pagezero_size 10000 -image_base 100000000")
5
- set_property(
6
- TARGET obs
7
- APPEND
8
- PROPERTY INSTALL_RPATH
9
- "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/"
10
- "/Library/Frameworks/Python.framework/Versions/3.6/lib/"
11
- "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/"
12
- )
13
endif()
14
15
define_graphic_modules(obs)
16
obs-studio-24.0.3.tar.xz/UI/auth-twitch.cpp -> obs-studio-24.0.5.tar.xz/UI/auth-twitch.cpp
Changed
11
1
2
chat->SetWidget(browser);
3
cef->add_force_popup_url(moderation_tools_url, chat.data());
4
5
- script = bttv_script;
6
+ script = "localStorage.setItem('twilight.theme', 1);";
7
+ script += bttv_script;
8
script += ffz_script;
9
browser->setStartupScript(script);
10
11
obs-studio-24.0.3.tar.xz/UI/forms/OBSBasicSettings.ui -> obs-studio-24.0.5.tar.xz/UI/forms/OBSBasicSettings.ui
Changed
24
1
2
<item row="0" column="1">
3
<widget class="QComboBox" name="sampleRate">
4
<property name="currentText">
5
- <string notr="true">44.1khz</string>
6
+ <string notr="true">44.1 kHz</string>
7
</property>
8
<property name="currentIndex">
9
<number>0</number>
10
</property>
11
<item>
12
<property name="text">
13
- <string>44.1khz</string>
14
+ <string>44.1 kHz</string>
15
</property>
16
</item>
17
<item>
18
<property name="text">
19
- <string>48khz</string>
20
+ <string>48 kHz</string>
21
</property>
22
</item>
23
</widget>
24
obs-studio-24.0.3.tar.xz/UI/frontend-plugins/frontend-tools/auto-scene-switcher-nix.cpp -> obs-studio-24.0.5.tar.xz/UI/frontend-plugins/frontend-tools/auto-scene-switcher-nix.cpp
Changed
21
1
2
if (status >= Success && name != nullptr) {
3
std::string str(name);
4
windowTitle = str;
5
+ XFree(name);
6
+ } else {
7
+ XTextProperty xtp_new_name;
8
+ if (XGetWMName(disp(), w, &xtp_new_name) != 0 &&
9
+ xtp_new_name.value != nullptr) {
10
+ std::string str((const char *)xtp_new_name.value);
11
+ windowTitle = str;
12
+ XFree(xtp_new_name.value);
13
+ }
14
}
15
16
- XFree(name);
17
-
18
return windowTitle;
19
}
20
21
obs-studio-24.0.3.tar.xz/UI/platform-osx.mm -> obs-studio-24.0.5.tar.xz/UI/platform-osx.mm
Changed
34
1
2
3
using namespace std;
4
5
+bool isInBundle()
6
+{
7
+ NSRunningApplication *app = [NSRunningApplication currentApplication];
8
+ return [app bundleIdentifier] != nil;
9
+}
10
+
11
bool GetDataFilePath(const char *data, string &output)
12
{
13
- stringstream str;
14
- str << OBS_DATA_PATH "/obs-studio/" << data;
15
- output = str.str();
16
+ if (isInBundle()) {
17
+ NSRunningApplication *app =
18
+ [NSRunningApplication currentApplication];
19
+ NSURL *bundleURL = [app bundleURL];
20
+ NSString *path = [NSString
21
+ stringWithFormat:@"Contents/Resources/data/obs-studio/%@",
22
+ [NSString stringWithUTF8String:data]];
23
+ NSURL *dataURL = [bundleURL URLByAppendingPathComponent:path];
24
+ output = [[dataURL path] UTF8String];
25
+ } else {
26
+ stringstream str;
27
+ str << OBS_DATA_PATH "/obs-studio/" << data;
28
+ output = str.str();
29
+ }
30
+
31
return !access(output.c_str(), R_OK);
32
}
33
34
obs-studio-24.0.3.tar.xz/UI/properties-view.cpp -> obs-studio-24.0.5.tar.xz/UI/properties-view.cpp
Changed
10
1
2
break;
3
case OBS_PROPERTY_GROUP:
4
GroupChanged(setting);
5
- return;
6
+ break;
7
}
8
9
if (view->callback && !view->deferUpdate)
10
obs-studio-24.0.3.tar.xz/UI/window-basic-auto-config.cpp -> obs-studio-24.0.5.tar.xz/UI/window-basic-auto-config.cpp
Changed
10
1
2
#ifdef BROWSER_AVAILABLE
3
std::string service = QT_TO_UTF8(ui->service->currentText());
4
5
+ OAuth::DeleteCookies(service);
6
+
7
auth = OAuthStreamKey::Login(this, service);
8
if (!!auth)
9
OnAuthConnected();
10
obs-studio-24.0.3.tar.xz/UI/window-basic-interaction.cpp -> obs-studio-24.0.5.tar.xz/UI/window-basic-interaction.cpp
Changed
12
1
2
const char *name = obs_source_get_name(source);
3
setWindowTitle(QTStr("Basic.InteractionWindow").arg(QT_UTF8(name)));
4
5
+ Qt::WindowFlags flags = windowFlags();
6
+ Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint;
7
+ setWindowFlags(flags & (~helpFlag));
8
+
9
auto addDrawCallback = [this]() {
10
obs_display_add_draw_callback(ui->preview->GetDisplay(),
11
OBSBasicInteraction::DrawPreview,
12
obs-studio-24.0.3.tar.xz/UI/window-basic-main-outputs.cpp -> obs-studio-24.0.5.tar.xz/UI/window-basic-main-outputs.cpp
Changed
9
1
2
} else if (videoEncoder == SIMPLE_ENCODER_NVENC) {
3
UpdateRecordingSettings_nvenc(crf);
4
}
5
+ UpdateRecordingAudioSettings();
6
}
7
8
inline void SimpleOutput::SetupOutputs()
9
obs-studio-24.0.3.tar.xz/UI/window-basic-main-scene-collections.cpp -> obs-studio-24.0.5.tar.xz/UI/window-basic-main-scene-collections.cpp
Changed
92
1
2
return found;
3
}
4
5
+static bool GetUnusedSceneCollectionFile(std::string &name, std::string &file)
6
+{
7
+ char path[512];
8
+ size_t len;
9
+ int ret;
10
+
11
+ if (!GetFileSafeName(name.c_str(), file)) {
12
+ blog(LOG_WARNING, "Failed to create safe file name for '%s'",
13
+ name.c_str());
14
+ return false;
15
+ }
16
+
17
+ ret = GetConfigPath(path, sizeof(path), "obs-studio/basic/scenes/");
18
+ if (ret <= 0) {
19
+ blog(LOG_WARNING, "Failed to get scene collection config path");
20
+ return false;
21
+ }
22
+
23
+ len = file.size();
24
+ file.insert(0, path);
25
+
26
+ if (!GetClosestUnusedFileName(file, "json")) {
27
+ blog(LOG_WARNING, "Failed to get closest file name for %s",
28
+ file.c_str());
29
+ return false;
30
+ }
31
+
32
+ file.erase(file.size() - 5, 5);
33
+ file.erase(0, file.size() - len);
34
+ return true;
35
+}
36
+
37
static bool GetSceneCollectionName(QWidget *parent, std::string &name,
38
std::string &file,
39
const char *oldName = nullptr)
40
41
bool rename = oldName != nullptr;
42
const char *title;
43
const char *text;
44
- char path[512];
45
- size_t len;
46
- int ret;
47
48
if (rename) {
49
title = Str("Basic.Main.RenameSceneCollection.Title");
50
51
break;
52
}
53
54
- if (!GetFileSafeName(name.c_str(), file)) {
55
- blog(LOG_WARNING, "Failed to create safe file name for '%s'",
56
- name.c_str());
57
- return false;
58
- }
59
-
60
- ret = GetConfigPath(path, sizeof(path), "obs-studio/basic/scenes/");
61
- if (ret <= 0) {
62
- blog(LOG_WARNING, "Failed to get scene collection config path");
63
- return false;
64
- }
65
-
66
- len = file.size();
67
- file.insert(0, path);
68
-
69
- if (!GetClosestUnusedFileName(file, "json")) {
70
- blog(LOG_WARNING, "Failed to get closest file name for %s",
71
- file.c_str());
72
+ if (!GetUnusedSceneCollectionFile(name, file)) {
73
return false;
74
}
75
76
- file.erase(file.size() - 5, 5);
77
- file.erase(0, file.size() - len);
78
return true;
79
}
80
81
82
name = QT_TO_UTF8(qname);
83
if (SceneCollectionExists(name.c_str()))
84
return false;
85
+
86
+ if (!GetUnusedSceneCollectionFile(name, file)) {
87
+ return false;
88
+ }
89
}
90
91
SaveProjectNow();
92
obs-studio-24.0.3.tar.xz/UI/window-basic-settings-stream.cpp -> obs-studio-24.0.5.tar.xz/UI/window-basic-settings-stream.cpp
Changed
10
1
2
#ifdef BROWSER_AVAILABLE
3
std::string service = QT_TO_UTF8(ui->service->currentText());
4
5
+ OAuth::DeleteCookies(service);
6
+
7
auth = OAuthStreamKey::Login(this, service);
8
if (!!auth)
9
OnAuthConnected();
10
obs-studio-24.0.3.tar.xz/UI/window-basic-settings.cpp -> obs-studio-24.0.5.tar.xz/UI/window-basic-settings.cpp
Changed
22
1
2
3
const char *str;
4
if (sampleRate == 48000)
5
- str = "48khz";
6
+ str = "48 kHz";
7
else
8
- str = "44.1khz";
9
+ str = "44.1 kHz";
10
11
int sampleRateIdx = ui->sampleRate->findText(str);
12
if (sampleRateIdx != -1)
13
14
}
15
16
int sampleRate = 44100;
17
- if (sampleRateStr == "48khz")
18
+ if (sampleRateStr == "48 kHz")
19
sampleRate = 48000;
20
21
if (WidgetChanged(ui->sampleRate))
22
obs-studio-24.0.3.tar.xz/UI/window-extra-browsers.cpp -> obs-studio-24.0.5.tar.xz/UI/window-extra-browsers.cpp
Changed
26
1
2
3
dock->SetWidget(browser);
4
5
+ /* Add support for Twitch Dashboard panels */
6
+ if (url.contains("twitch.tv/popout") &&
7
+ url.contains("dashboard/live")) {
8
+ QRegularExpression re("twitch.tv\/popout\/([^/]+)\/");
9
+ QRegularExpressionMatch match = re.match(url);
10
+ QString username = match.captured(1);
11
+ if (username.length() > 0) {
12
+ std::string script;
13
+ script =
14
+ "Object.defineProperty(document, 'referrer', { get: () => '";
15
+ script += "https://twitch.tv/";
16
+ script += QT_TO_UTF8(username);
17
+ script += "/dashboard/live";
18
+ script += "'});";
19
+ browser->setStartupScript(script);
20
+ }
21
+ }
22
+
23
addDockWidget(Qt::RightDockWidgetArea, dock);
24
25
if (firstCreate) {
26
obs-studio-24.0.3.tar.xz/UI/window-projector.cpp -> obs-studio-24.0.5.tar.xz/UI/window-projector.cpp
Changed
11
1
2
source = curSource;
3
window->source = source;
4
}
5
+ } else if (window->type == ProjectorType::Preview &&
6
+ !main->IsPreviewProgramMode()) {
7
+ window->source = nullptr;
8
}
9
10
if (source)
11
obs-studio-24.0.3.tar.xz/cmake/Modules/ObsHelpers.cmake -> obs-studio-24.0.5.tar.xz/cmake/Modules/ObsHelpers.cmake
Changed
10
1
2
set(OBS_INSTALL_PREFIX "")
3
set(OBS_RELATIVE_PREFIX "../")
4
5
- set(OBS_SCRIPT_PLUGIN_DESTINATION "${OBS_DATA_DESTINATION}/obs-scripting/${_lib_suffix}bit")
6
+ set(OBS_SCRIPT_PLUGIN_DESTINATION "${OBS_DATA_DESTINATION}/obs-scripting")
7
else()
8
set(OBS_EXECUTABLE_DESTINATION "bin/${_lib_suffix}bit")
9
set(OBS_EXECUTABLE32_DESTINATION "bin/32bit")
10
obs-studio-24.0.3.tar.xz/deps/media-playback/media-playback/media.c -> obs-studio-24.0.5.tar.xz/deps/media-playback/media-playback/media.c
Changed
32
1
2
3
int ret = av_read_frame(media->fmt, &pkt);
4
if (ret < 0) {
5
- if (ret != AVERROR_EOF)
6
+ if (ret != AVERROR_EOF && ret != AVERROR_EXIT)
7
blog(LOG_WARNING, "MP: av_read_frame failed: %s (%d)",
8
av_err2str(ret), ret);
9
return ret;
10
11
while (!mp_media_ready_to_start(m)) {
12
if (!m->eof) {
13
int ret = mp_media_next_packet(m);
14
- if (ret == AVERROR_EOF)
15
+ if (ret == AVERROR_EOF || ret == AVERROR_EXIT)
16
m->eof = true;
17
else if (ret < 0)
18
return false;
19
20
av_dict_set_int(&opts, "buffer_size", m->buffering, 0);
21
22
m->fmt = avformat_alloc_context();
23
- m->fmt->interrupt_callback.callback = interrupt_callback;
24
- m->fmt->interrupt_callback.opaque = m;
25
+ if (!m->is_local_file) {
26
+ m->fmt->interrupt_callback.callback = interrupt_callback;
27
+ m->fmt->interrupt_callback.opaque = m;
28
+ }
29
30
int ret = avformat_open_input(&m->fmt, m->path, format,
31
opts ? &opts : NULL);
32
obs-studio-24.0.3.tar.xz/deps/obs-scripting/CMakeLists.txt -> obs-studio-24.0.5.tar.xz/deps/obs-scripting/CMakeLists.txt
Changed
13
1
2
w32-pthreads)
3
endif()
4
5
+if(APPLE)
6
+ set(obs-scripting_PLATFORM_DEPS
7
+ objc)
8
+endif()
9
+
10
option(DISABLE_LUA "Disable Lua scripting support" OFF)
11
option(DISABLE_PYTHON "Disable Python scripting support" OFF)
12
13
obs-studio-24.0.3.tar.xz/deps/obs-scripting/obs-scripting-lua.c -> obs-studio-24.0.5.tar.xz/deps/obs-scripting/obs-scripting-lua.c
Changed
44
1
2
for val in pairs(package.preload) do\n\
3
package.preload[val] = nil\n\
4
end\n\
5
-package.cpath = package.cpath .. \";\" .. \"%s\" .. \"/?." SO_EXT "\"\n\
6
+package.cpath = package.cpath .. \";\" .. \"%s/Contents/MacOS/?.so\" .. \";\" .. \"%s\" .. \"/?." SO_EXT
7
+ "\"\n\
8
require \"obslua\"\n";
9
10
static const char *get_script_path_func = "\
11
12
/* ---------------------------------------------- */
13
/* Initialize Lua startup script */
14
15
- dstr_printf(&tmp, startup_script_template, SCRIPT_DIR);
16
+ char *bundlePath = "./";
17
+
18
+#ifdef __APPLE__
19
+ Class nsRunningApplication = objc_lookUpClass("NSRunningApplication");
20
+ SEL currentAppSel = sel_getUid("currentApplication");
21
+
22
+ typedef id (*running_app_func)(Class, SEL);
23
+ running_app_func operatingSystemName = (running_app_func)objc_msgSend;
24
+ id app = operatingSystemName(nsRunningApplication, currentAppSel);
25
+
26
+ typedef id (*bundle_url_func)(id, SEL);
27
+ bundle_url_func bundleURL = (bundle_url_func)objc_msgSend;
28
+ id url = bundleURL(app, sel_getUid("bundleURL"));
29
+
30
+ typedef id (*url_path_func)(id, SEL);
31
+ url_path_func urlPath = (url_path_func)objc_msgSend;
32
+
33
+ id path = urlPath(url, sel_getUid("path"));
34
+
35
+ typedef id (*string_func)(id, SEL);
36
+ string_func utf8String = (string_func)objc_msgSend;
37
+ bundlePath = (char *)utf8String(path, sel_registerName("UTF8String"));
38
+#endif
39
+
40
+ dstr_printf(&tmp, startup_script_template, bundlePath, SCRIPT_DIR);
41
startup_script = tmp.array;
42
43
dstr_free(&dep_paths);
44
obs-studio-24.0.3.tar.xz/deps/obs-scripting/obs-scripting-python-import.c -> obs-studio-24.0.5.tar.xz/deps/obs-scripting/obs-scripting-python-import.c
Changed
23
1
2
#define SO_EXT ".dylib"
3
#endif
4
5
+#ifdef __APPLE__
6
+#define PYTHON_LIB_SUBDIR "lib/"
7
+#else
8
+#define PYTHON_LIB_SUBDIR ""
9
+#endif
10
+
11
bool import_python(const char *python_path)
12
{
13
struct dstr lib_path;
14
15
dstr_init_copy(&lib_path, python_path);
16
dstr_replace(&lib_path, "\\", "/");
17
if (!dstr_is_empty(&lib_path)) {
18
- dstr_cat(&lib_path, "/");
19
+ dstr_cat(&lib_path, "/" PYTHON_LIB_SUBDIR);
20
}
21
dstr_cat(&lib_path, PYTHON_LIB SO_EXT);
22
23
obs-studio-24.0.3.tar.xz/deps/obs-scripting/obs-scripting-python.c -> obs-studio-24.0.5.tar.xz/deps/obs-scripting/obs-scripting-python.c
Changed
15
1
2
3
add_to_python_path(SCRIPT_DIR);
4
5
+#if __APPLE__
6
+ char *exec_path = os_get_executable_path_ptr("");
7
+ if (exec_path)
8
+ add_to_python_path(exec_path);
9
+ bfree(exec_path);
10
+#endif
11
+
12
py_obspython = PyImport_ImportModule("obspython");
13
bool success = !py_error();
14
if (!success) {
15
obs-studio-24.0.3.tar.xz/deps/obs-scripting/obspython/CMakeLists.txt -> obs-studio-24.0.5.tar.xz/deps/obs-scripting/obspython/CMakeLists.txt
Changed
31
1
2
else()
3
SWIG_ADD_MODULE(obspython python obspython.i ../cstrcache.cpp ../cstrcache.h)
4
endif()
5
-SWIG_LINK_LIBRARIES(obspython obs-scripting libobs ${PYTHON_LIBRARIES})
6
+
7
+IF(APPLE)
8
+ SWIG_LINK_LIBRARIES(obspython obs-scripting libobs)
9
+ELSE()
10
+ SWIG_LINK_LIBRARIES(obspython obs-scripting libobs ${PYTHON_LIBRARIES})
11
+ENDIF()
12
13
function(install_plugin_bin_swig target additional_target)
14
if(APPLE)
15
16
PREFIX "")
17
18
if (APPLE)
19
- set_property(
20
- TARGET ${additional_target}
21
- APPEND
22
- PROPERTY INSTALL_RPATH
23
- "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/"
24
- "/Library/Frameworks/Python.framework/Versions/3.6/lib/"
25
- "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/"
26
- )
27
+ SET_TARGET_PROPERTIES(${additional_target} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
28
endif()
29
30
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/obspython.py"
31
obs-studio-24.0.3.tar.xz/formatcode.sh -> obs-studio-24.0.5.tar.xz/formatcode.sh
Changed
17
1
2
CLANG_FORMAT=clang-format
3
fi
4
5
-find . -type d \( -path ./deps -o -path ./cmake -o -path ./plugins/decklink/win -o -path ./plugins/decklink/mac -o -path ./plugins/decklink/linux -o -path ./build \) -prune -type f -o -name '*.h' -or -name '*.hpp' -or -name '*.m' -or -name '*.mm' -or -name '*.c' -or -name '*.cpp' \
6
+find . -type d \( -path ./deps \
7
+-o -path ./cmake \
8
+-o -path ./plugins/decklink/win \
9
+-o -path ./plugins/decklink/mac \
10
+-o -path ./plugins/decklink/linux \
11
+-o -path ./plugins/enc-amf \
12
+-o -path ./plugins/mac-syphon/syphon-framework \
13
+-o -path ./plugins/obs-outputs/ftl-sdk \
14
+-o -path ./plugins/obs-vst \
15
+-o -path ./build \) -prune -type f -o -name '*.h' -or -name '*.hpp' -or -name '*.m' -or -name '*.mm' -or -name '*.c' -or -name '*.cpp' \
16
| xargs -I{} -P ${NPROC} ${CLANG_FORMAT} -i -style=file -fallback-style=none {}
17
obs-studio-24.0.3.tar.xz/libobs-d3d11/d3d11-rebuild.cpp -> obs-studio-24.0.5.tar.xz/libobs-d3d11/d3d11-rebuild.cpp
Changed
19
1
2
if (FAILED(hr))
3
throw HRError("Failed to create vertex shader", hr);
4
5
- hr = dev->CreateInputLayout(layoutData.data(), (UINT)layoutData.size(),
6
- data.data(), data.size(), &layout);
7
- if (FAILED(hr))
8
- throw HRError("Failed to create input layout", hr);
9
+ const UINT layoutSize = (UINT)layoutData.size();
10
+ if (layoutSize > 0) {
11
+ hr = dev->CreateInputLayout(layoutData.data(), layoutSize,
12
+ data.data(), data.size(), &layout);
13
+ if (FAILED(hr))
14
+ throw HRError("Failed to create input layout", hr);
15
+ }
16
17
if (constantSize) {
18
hr = dev->CreateBuffer(&bd, NULL, &constants);
19
obs-studio-24.0.3.tar.xz/libobs-d3d11/d3d11-subsystem.cpp -> obs-studio-24.0.5.tar.xz/libobs-d3d11/d3d11-subsystem.cpp
Changed
126
1
2
}
3
}
4
5
+static bool GetMonitorTarget(const MONITORINFOEX &info,
6
+ DISPLAYCONFIG_TARGET_DEVICE_NAME &target)
7
+{
8
+ bool found = false;
9
+
10
+ UINT32 numPath, numMode;
11
+ if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPath,
12
+ &numMode) == ERROR_SUCCESS) {
13
+ std::vector<DISPLAYCONFIG_PATH_INFO> paths(numPath);
14
+ std::vector<DISPLAYCONFIG_MODE_INFO> modes(numMode);
15
+ if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPath,
16
+ paths.data(), &numMode, modes.data(),
17
+ nullptr) == ERROR_SUCCESS) {
18
+ paths.resize(numPath);
19
+ for (size_t i = 0; i < numPath; ++i) {
20
+ const DISPLAYCONFIG_PATH_INFO &path = paths[i];
21
+
22
+ DISPLAYCONFIG_SOURCE_DEVICE_NAME
23
+ source;
24
+ source.header.type =
25
+ DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
26
+ source.header.size = sizeof(source);
27
+ source.header.adapterId =
28
+ path.sourceInfo.adapterId;
29
+ source.header.id = path.sourceInfo.id;
30
+ if (DisplayConfigGetDeviceInfo(
31
+ &source.header) == ERROR_SUCCESS &&
32
+ wcscmp(info.szDevice,
33
+ source.viewGdiDeviceName) == 0) {
34
+ target.header.type =
35
+ DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
36
+ target.header.size = sizeof(target);
37
+ target.header.adapterId =
38
+ path.sourceInfo.adapterId;
39
+ target.header.id = path.targetInfo.id;
40
+ found = DisplayConfigGetDeviceInfo(
41
+ &target.header) ==
42
+ ERROR_SUCCESS;
43
+ break;
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ return found;
50
+}
51
+
52
static inline void LogAdapterMonitors(IDXGIAdapter1 *adapter)
53
{
54
UINT i;
55
56
if (FAILED(output->GetDesc(&desc)))
57
continue;
58
59
- RECT rect = desc.DesktopCoordinates;
60
+ unsigned refresh = 0;
61
+
62
+ bool target_found = false;
63
+ DISPLAYCONFIG_TARGET_DEVICE_NAME target;
64
+
65
+ MONITORINFOEX info;
66
+ info.cbSize = sizeof(info);
67
+ if (GetMonitorInfo(desc.Monitor, &info)) {
68
+ target_found = GetMonitorTarget(info, target);
69
+
70
+ DEVMODE mode;
71
+ mode.dmSize = sizeof(mode);
72
+ mode.dmDriverExtra = 0;
73
+ if (EnumDisplaySettings(info.szDevice,
74
+ ENUM_CURRENT_SETTINGS, &mode)) {
75
+ refresh = mode.dmDisplayFrequency;
76
+ }
77
+ }
78
+
79
+ if (!target_found) {
80
+ target.monitorFriendlyDeviceName[0] = 0;
81
+ }
82
+
83
+ const RECT &rect = desc.DesktopCoordinates;
84
blog(LOG_INFO,
85
"\t output %u: "
86
"pos={%d, %d}, "
87
"size={%d, %d}, "
88
- "attached=%s",
89
+ "attached=%s, "
90
+ "refresh=%u, "
91
+ "name=%ls",
92
i, rect.left, rect.top, rect.right - rect.left,
93
rect.bottom - rect.top,
94
- desc.AttachedToDesktop ? "true" : "false");
95
+ desc.AttachedToDesktop ? "true" : "false", refresh,
96
+ target.monitorFriendlyDeviceName);
97
}
98
}
99
100
101
blog(LOG_INFO, "\t Shared VRAM: %u",
102
desc.SharedSystemMemory);
103
104
+ /* driver version */
105
+ LARGE_INTEGER umd;
106
+ hr = adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice),
107
+ &umd);
108
+ if (SUCCEEDED(hr)) {
109
+ const uint64_t version = umd.QuadPart;
110
+ const uint16_t aa = (version >> 48) & 0xffff;
111
+ const uint16_t bb = (version >> 32) & 0xffff;
112
+ const uint16_t ccccc = (version >> 16) & 0xffff;
113
+ const uint16_t ddddd = version & 0xffff;
114
+ blog(LOG_INFO,
115
+ "\t Driver Version: %" PRIu16 ".%" PRIu16
116
+ ".%" PRIu16 ".%" PRIu16,
117
+ aa, bb, ccccc, ddddd);
118
+ } else {
119
+ blog(LOG_INFO, "\t Driver Version: Unknown (0x%X)",
120
+ (unsigned)hr);
121
+ }
122
+
123
LogAdapterMonitors(adapter);
124
}
125
}
126
obs-studio-24.0.3.tar.xz/libobs/CMakeLists.txt -> obs-studio-24.0.5.tar.xz/libobs/CMakeLists.txt
Changed
10
1
2
endif()
3
elseif(APPLE)
4
set(libobs_PLATFORM_SOURCES
5
- obs-cocoa.c
6
+ obs-cocoa.m
7
util/threading-posix.c
8
util/pipe-posix.c
9
util/platform-nix.c
10
obs-studio-24.0.5.tar.xz/libobs/obs-cocoa.m
Added
1778
1
2
+/******************************************************************************
3
+ Copyright (C) 2013 by Ruwen Hahn <palana@stunned.de>
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 2 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+******************************************************************************/
18
+
19
+#include "util/platform.h"
20
+#include "util/dstr.h"
21
+#include "obs.h"
22
+#include "obs-internal.h"
23
+
24
+#include <unistd.h>
25
+#include <sys/types.h>
26
+#include <sys/sysctl.h>
27
+
28
+#include <objc/objc.h>
29
+#include <Carbon/Carbon.h>
30
+#include <IOKit/hid/IOHIDDevice.h>
31
+#include <IOKit/hid/IOHIDManager.h>
32
+
33
+#import <AppKit/AppKit.h>
34
+
35
+bool is_in_bundle()
36
+{
37
+ NSRunningApplication *app = [NSRunningApplication currentApplication];
38
+ return [app bundleIdentifier] != nil;
39
+}
40
+
41
+const char *get_module_extension(void)
42
+{
43
+ return ".so";
44
+}
45
+
46
+static const char *module_bin[] = {
47
+ "../obs-plugins",
48
+ OBS_INSTALL_PREFIX "obs-plugins",
49
+};
50
+
51
+static const char *module_data[] = {
52
+ "../data/obs-plugins/%module%",
53
+ OBS_INSTALL_DATA_PATH "obs-plugins/%module%",
54
+};
55
+
56
+static const int module_patterns_size =
57
+ sizeof(module_bin) / sizeof(module_bin[0]);
58
+
59
+void add_default_module_paths(void)
60
+{
61
+ for (int i = 0; i < module_patterns_size; i++)
62
+ obs_add_module_path(module_bin[i], module_data[i]);
63
+
64
+ if (is_in_bundle()) {
65
+ NSRunningApplication *app =
66
+ [NSRunningApplication currentApplication];
67
+ NSURL *bundleURL = [app bundleURL];
68
+ NSURL *pluginsURL = [bundleURL
69
+ URLByAppendingPathComponent:@"Contents/Plugins"];
70
+ NSURL *dataURL = [bundleURL
71
+ URLByAppendingPathComponent:
72
+ @"Contents/Resources/data/obs-plugins/%module%"];
73
+
74
+ const char *binPath = [[pluginsURL path]
75
+ cStringUsingEncoding:NSUTF8StringEncoding];
76
+ const char *dataPath = [[dataURL path]
77
+ cStringUsingEncoding:NSUTF8StringEncoding];
78
+
79
+ obs_add_module_path(binPath, dataPath);
80
+ }
81
+}
82
+
83
+char *find_libobs_data_file(const char *file)
84
+{
85
+ struct dstr path;
86
+
87
+ if (is_in_bundle()) {
88
+ NSRunningApplication *app =
89
+ [NSRunningApplication currentApplication];
90
+ NSURL *bundleURL = [app bundleURL];
91
+ NSURL *libobsDataURL =
92
+ [bundleURL URLByAppendingPathComponent:
93
+ @"Contents/Resources/data/libobs/"];
94
+ const char *libobsDataPath = [[libobsDataURL path]
95
+ cStringUsingEncoding:NSUTF8StringEncoding];
96
+ dstr_init_copy(&path, libobsDataPath);
97
+ dstr_cat(&path, "/");
98
+ } else {
99
+ dstr_init_copy(&path, OBS_INSTALL_DATA_PATH "/libobs/");
100
+ }
101
+
102
+ dstr_cat(&path, file);
103
+ return path.array;
104
+}
105
+
106
+static void log_processor_name(void)
107
+{
108
+ char *name = NULL;
109
+ size_t size;
110
+ int ret;
111
+
112
+ ret = sysctlbyname("machdep.cpu.brand_string", NULL, &size, NULL, 0);
113
+ if (ret != 0)
114
+ return;
115
+
116
+ name = malloc(size);
117
+
118
+ ret = sysctlbyname("machdep.cpu.brand_string", name, &size, NULL, 0);
119
+ if (ret == 0)
120
+ blog(LOG_INFO, "CPU Name: %s", name);
121
+
122
+ free(name);
123
+}
124
+
125
+static void log_processor_speed(void)
126
+{
127
+ size_t size;
128
+ long long freq;
129
+ int ret;
130
+
131
+ size = sizeof(freq);
132
+ ret = sysctlbyname("hw.cpufrequency", &freq, &size, NULL, 0);
133
+ if (ret == 0)
134
+ blog(LOG_INFO, "CPU Speed: %lldMHz", freq / 1000000);
135
+}
136
+
137
+static void log_processor_cores(void)
138
+{
139
+ blog(LOG_INFO, "Physical Cores: %d, Logical Cores: %d",
140
+ os_get_physical_cores(), os_get_logical_cores());
141
+}
142
+
143
+static void log_available_memory(void)
144
+{
145
+ size_t size;
146
+ long long memory_available;
147
+ int ret;
148
+
149
+ size = sizeof(memory_available);
150
+ ret = sysctlbyname("hw.memsize", &memory_available, &size, NULL, 0);
151
+ if (ret == 0)
152
+ blog(LOG_INFO, "Physical Memory: %lldMB Total",
153
+ memory_available / 1024 / 1024);
154
+}
155
+
156
+static void log_os_name(id pi, SEL UTF8StringSel)
157
+{
158
+ typedef int (*os_func)(id, SEL);
159
+ os_func operatingSystem = (os_func)objc_msgSend;
160
+ unsigned long os_id = (unsigned long)operatingSystem(
161
+ pi, sel_registerName("operatingSystem"));
162
+
163
+ typedef id (*os_name_func)(id, SEL);
164
+ os_name_func operatingSystemName = (os_name_func)objc_msgSend;
165
+ id os = operatingSystemName(pi,
166
+ sel_registerName("operatingSystemName"));
167
+ typedef const char *(*utf8_func)(id, SEL);
168
+ utf8_func UTF8String = (utf8_func)objc_msgSend;
169
+ const char *name = UTF8String(os, UTF8StringSel);
170
+
171
+ if (os_id == 5 /*NSMACHOperatingSystem*/) {
172
+ blog(LOG_INFO, "OS Name: Mac OS X (%s)", name);
173
+ return;
174
+ }
175
+
176
+ blog(LOG_INFO, "OS Name: %s", name ? name : "Unknown");
177
+}
178
+
179
+static void log_os_version(id pi, SEL UTF8StringSel)
180
+{
181
+ typedef id (*version_func)(id, SEL);
182
+ version_func operatingSystemVersionString = (version_func)objc_msgSend;
183
+ id vs = operatingSystemVersionString(
184
+ pi, sel_registerName("operatingSystemVersionString"));
185
+ typedef const char *(*utf8_func)(id, SEL);
186
+ utf8_func UTF8String = (utf8_func)objc_msgSend;
187
+ const char *version = UTF8String(vs, UTF8StringSel);
188
+
189
+ blog(LOG_INFO, "OS Version: %s", version ? version : "Unknown");
190
+}
191
+
192
+static void log_os(void)
193
+{
194
+ Class NSProcessInfo = objc_getClass("NSProcessInfo");
195
+ typedef id (*func)(id, SEL);
196
+ func processInfo = (func)objc_msgSend;
197
+ id pi = processInfo((id)NSProcessInfo, sel_registerName("processInfo"));
198
+
199
+ SEL UTF8String = sel_registerName("UTF8String");
200
+
201
+ log_os_name(pi, UTF8String);
202
+ log_os_version(pi, UTF8String);
203
+}
204
+
205
+static void log_kernel_version(void)
206
+{
207
+ char kernel_version[1024];
208
+ size_t size = sizeof(kernel_version);
209
+ int ret;
210
+
211
+ ret = sysctlbyname("kern.osrelease", kernel_version, &size, NULL, 0);
212
+ if (ret == 0)
213
+ blog(LOG_INFO, "Kernel Version: %s", kernel_version);
214
+}
215
+
216
+void log_system_info(void)
217
+{
218
+ log_processor_name();
219
+ log_processor_speed();
220
+ log_processor_cores();
221
+ log_available_memory();
222
+ log_os();
223
+ log_kernel_version();
224
+}
225
+
226
+static bool dstr_from_cfstring(struct dstr *str, CFStringRef ref)
227
+{
228
+ CFIndex length = CFStringGetLength(ref);
229
+ CFIndex max_size = CFStringGetMaximumSizeForEncoding(
230
+ length, kCFStringEncodingUTF8);
231
+ dstr_reserve(str, max_size);
232
+
233
+ if (!CFStringGetCString(ref, str->array, max_size,
234
+ kCFStringEncodingUTF8))
235
+ return false;
236
+
237
+ str->len = strlen(str->array);
238
+ return true;
239
+}
240
+
241
+struct obs_hotkeys_platform {
242
+ volatile long refs;
243
+ TISInputSourceRef tis;
244
+ CFDataRef layout_data;
245
+ UCKeyboardLayout *layout;
246
+ IOHIDManagerRef manager;
247
+ DARRAY(IOHIDElementRef) keys[OBS_KEY_LAST_VALUE];
248
+};
249
+
250
+static void hotkeys_retain(struct obs_hotkeys_platform *plat)
251
+{
252
+ os_atomic_inc_long(&plat->refs);
253
+}
254
+
255
+static inline void free_hotkeys_platform(obs_hotkeys_platform_t *plat);
256
+static void hotkeys_release(struct obs_hotkeys_platform *plat)
257
+{
258
+ if (os_atomic_dec_long(&plat->refs) == -1)
259
+ free_hotkeys_platform(plat);
260
+}
261
+
262
+#define INVALID_KEY 0xff
263
+
264
+int obs_key_to_virtual_key(obs_key_t code)
265
+{
266
+ switch (code) {
267
+ case OBS_KEY_A:
268
+ return kVK_ANSI_A;
269
+ case OBS_KEY_B:
270
+ return kVK_ANSI_B;
271
+ case OBS_KEY_C:
272
+ return kVK_ANSI_C;
273
+ case OBS_KEY_D:
274
+ return kVK_ANSI_D;
275
+ case OBS_KEY_E:
276
+ return kVK_ANSI_E;
277
+ case OBS_KEY_F:
278
+ return kVK_ANSI_F;
279
+ case OBS_KEY_G:
280
+ return kVK_ANSI_G;
281
+ case OBS_KEY_H:
282
+ return kVK_ANSI_H;
283
+ case OBS_KEY_I:
284
+ return kVK_ANSI_I;
285
+ case OBS_KEY_J:
286
+ return kVK_ANSI_J;
287
+ case OBS_KEY_K:
288
+ return kVK_ANSI_K;
289
+ case OBS_KEY_L:
290
+ return kVK_ANSI_L;
291
+ case OBS_KEY_M:
292
+ return kVK_ANSI_M;
293
+ case OBS_KEY_N:
294
+ return kVK_ANSI_N;
295
+ case OBS_KEY_O:
296
+ return kVK_ANSI_O;
297
+ case OBS_KEY_P:
298
+ return kVK_ANSI_P;
299
+ case OBS_KEY_Q:
300
+ return kVK_ANSI_Q;
301
+ case OBS_KEY_R:
302
+ return kVK_ANSI_R;
303
+ case OBS_KEY_S:
304
+ return kVK_ANSI_S;
305
+ case OBS_KEY_T:
306
+ return kVK_ANSI_T;
307
+ case OBS_KEY_U:
308
+ return kVK_ANSI_U;
309
+ case OBS_KEY_V:
310
+ return kVK_ANSI_V;
311
+ case OBS_KEY_W:
312
+ return kVK_ANSI_W;
313
+ case OBS_KEY_X:
314
+ return kVK_ANSI_X;
315
+ case OBS_KEY_Y:
316
+ return kVK_ANSI_Y;
317
+ case OBS_KEY_Z:
318
+ return kVK_ANSI_Z;
319
+
320
+ case OBS_KEY_1:
321
+ return kVK_ANSI_1;
322
+ case OBS_KEY_2:
323
+ return kVK_ANSI_2;
324
+ case OBS_KEY_3:
325
+ return kVK_ANSI_3;
326
+ case OBS_KEY_4:
327
+ return kVK_ANSI_4;
328
+ case OBS_KEY_5:
329
+ return kVK_ANSI_5;
330
+ case OBS_KEY_6:
331
+ return kVK_ANSI_6;
332
+ case OBS_KEY_7:
333
+ return kVK_ANSI_7;
334
+ case OBS_KEY_8:
335
+ return kVK_ANSI_8;
336
+ case OBS_KEY_9:
337
+ return kVK_ANSI_9;
338
+ case OBS_KEY_0:
339
+ return kVK_ANSI_0;
340
+
341
+ case OBS_KEY_RETURN:
342
+ return kVK_Return;
343
+ case OBS_KEY_ESCAPE:
344
+ return kVK_Escape;
345
+ case OBS_KEY_BACKSPACE:
346
+ return kVK_Delete;
347
+ case OBS_KEY_TAB:
348
+ return kVK_Tab;
349
+ case OBS_KEY_SPACE:
350
+ return kVK_Space;
351
+ case OBS_KEY_MINUS:
352
+ return kVK_ANSI_Minus;
353
+ case OBS_KEY_EQUAL:
354
+ return kVK_ANSI_Equal;
355
+ case OBS_KEY_BRACKETLEFT:
356
+ return kVK_ANSI_LeftBracket;
357
+ case OBS_KEY_BRACKETRIGHT:
358
+ return kVK_ANSI_RightBracket;
359
+ case OBS_KEY_BACKSLASH:
360
+ return kVK_ANSI_Backslash;
361
+ case OBS_KEY_SEMICOLON:
362
+ return kVK_ANSI_Semicolon;
363
+ case OBS_KEY_QUOTE:
364
+ return kVK_ANSI_Quote;
365
+ case OBS_KEY_DEAD_GRAVE:
366
+ return kVK_ANSI_Grave;
367
+ case OBS_KEY_COMMA:
368
+ return kVK_ANSI_Comma;
369
+ case OBS_KEY_PERIOD:
370
+ return kVK_ANSI_Period;
371
+ case OBS_KEY_SLASH:
372
+ return kVK_ANSI_Slash;
373
+ case OBS_KEY_CAPSLOCK:
374
+ return kVK_CapsLock;
375
+ case OBS_KEY_SECTION:
376
+ return kVK_ISO_Section;
377
+
378
+ case OBS_KEY_F1:
379
+ return kVK_F1;
380
+ case OBS_KEY_F2:
381
+ return kVK_F2;
382
+ case OBS_KEY_F3:
383
+ return kVK_F3;
384
+ case OBS_KEY_F4:
385
+ return kVK_F4;
386
+ case OBS_KEY_F5:
387
+ return kVK_F5;
388
+ case OBS_KEY_F6:
389
+ return kVK_F6;
390
+ case OBS_KEY_F7:
391
+ return kVK_F7;
392
+ case OBS_KEY_F8:
393
+ return kVK_F8;
394
+ case OBS_KEY_F9:
395
+ return kVK_F9;
396
+ case OBS_KEY_F10:
397
+ return kVK_F10;
398
+ case OBS_KEY_F11:
399
+ return kVK_F11;
400
+ case OBS_KEY_F12:
401
+ return kVK_F12;
402
+
403
+ case OBS_KEY_HELP:
404
+ return kVK_Help;
405
+ case OBS_KEY_HOME:
406
+ return kVK_Home;
407
+ case OBS_KEY_PAGEUP:
408
+ return kVK_PageUp;
409
+ case OBS_KEY_DELETE:
410
+ return kVK_ForwardDelete;
411
+ case OBS_KEY_END:
412
+ return kVK_End;
413
+ case OBS_KEY_PAGEDOWN:
414
+ return kVK_PageDown;
415
+
416
+ case OBS_KEY_RIGHT:
417
+ return kVK_RightArrow;
418
+ case OBS_KEY_LEFT:
419
+ return kVK_LeftArrow;
420
+ case OBS_KEY_DOWN:
421
+ return kVK_DownArrow;
422
+ case OBS_KEY_UP:
423
+ return kVK_UpArrow;
424
+
425
+ case OBS_KEY_CLEAR:
426
+ return kVK_ANSI_KeypadClear;
427
+ case OBS_KEY_NUMSLASH:
428
+ return kVK_ANSI_KeypadDivide;
429
+ case OBS_KEY_NUMASTERISK:
430
+ return kVK_ANSI_KeypadMultiply;
431
+ case OBS_KEY_NUMMINUS:
432
+ return kVK_ANSI_KeypadMinus;
433
+ case OBS_KEY_NUMPLUS:
434
+ return kVK_ANSI_KeypadPlus;
435
+ case OBS_KEY_ENTER:
436
+ return kVK_ANSI_KeypadEnter;
437
+
438
+ case OBS_KEY_NUM1:
439
+ return kVK_ANSI_Keypad1;
440
+ case OBS_KEY_NUM2:
441
+ return kVK_ANSI_Keypad2;
442
+ case OBS_KEY_NUM3:
443
+ return kVK_ANSI_Keypad3;
444
+ case OBS_KEY_NUM4:
445
+ return kVK_ANSI_Keypad4;
446
+ case OBS_KEY_NUM5:
447
+ return kVK_ANSI_Keypad5;
448
+ case OBS_KEY_NUM6:
449
+ return kVK_ANSI_Keypad6;
450
+ case OBS_KEY_NUM7:
451
+ return kVK_ANSI_Keypad7;
452
+ case OBS_KEY_NUM8:
453
+ return kVK_ANSI_Keypad8;
454
+ case OBS_KEY_NUM9:
455
+ return kVK_ANSI_Keypad9;
456
+ case OBS_KEY_NUM0:
457
+ return kVK_ANSI_Keypad0;
458
+
459
+ case OBS_KEY_NUMPERIOD:
460
+ return kVK_ANSI_KeypadDecimal;
461
+ case OBS_KEY_NUMEQUAL:
462
+ return kVK_ANSI_KeypadEquals;
463
+
464
+ case OBS_KEY_F13:
465
+ return kVK_F13;
466
+ case OBS_KEY_F14:
467
+ return kVK_F14;
468
+ case OBS_KEY_F15:
469
+ return kVK_F15;
470
+ case OBS_KEY_F16:
471
+ return kVK_F16;
472
+ case OBS_KEY_F17:
473
+ return kVK_F17;
474
+ case OBS_KEY_F18:
475
+ return kVK_F18;
476
+ case OBS_KEY_F19:
477
+ return kVK_F19;
478
+ case OBS_KEY_F20:
479
+ return kVK_F20;
480
+
481
+ case OBS_KEY_CONTROL:
482
+ return kVK_Control;
483
+ case OBS_KEY_SHIFT:
484
+ return kVK_Shift;
485
+ case OBS_KEY_ALT:
486
+ return kVK_Option;
487
+ case OBS_KEY_META:
488
+ return kVK_Command;
489
+ //case OBS_KEY_CONTROL: return kVK_RightControl;
490
+ //case OBS_KEY_SHIFT: return kVK_RightShift;
491
+ //case OBS_KEY_ALT: return kVK_RightOption;
492
+ //case OBS_KEY_META: return 0x36;
493
+
494
+ case OBS_KEY_NONE:
495
+ case OBS_KEY_LAST_VALUE:
496
+ default:
497
+ break;
498
+ }
499
+ return INVALID_KEY;
500
+}
501
+
502
+static bool localized_key_to_str(obs_key_t key, struct dstr *str)
503
+{
504
+#define MAP_KEY(k, s) \
505
+ case k: \
506
+ dstr_copy(str, obs_get_hotkey_translation(k, s)); \
507
+ return true
508
+
509
+#define MAP_BUTTON(i) \
510
+ case OBS_KEY_MOUSE##i: \
511
+ dstr_copy(str, obs_get_hotkey_translation(key, "Mouse " #i)); \
512
+ return true
513
+
514
+ switch (key) {
515
+ MAP_KEY(OBS_KEY_SPACE, "Space");
516
+ MAP_KEY(OBS_KEY_NUMEQUAL, "= (Keypad)");
517
+ MAP_KEY(OBS_KEY_NUMASTERISK, "* (Keypad)");
518
+ MAP_KEY(OBS_KEY_NUMPLUS, "+ (Keypad)");
519
+ MAP_KEY(OBS_KEY_NUMMINUS, "- (Keypad)");
520
+ MAP_KEY(OBS_KEY_NUMPERIOD, ". (Keypad)");
521
+ MAP_KEY(OBS_KEY_NUMSLASH, "/ (Keypad)");
522
+ MAP_KEY(OBS_KEY_NUM0, "0 (Keypad)");
523
+ MAP_KEY(OBS_KEY_NUM1, "1 (Keypad)");
524
+ MAP_KEY(OBS_KEY_NUM2, "2 (Keypad)");
525
+ MAP_KEY(OBS_KEY_NUM3, "3 (Keypad)");
526
+ MAP_KEY(OBS_KEY_NUM4, "4 (Keypad)");
527
+ MAP_KEY(OBS_KEY_NUM5, "5 (Keypad)");
528
+ MAP_KEY(OBS_KEY_NUM6, "6 (Keypad)");
529
+ MAP_KEY(OBS_KEY_NUM7, "7 (Keypad)");
530
+ MAP_KEY(OBS_KEY_NUM8, "8 (Keypad)");
531
+ MAP_KEY(OBS_KEY_NUM9, "9 (Keypad)");
532
+
533
+ MAP_BUTTON(1);
534
+ MAP_BUTTON(2);
535
+ MAP_BUTTON(3);
536
+ MAP_BUTTON(4);
537
+ MAP_BUTTON(5);
538
+ MAP_BUTTON(6);
539
+ MAP_BUTTON(7);
540
+ MAP_BUTTON(8);
541
+ MAP_BUTTON(9);
542
+ MAP_BUTTON(10);
543
+ MAP_BUTTON(11);
544
+ MAP_BUTTON(12);
545
+ MAP_BUTTON(13);
546
+ MAP_BUTTON(14);
547
+ MAP_BUTTON(15);
548
+ MAP_BUTTON(16);
549
+ MAP_BUTTON(17);
550
+ MAP_BUTTON(18);
551
+ MAP_BUTTON(19);
552
+ MAP_BUTTON(20);
553
+ MAP_BUTTON(21);
554
+ MAP_BUTTON(22);
555
+ MAP_BUTTON(23);
556
+ MAP_BUTTON(24);
557
+ MAP_BUTTON(25);
558
+ MAP_BUTTON(26);
559
+ MAP_BUTTON(27);
560
+ MAP_BUTTON(28);
561
+ MAP_BUTTON(29);
562
+ default:
563
+ break;
564
+ }
565
+#undef MAP_BUTTON
566
+#undef MAP_KEY
567
+
568
+ return false;
569
+}
570
+
571
+static bool code_to_str(int code, struct dstr *str)
572
+{
573
+#define MAP_GLYPH(c, g) \
574
+ case c: \
575
+ dstr_from_wcs(str, (wchar_t[]){g, 0}); \
576
+ return true
577
+#define MAP_STR(c, s) \
578
+ case c: \
579
+ dstr_copy(str, s); \
580
+ return true
581
+ switch (code) {
582
+ MAP_GLYPH(kVK_Return, 0x21A9);
583
+ MAP_GLYPH(kVK_Escape, 0x238B);
584
+ MAP_GLYPH(kVK_Delete, 0x232B);
585
+ MAP_GLYPH(kVK_Tab, 0x21e5);
586
+ MAP_GLYPH(kVK_CapsLock, 0x21EA);
587
+ MAP_GLYPH(kVK_ANSI_KeypadClear, 0x2327);
588
+ MAP_GLYPH(kVK_ANSI_KeypadEnter, 0x2305);
589
+ MAP_GLYPH(kVK_Help, 0x003F);
590
+ MAP_GLYPH(kVK_Home, 0x2196);
591
+ MAP_GLYPH(kVK_PageUp, 0x21de);
592
+ MAP_GLYPH(kVK_ForwardDelete, 0x2326);
593
+ MAP_GLYPH(kVK_End, 0x2198);
594
+ MAP_GLYPH(kVK_PageDown, 0x21df);
595
+
596
+ MAP_GLYPH(kVK_RightArrow, 0x2192);
597
+ MAP_GLYPH(kVK_LeftArrow, 0x2190);
598
+ MAP_GLYPH(kVK_DownArrow, 0x2193);
599
+ MAP_GLYPH(kVK_UpArrow, 0x2191);
600
+
601
+ MAP_STR(kVK_F1, "F1");
602
+ MAP_STR(kVK_F2, "F2");
603
+ MAP_STR(kVK_F3, "F3");
604
+ MAP_STR(kVK_F4, "F4");
605
+ MAP_STR(kVK_F5, "F5");
606
+ MAP_STR(kVK_F6, "F6");
607
+ MAP_STR(kVK_F7, "F7");
608
+ MAP_STR(kVK_F8, "F8");
609
+ MAP_STR(kVK_F9, "F9");
610
+ MAP_STR(kVK_F10, "F10");
611
+ MAP_STR(kVK_F11, "F11");
612
+ MAP_STR(kVK_F12, "F12");
613
+ MAP_STR(kVK_F13, "F13");
614
+ MAP_STR(kVK_F14, "F14");
615
+ MAP_STR(kVK_F15, "F15");
616
+ MAP_STR(kVK_F16, "F16");
617
+ MAP_STR(kVK_F17, "F17");
618
+ MAP_STR(kVK_F18, "F18");
619
+ MAP_STR(kVK_F19, "F19");
620
+ MAP_STR(kVK_F20, "F20");
621
+ MAP_GLYPH(kVK_Control, kControlUnicode);
622
+ MAP_GLYPH(kVK_Shift, kShiftUnicode);
623
+ MAP_GLYPH(kVK_Option, kOptionUnicode);
624
+ MAP_GLYPH(kVK_Command, kCommandUnicode);
625
+ MAP_GLYPH(kVK_RightControl, kControlUnicode);
626
+ MAP_GLYPH(kVK_RightShift, kShiftUnicode);
627
+ MAP_GLYPH(kVK_RightOption, kOptionUnicode);
628
+ }
629
+#undef MAP_STR
630
+#undef MAP_GLYPH
631
+
632
+ return false;
633
+}
634
+
635
+void obs_key_to_str(obs_key_t key, struct dstr *str)
636
+{
637
+ if (localized_key_to_str(key, str))
638
+ return;
639
+
640
+ int code = obs_key_to_virtual_key(key);
641
+ if (code_to_str(code, str))
642
+ return;
643
+
644
+ if (code == INVALID_KEY) {
645
+ blog(LOG_ERROR,
646
+ "hotkey-cocoa: Got invalid key while "
647
+ "translating key '%d' (%s)",
648
+ key, obs_key_to_name(key));
649
+ goto err;
650
+ }
651
+
652
+ struct obs_hotkeys_platform *plat = NULL;
653
+
654
+ if (obs) {
655
+ pthread_mutex_lock(&obs->hotkeys.mutex);
656
+ plat = obs->hotkeys.platform_context;
657
+ hotkeys_retain(plat);
658
+ pthread_mutex_unlock(&obs->hotkeys.mutex);
659
+ }
660
+
661
+ if (!plat) {
662
+ blog(LOG_ERROR,
663
+ "hotkey-cocoa: Could not get hotkey platform "
664
+ "while translating key '%d' (%s)",
665
+ key, obs_key_to_name(key));
666
+ goto err;
667
+ }
668
+
669
+ const UniCharCount max_length = 16;
670
+ UInt32 dead_key_state = 0;
671
+ UniChar buffer[max_length];
672
+ UniCharCount len = 0;
673
+
674
+ OSStatus err =
675
+ UCKeyTranslate(plat->layout, code, kUCKeyActionDown,
676
+ 0x104, //caps lock for upper case letters
677
+ LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit,
678
+ &dead_key_state, max_length, &len, buffer);
679
+
680
+ if (err == noErr && len <= 0 && dead_key_state) {
681
+ err = UCKeyTranslate(plat->layout, kVK_Space, kUCKeyActionDown,
682
+ 0x104, LMGetKbdType(),
683
+ kUCKeyTranslateNoDeadKeysBit,
684
+ &dead_key_state, max_length, &len, buffer);
685
+ }
686
+
687
+ hotkeys_release(plat);
688
+
689
+ if (err != noErr) {
690
+ blog(LOG_ERROR,
691
+ "hotkey-cocoa: Error while translating key '%d'"
692
+ " (0x%x, %s) to string: %d",
693
+ key, code, obs_key_to_name(key), err);
694
+ goto err;
695
+ }
696
+
697
+ if (len == 0) {
698
+ blog(LOG_ERROR,
699
+ "hotkey-cocoa: Got 0 length string while "
700
+ "translating '%d' (0x%x, %s) to string",
701
+ key, code, obs_key_to_name(key));
702
+ goto err;
703
+ }
704
+
705
+ CFStringRef string = CFStringCreateWithCharactersNoCopy(
706
+ NULL, buffer, len, kCFAllocatorNull);
707
+ if (!string) {
708
+ blog(LOG_ERROR,
709
+ "hotkey-cocoa: Could not create CFStringRef "
710
+ "while translating '%d' (0x%x, %s) to string",
711
+ key, code, obs_key_to_name(key));
712
+ goto err;
713
+ }
714
+
715
+ if (!dstr_from_cfstring(str, string)) {
716
+ blog(LOG_ERROR,
717
+ "hotkey-cocoa: Could not translate CFStringRef "
718
+ "to CString while translating '%d' (0x%x, %s)",
719
+ key, code, obs_key_to_name(key));
720
+
721
+ goto release;
722
+ }
723
+
724
+ CFRelease(string);
725
+ return;
726
+
727
+release:
728
+ CFRelease(string);
729
+err:
730
+ dstr_copy(str, obs_key_to_name(key));
731
+}
732
+
733
+#define OBS_COCOA_MODIFIER_SIZE 7
734
+static void unichar_to_utf8(const UniChar *c, char *buff)
735
+{
736
+ CFStringRef string = CFStringCreateWithCharactersNoCopy(
737
+ NULL, c, 2, kCFAllocatorNull);
738
+ if (!string) {
739
+ blog(LOG_ERROR, "hotkey-cocoa: Could not create CFStringRef "
740
+ "while populating modifier strings");
741
+ return;
742
+ }
743
+
744
+ if (!CFStringGetCString(string, buff, OBS_COCOA_MODIFIER_SIZE,
745
+ kCFStringEncodingUTF8))
746
+ blog(LOG_ERROR,
747
+ "hotkey-cocoa: Error while populating "
748
+ " modifier string with glyph %d (0x%x)",
749
+ c[0], c[0]);
750
+
751
+ CFRelease(string);
752
+}
753
+
754
+static char ctrl_str[OBS_COCOA_MODIFIER_SIZE];
755
+static char opt_str[OBS_COCOA_MODIFIER_SIZE];
756
+static char shift_str[OBS_COCOA_MODIFIER_SIZE];
757
+static char cmd_str[OBS_COCOA_MODIFIER_SIZE];
758
+static void init_utf_8_strings(void)
759
+{
760
+ const UniChar ctrl_uni[] = {kControlUnicode, 0};
761
+ const UniChar opt_uni[] = {kOptionUnicode, 0};
762
+ const UniChar shift_uni[] = {kShiftUnicode, 0};
763
+ const UniChar cmd_uni[] = {kCommandUnicode, 0};
764
+
765
+ unichar_to_utf8(ctrl_uni, ctrl_str);
766
+ unichar_to_utf8(opt_uni, opt_str);
767
+ unichar_to_utf8(shift_uni, shift_str);
768
+ unichar_to_utf8(cmd_uni, cmd_str);
769
+}
770
+
771
+static pthread_once_t strings_token = PTHREAD_ONCE_INIT;
772
+void obs_key_combination_to_str(obs_key_combination_t key, struct dstr *str)
773
+{
774
+ struct dstr key_str = {0};
775
+ if (key.key != OBS_KEY_NONE)
776
+ obs_key_to_str(key.key, &key_str);
777
+
778
+ int res = pthread_once(&strings_token, init_utf_8_strings);
779
+ if (res) {
780
+ blog(LOG_ERROR,
781
+ "hotkeys-cocoa: Error while translating "
782
+ "modifiers %d (0x%x)",
783
+ res, res);
784
+ dstr_move(str, &key_str);
785
+ return;
786
+ }
787
+
788
+#define CHECK_MODIFIER(mod, str) ((key.modifiers & mod) ? str : "")
789
+ dstr_printf(str, "%s%s%s%s%s",
790
+ CHECK_MODIFIER(INTERACT_CONTROL_KEY, ctrl_str),
791
+ CHECK_MODIFIER(INTERACT_ALT_KEY, opt_str),
792
+ CHECK_MODIFIER(INTERACT_SHIFT_KEY, shift_str),
793
+ CHECK_MODIFIER(INTERACT_COMMAND_KEY, cmd_str),
794
+ key_str.len ? key_str.array : "");
795
+#undef CHECK_MODIFIER
796
+
797
+ dstr_free(&key_str);
798
+}
799
+
800
+static inline CFDictionaryRef copy_device_mask(UInt32 page, UInt32 usage)
801
+{
802
+ CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
803
+ kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks,
804
+ &kCFTypeDictionaryValueCallBacks);
805
+
806
+ CFNumberRef value;
807
+ // Add the page value.
808
+ value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
809
+ CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), value);
810
+ CFRelease(value);
811
+
812
+ // Add the usage value (which is only valid if page value exists).
813
+ value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
814
+ CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), value);
815
+ CFRelease(value);
816
+
817
+ return dict;
818
+}
819
+
820
+static CFSetRef copy_devices(obs_hotkeys_platform_t *plat, UInt32 page,
821
+ UInt32 usage)
822
+{
823
+ CFDictionaryRef mask = copy_device_mask(page, usage);
824
+ IOHIDManagerSetDeviceMatching(plat->manager, mask);
825
+ CFRelease(mask);
826
+
827
+ CFSetRef devices = IOHIDManagerCopyDevices(plat->manager);
828
+ if (!devices)
829
+ return NULL;
830
+
831
+ if (CFSetGetCount(devices) < 1) {
832
+ CFRelease(devices);
833
+ return NULL;
834
+ }
835
+
836
+ return devices;
837
+}
838
+
839
+static UInt16 usage_to_carbon(UInt32 usage)
840
+{
841
+ switch (usage) {
842
+ case kHIDUsage_KeyboardErrorRollOver:
843
+ return INVALID_KEY;
844
+ case kHIDUsage_KeyboardPOSTFail:
845
+ return INVALID_KEY;
846
+ case kHIDUsage_KeyboardErrorUndefined:
847
+ return INVALID_KEY;
848
+
849
+ case kHIDUsage_KeyboardA:
850
+ return kVK_ANSI_A;
851
+ case kHIDUsage_KeyboardB:
852
+ return kVK_ANSI_B;
853
+ case kHIDUsage_KeyboardC:
854
+ return kVK_ANSI_C;
855
+ case kHIDUsage_KeyboardD:
856
+ return kVK_ANSI_D;
857
+ case kHIDUsage_KeyboardE:
858
+ return kVK_ANSI_E;
859
+ case kHIDUsage_KeyboardF:
860
+ return kVK_ANSI_F;
861
+ case kHIDUsage_KeyboardG:
862
+ return kVK_ANSI_G;
863
+ case kHIDUsage_KeyboardH:
864
+ return kVK_ANSI_H;
865
+ case kHIDUsage_KeyboardI:
866
+ return kVK_ANSI_I;
867
+ case kHIDUsage_KeyboardJ:
868
+ return kVK_ANSI_J;
869
+ case kHIDUsage_KeyboardK:
870
+ return kVK_ANSI_K;
871
+ case kHIDUsage_KeyboardL:
872
+ return kVK_ANSI_L;
873
+ case kHIDUsage_KeyboardM:
874
+ return kVK_ANSI_M;
875
+ case kHIDUsage_KeyboardN:
876
+ return kVK_ANSI_N;
877
+ case kHIDUsage_KeyboardO:
878
+ return kVK_ANSI_O;
879
+ case kHIDUsage_KeyboardP:
880
+ return kVK_ANSI_P;
881
+ case kHIDUsage_KeyboardQ:
882
+ return kVK_ANSI_Q;
883
+ case kHIDUsage_KeyboardR:
884
+ return kVK_ANSI_R;
885
+ case kHIDUsage_KeyboardS:
886
+ return kVK_ANSI_S;
887
+ case kHIDUsage_KeyboardT:
888
+ return kVK_ANSI_T;
889
+ case kHIDUsage_KeyboardU:
890
+ return kVK_ANSI_U;
891
+ case kHIDUsage_KeyboardV:
892
+ return kVK_ANSI_V;
893
+ case kHIDUsage_KeyboardW:
894
+ return kVK_ANSI_W;
895
+ case kHIDUsage_KeyboardX:
896
+ return kVK_ANSI_X;
897
+ case kHIDUsage_KeyboardY:
898
+ return kVK_ANSI_Y;
899
+ case kHIDUsage_KeyboardZ:
900
+ return kVK_ANSI_Z;
901
+
902
+ case kHIDUsage_Keyboard1:
903
+ return kVK_ANSI_1;
904
+ case kHIDUsage_Keyboard2:
905
+ return kVK_ANSI_2;
906
+ case kHIDUsage_Keyboard3:
907
+ return kVK_ANSI_3;
908
+ case kHIDUsage_Keyboard4:
909
+ return kVK_ANSI_4;
910
+ case kHIDUsage_Keyboard5:
911
+ return kVK_ANSI_5;
912
+ case kHIDUsage_Keyboard6:
913
+ return kVK_ANSI_6;
914
+ case kHIDUsage_Keyboard7:
915
+ return kVK_ANSI_7;
916
+ case kHIDUsage_Keyboard8:
917
+ return kVK_ANSI_8;
918
+ case kHIDUsage_Keyboard9:
919
+ return kVK_ANSI_9;
920
+ case kHIDUsage_Keyboard0:
921
+ return kVK_ANSI_0;
922
+
923
+ case kHIDUsage_KeyboardReturnOrEnter:
924
+ return kVK_Return;
925
+ case kHIDUsage_KeyboardEscape:
926
+ return kVK_Escape;
927
+ case kHIDUsage_KeyboardDeleteOrBackspace:
928
+ return kVK_Delete;
929
+ case kHIDUsage_KeyboardTab:
930
+ return kVK_Tab;
931
+ case kHIDUsage_KeyboardSpacebar:
932
+ return kVK_Space;
933
+ case kHIDUsage_KeyboardHyphen:
934
+ return kVK_ANSI_Minus;
935
+ case kHIDUsage_KeyboardEqualSign:
936
+ return kVK_ANSI_Equal;
937
+ case kHIDUsage_KeyboardOpenBracket:
938
+ return kVK_ANSI_LeftBracket;
939
+ case kHIDUsage_KeyboardCloseBracket:
940
+ return kVK_ANSI_RightBracket;
941
+ case kHIDUsage_KeyboardBackslash:
942
+ return kVK_ANSI_Backslash;
943
+ case kHIDUsage_KeyboardNonUSPound:
944
+ return INVALID_KEY;
945
+ case kHIDUsage_KeyboardSemicolon:
946
+ return kVK_ANSI_Semicolon;
947
+ case kHIDUsage_KeyboardQuote:
948
+ return kVK_ANSI_Quote;
949
+ case kHIDUsage_KeyboardGraveAccentAndTilde:
950
+ return kVK_ANSI_Grave;
951
+ case kHIDUsage_KeyboardComma:
952
+ return kVK_ANSI_Comma;
953
+ case kHIDUsage_KeyboardPeriod:
954
+ return kVK_ANSI_Period;
955
+ case kHIDUsage_KeyboardSlash:
956
+ return kVK_ANSI_Slash;
957
+ case kHIDUsage_KeyboardCapsLock:
958
+ return kVK_CapsLock;
959
+
960
+ case kHIDUsage_KeyboardF1:
961
+ return kVK_F1;
962
+ case kHIDUsage_KeyboardF2:
963
+ return kVK_F2;
964
+ case kHIDUsage_KeyboardF3:
965
+ return kVK_F3;
966
+ case kHIDUsage_KeyboardF4:
967
+ return kVK_F4;
968
+ case kHIDUsage_KeyboardF5:
969
+ return kVK_F5;
970
+ case kHIDUsage_KeyboardF6:
971
+ return kVK_F6;
972
+ case kHIDUsage_KeyboardF7:
973
+ return kVK_F7;
974
+ case kHIDUsage_KeyboardF8:
975
+ return kVK_F8;
976
+ case kHIDUsage_KeyboardF9:
977
+ return kVK_F9;
978
+ case kHIDUsage_KeyboardF10:
979
+ return kVK_F10;
980
+ case kHIDUsage_KeyboardF11:
981
+ return kVK_F11;
982
+ case kHIDUsage_KeyboardF12:
983
+ return kVK_F12;
984
+
985
+ case kHIDUsage_KeyboardPrintScreen:
986
+ return INVALID_KEY;
987
+ case kHIDUsage_KeyboardScrollLock:
988
+ return INVALID_KEY;
989
+ case kHIDUsage_KeyboardPause:
990
+ return INVALID_KEY;
991
+ case kHIDUsage_KeyboardInsert:
992
+ return kVK_Help;
993
+ case kHIDUsage_KeyboardHome:
994
+ return kVK_Home;
995
+ case kHIDUsage_KeyboardPageUp:
996
+ return kVK_PageUp;
997
+ case kHIDUsage_KeyboardDeleteForward:
998
+ return kVK_ForwardDelete;
999
+ case kHIDUsage_KeyboardEnd:
1000
+ return kVK_End;
1001
+ case kHIDUsage_KeyboardPageDown:
1002
+ return kVK_PageDown;
1003
+
1004
+ case kHIDUsage_KeyboardRightArrow:
1005
+ return kVK_RightArrow;
1006
+ case kHIDUsage_KeyboardLeftArrow:
1007
+ return kVK_LeftArrow;
1008
+ case kHIDUsage_KeyboardDownArrow:
1009
+ return kVK_DownArrow;
1010
+ case kHIDUsage_KeyboardUpArrow:
1011
+ return kVK_UpArrow;
1012
+
1013
+ case kHIDUsage_KeypadNumLock:
1014
+ return kVK_ANSI_KeypadClear;
1015
+ case kHIDUsage_KeypadSlash:
1016
+ return kVK_ANSI_KeypadDivide;
1017
+ case kHIDUsage_KeypadAsterisk:
1018
+ return kVK_ANSI_KeypadMultiply;
1019
+ case kHIDUsage_KeypadHyphen:
1020
+ return kVK_ANSI_KeypadMinus;
1021
+ case kHIDUsage_KeypadPlus:
1022
+ return kVK_ANSI_KeypadPlus;
1023
+ case kHIDUsage_KeypadEnter:
1024
+ return kVK_ANSI_KeypadEnter;
1025
+
1026
+ case kHIDUsage_Keypad1:
1027
+ return kVK_ANSI_Keypad1;
1028
+ case kHIDUsage_Keypad2:
1029
+ return kVK_ANSI_Keypad2;
1030
+ case kHIDUsage_Keypad3:
1031
+ return kVK_ANSI_Keypad3;
1032
+ case kHIDUsage_Keypad4:
1033
+ return kVK_ANSI_Keypad4;
1034
+ case kHIDUsage_Keypad5:
1035
+ return kVK_ANSI_Keypad5;
1036
+ case kHIDUsage_Keypad6:
1037
+ return kVK_ANSI_Keypad6;
1038
+ case kHIDUsage_Keypad7:
1039
+ return kVK_ANSI_Keypad7;
1040
+ case kHIDUsage_Keypad8:
1041
+ return kVK_ANSI_Keypad8;
1042
+ case kHIDUsage_Keypad9:
1043
+ return kVK_ANSI_Keypad9;
1044
+ case kHIDUsage_Keypad0:
1045
+ return kVK_ANSI_Keypad0;
1046
+
1047
+ case kHIDUsage_KeypadPeriod:
1048
+ return kVK_ANSI_KeypadDecimal;
1049
+ case kHIDUsage_KeyboardNonUSBackslash:
1050
+ return INVALID_KEY;
1051
+ case kHIDUsage_KeyboardApplication:
1052
+ return kVK_F13;
1053
+ case kHIDUsage_KeyboardPower:
1054
+ return INVALID_KEY;
1055
+ case kHIDUsage_KeypadEqualSign:
1056
+ return kVK_ANSI_KeypadEquals;
1057
+
1058
+ case kHIDUsage_KeyboardF13:
1059
+ return kVK_F13;
1060
+ case kHIDUsage_KeyboardF14:
1061
+ return kVK_F14;
1062
+ case kHIDUsage_KeyboardF15:
1063
+ return kVK_F15;
1064
+ case kHIDUsage_KeyboardF16:
1065
+ return kVK_F16;
1066
+ case kHIDUsage_KeyboardF17:
1067
+ return kVK_F17;
1068
+ case kHIDUsage_KeyboardF18:
1069
+ return kVK_F18;
1070
+ case kHIDUsage_KeyboardF19:
1071
+ return kVK_F19;
1072
+ case kHIDUsage_KeyboardF20:
1073
+ return kVK_F20;
1074
+ case kHIDUsage_KeyboardF21:
1075
+ return INVALID_KEY;
1076
+ case kHIDUsage_KeyboardF22:
1077
+ return INVALID_KEY;
1078
+ case kHIDUsage_KeyboardF23:
1079
+ return INVALID_KEY;
1080
+ case kHIDUsage_KeyboardF24:
1081
+ return INVALID_KEY;
1082
+
1083
+ case kHIDUsage_KeyboardExecute:
1084
+ return INVALID_KEY;
1085
+ case kHIDUsage_KeyboardHelp:
1086
+ return INVALID_KEY;
1087
+ case kHIDUsage_KeyboardMenu:
1088
+ return 0x7F;
1089
+ case kHIDUsage_KeyboardSelect:
1090
+ return kVK_ANSI_KeypadEnter;
1091
+ case kHIDUsage_KeyboardStop:
1092
+ return INVALID_KEY;
1093
+ case kHIDUsage_KeyboardAgain:
1094
+ return INVALID_KEY;
1095
+ case kHIDUsage_KeyboardUndo:
1096
+ return INVALID_KEY;
1097
+ case kHIDUsage_KeyboardCut:
1098
+ return INVALID_KEY;
1099
+ case kHIDUsage_KeyboardCopy:
1100
+ return INVALID_KEY;
1101
+ case kHIDUsage_KeyboardPaste:
1102
+ return INVALID_KEY;
1103
+ case kHIDUsage_KeyboardFind:
1104
+ return INVALID_KEY;
1105
+
1106
+ case kHIDUsage_KeyboardMute:
1107
+ return kVK_Mute;
1108
+ case kHIDUsage_KeyboardVolumeUp:
1109
+ return kVK_VolumeUp;
1110
+ case kHIDUsage_KeyboardVolumeDown:
1111
+ return kVK_VolumeDown;
1112
+
1113
+ case kHIDUsage_KeyboardLockingCapsLock:
1114
+ return INVALID_KEY;
1115
+ case kHIDUsage_KeyboardLockingNumLock:
1116
+ return INVALID_KEY;
1117
+ case kHIDUsage_KeyboardLockingScrollLock:
1118
+ return INVALID_KEY;
1119
+
1120
+ case kHIDUsage_KeypadComma:
1121
+ return INVALID_KEY;
1122
+ case kHIDUsage_KeypadEqualSignAS400:
1123
+ return INVALID_KEY;
1124
+ case kHIDUsage_KeyboardInternational1:
1125
+ return INVALID_KEY;
1126
+ case kHIDUsage_KeyboardInternational2:
1127
+ return INVALID_KEY;
1128
+ case kHIDUsage_KeyboardInternational3:
1129
+ return INVALID_KEY;
1130
+ case kHIDUsage_KeyboardInternational4:
1131
+ return INVALID_KEY;
1132
+ case kHIDUsage_KeyboardInternational5:
1133
+ return INVALID_KEY;
1134
+ case kHIDUsage_KeyboardInternational6:
1135
+ return INVALID_KEY;
1136
+ case kHIDUsage_KeyboardInternational7:
1137
+ return INVALID_KEY;
1138
+ case kHIDUsage_KeyboardInternational8:
1139
+ return INVALID_KEY;
1140
+ case kHIDUsage_KeyboardInternational9:
1141
+ return INVALID_KEY;
1142
+
1143
+ case kHIDUsage_KeyboardLANG1:
1144
+ return INVALID_KEY;
1145
+ case kHIDUsage_KeyboardLANG2:
1146
+ return INVALID_KEY;
1147
+ case kHIDUsage_KeyboardLANG3:
1148
+ return INVALID_KEY;
1149
+ case kHIDUsage_KeyboardLANG4:
1150
+ return INVALID_KEY;
1151
+ case kHIDUsage_KeyboardLANG5:
1152
+ return INVALID_KEY;
1153
+ case kHIDUsage_KeyboardLANG6:
1154
+ return INVALID_KEY;
1155
+ case kHIDUsage_KeyboardLANG7:
1156
+ return INVALID_KEY;
1157
+ case kHIDUsage_KeyboardLANG8:
1158
+ return INVALID_KEY;
1159
+ case kHIDUsage_KeyboardLANG9:
1160
+ return INVALID_KEY;
1161
+
1162
+ case kHIDUsage_KeyboardAlternateErase:
1163
+ return INVALID_KEY;
1164
+ case kHIDUsage_KeyboardSysReqOrAttention:
1165
+ return INVALID_KEY;
1166
+ case kHIDUsage_KeyboardCancel:
1167
+ return INVALID_KEY;
1168
+ case kHIDUsage_KeyboardClear:
1169
+ return INVALID_KEY;
1170
+ case kHIDUsage_KeyboardPrior:
1171
+ return INVALID_KEY;
1172
+ case kHIDUsage_KeyboardReturn:
1173
+ return INVALID_KEY;
1174
+ case kHIDUsage_KeyboardSeparator:
1175
+ return INVALID_KEY;
1176
+ case kHIDUsage_KeyboardOut:
1177
+ return INVALID_KEY;
1178
+ case kHIDUsage_KeyboardOper:
1179
+ return INVALID_KEY;
1180
+ case kHIDUsage_KeyboardClearOrAgain:
1181
+ return INVALID_KEY;
1182
+ case kHIDUsage_KeyboardCrSelOrProps:
1183
+ return INVALID_KEY;
1184
+ case kHIDUsage_KeyboardExSel:
1185
+ return INVALID_KEY;
1186
+
1187
+ /* 0xa5-0xdf Reserved */
1188
+
1189
+ case kHIDUsage_KeyboardLeftControl:
1190
+ return kVK_Control;
1191
+ case kHIDUsage_KeyboardLeftShift:
1192
+ return kVK_Shift;
1193
+ case kHIDUsage_KeyboardLeftAlt:
1194
+ return kVK_Option;
1195
+ case kHIDUsage_KeyboardLeftGUI:
1196
+ return kVK_Command;
1197
+ case kHIDUsage_KeyboardRightControl:
1198
+ return kVK_RightControl;
1199
+ case kHIDUsage_KeyboardRightShift:
1200
+ return kVK_RightShift;
1201
+ case kHIDUsage_KeyboardRightAlt:
1202
+ return kVK_RightOption;
1203
+ case kHIDUsage_KeyboardRightGUI:
1204
+ return 0x36; //??
1205
+
1206
+ /* 0xe8-0xffff Reserved */
1207
+
1208
+ case kHIDUsage_Keyboard_Reserved:
1209
+ return INVALID_KEY;
1210
+ default:
1211
+ return INVALID_KEY;
1212
+ }
1213
+ return INVALID_KEY;
1214
+}
1215
+
1216
+obs_key_t obs_key_from_virtual_key(int code)
1217
+{
1218
+ switch (code) {
1219
+ case kVK_ANSI_A:
1220
+ return OBS_KEY_A;
1221
+ case kVK_ANSI_B:
1222
+ return OBS_KEY_B;
1223
+ case kVK_ANSI_C:
1224
+ return OBS_KEY_C;
1225
+ case kVK_ANSI_D:
1226
+ return OBS_KEY_D;
1227
+ case kVK_ANSI_E:
1228
+ return OBS_KEY_E;
1229
+ case kVK_ANSI_F:
1230
+ return OBS_KEY_F;
1231
+ case kVK_ANSI_G:
1232
+ return OBS_KEY_G;
1233
+ case kVK_ANSI_H:
1234
+ return OBS_KEY_H;
1235
+ case kVK_ANSI_I:
1236
+ return OBS_KEY_I;
1237
+ case kVK_ANSI_J:
1238
+ return OBS_KEY_J;
1239
+ case kVK_ANSI_K:
1240
+ return OBS_KEY_K;
1241
+ case kVK_ANSI_L:
1242
+ return OBS_KEY_L;
1243
+ case kVK_ANSI_M:
1244
+ return OBS_KEY_M;
1245
+ case kVK_ANSI_N:
1246
+ return OBS_KEY_N;
1247
+ case kVK_ANSI_O:
1248
+ return OBS_KEY_O;
1249
+ case kVK_ANSI_P:
1250
+ return OBS_KEY_P;
1251
+ case kVK_ANSI_Q:
1252
+ return OBS_KEY_Q;
1253
+ case kVK_ANSI_R:
1254
+ return OBS_KEY_R;
1255
+ case kVK_ANSI_S:
1256
+ return OBS_KEY_S;
1257
+ case kVK_ANSI_T:
1258
+ return OBS_KEY_T;
1259
+ case kVK_ANSI_U:
1260
+ return OBS_KEY_U;
1261
+ case kVK_ANSI_V:
1262
+ return OBS_KEY_V;
1263
+ case kVK_ANSI_W:
1264
+ return OBS_KEY_W;
1265
+ case kVK_ANSI_X:
1266
+ return OBS_KEY_X;
1267
+ case kVK_ANSI_Y:
1268
+ return OBS_KEY_Y;
1269
+ case kVK_ANSI_Z:
1270
+ return OBS_KEY_Z;
1271
+
1272
+ case kVK_ANSI_1:
1273
+ return OBS_KEY_1;
1274
+ case kVK_ANSI_2:
1275
+ return OBS_KEY_2;
1276
+ case kVK_ANSI_3:
1277
+ return OBS_KEY_3;
1278
+ case kVK_ANSI_4:
1279
+ return OBS_KEY_4;
1280
+ case kVK_ANSI_5:
1281
+ return OBS_KEY_5;
1282
+ case kVK_ANSI_6:
1283
+ return OBS_KEY_6;
1284
+ case kVK_ANSI_7:
1285
+ return OBS_KEY_7;
1286
+ case kVK_ANSI_8:
1287
+ return OBS_KEY_8;
1288
+ case kVK_ANSI_9:
1289
+ return OBS_KEY_9;
1290
+ case kVK_ANSI_0:
1291
+ return OBS_KEY_0;
1292
+
1293
+ case kVK_Return:
1294
+ return OBS_KEY_RETURN;
1295
+ case kVK_Escape:
1296
+ return OBS_KEY_ESCAPE;
1297
+ case kVK_Delete:
1298
+ return OBS_KEY_BACKSPACE;
1299
+ case kVK_Tab:
1300
+ return OBS_KEY_TAB;
1301
+ case kVK_Space:
1302
+ return OBS_KEY_SPACE;
1303
+ case kVK_ANSI_Minus:
1304
+ return OBS_KEY_MINUS;
1305
+ case kVK_ANSI_Equal:
1306
+ return OBS_KEY_EQUAL;
1307
+ case kVK_ANSI_LeftBracket:
1308
+ return OBS_KEY_BRACKETLEFT;
1309
+ case kVK_ANSI_RightBracket:
1310
+ return OBS_KEY_BRACKETRIGHT;
1311
+ case kVK_ANSI_Backslash:
1312
+ return OBS_KEY_BACKSLASH;
1313
+ case kVK_ANSI_Semicolon:
1314
+ return OBS_KEY_SEMICOLON;
1315
+ case kVK_ANSI_Quote:
1316
+ return OBS_KEY_QUOTE;
1317
+ case kVK_ANSI_Grave:
1318
+ return OBS_KEY_DEAD_GRAVE;
1319
+ case kVK_ANSI_Comma:
1320
+ return OBS_KEY_COMMA;
1321
+ case kVK_ANSI_Period:
1322
+ return OBS_KEY_PERIOD;
1323
+ case kVK_ANSI_Slash:
1324
+ return OBS_KEY_SLASH;
1325
+ case kVK_CapsLock:
1326
+ return OBS_KEY_CAPSLOCK;
1327
+ case kVK_ISO_Section:
1328
+ return OBS_KEY_SECTION;
1329
+
1330
+ case kVK_F1:
1331
+ return OBS_KEY_F1;
1332
+ case kVK_F2:
1333
+ return OBS_KEY_F2;
1334
+ case kVK_F3:
1335
+ return OBS_KEY_F3;
1336
+ case kVK_F4:
1337
+ return OBS_KEY_F4;
1338
+ case kVK_F5:
1339
+ return OBS_KEY_F5;
1340
+ case kVK_F6:
1341
+ return OBS_KEY_F6;
1342
+ case kVK_F7:
1343
+ return OBS_KEY_F7;
1344
+ case kVK_F8:
1345
+ return OBS_KEY_F8;
1346
+ case kVK_F9:
1347
+ return OBS_KEY_F9;
1348
+ case kVK_F10:
1349
+ return OBS_KEY_F10;
1350
+ case kVK_F11:
1351
+ return OBS_KEY_F11;
1352
+ case kVK_F12:
1353
+ return OBS_KEY_F12;
1354
+
1355
+ case kVK_Help:
1356
+ return OBS_KEY_HELP;
1357
+ case kVK_Home:
1358
+ return OBS_KEY_HOME;
1359
+ case kVK_PageUp:
1360
+ return OBS_KEY_PAGEUP;
1361
+ case kVK_ForwardDelete:
1362
+ return OBS_KEY_DELETE;
1363
+ case kVK_End:
1364
+ return OBS_KEY_END;
1365
+ case kVK_PageDown:
1366
+ return OBS_KEY_PAGEDOWN;
1367
+
1368
+ case kVK_RightArrow:
1369
+ return OBS_KEY_RIGHT;
1370
+ case kVK_LeftArrow:
1371
+ return OBS_KEY_LEFT;
1372
+ case kVK_DownArrow:
1373
+ return OBS_KEY_DOWN;
1374
+ case kVK_UpArrow:
1375
+ return OBS_KEY_UP;
1376
+
1377
+ case kVK_ANSI_KeypadClear:
1378
+ return OBS_KEY_CLEAR;
1379
+ case kVK_ANSI_KeypadDivide:
1380
+ return OBS_KEY_NUMSLASH;
1381
+ case kVK_ANSI_KeypadMultiply:
1382
+ return OBS_KEY_NUMASTERISK;
1383
+ case kVK_ANSI_KeypadMinus:
1384
+ return OBS_KEY_NUMMINUS;
1385
+ case kVK_ANSI_KeypadPlus:
1386
+ return OBS_KEY_NUMPLUS;
1387
+ case kVK_ANSI_KeypadEnter:
1388
+ return OBS_KEY_ENTER;
1389
+
1390
+ case kVK_ANSI_Keypad1:
1391
+ return OBS_KEY_NUM1;
1392
+ case kVK_ANSI_Keypad2:
1393
+ return OBS_KEY_NUM2;
1394
+ case kVK_ANSI_Keypad3:
1395
+ return OBS_KEY_NUM3;
1396
+ case kVK_ANSI_Keypad4:
1397
+ return OBS_KEY_NUM4;
1398
+ case kVK_ANSI_Keypad5:
1399
+ return OBS_KEY_NUM5;
1400
+ case kVK_ANSI_Keypad6:
1401
+ return OBS_KEY_NUM6;
1402
+ case kVK_ANSI_Keypad7:
1403
+ return OBS_KEY_NUM7;
1404
+ case kVK_ANSI_Keypad8:
1405
+ return OBS_KEY_NUM8;
1406
+ case kVK_ANSI_Keypad9:
1407
+ return OBS_KEY_NUM9;
1408
+ case kVK_ANSI_Keypad0:
1409
+ return OBS_KEY_NUM0;
1410
+
1411
+ case kVK_ANSI_KeypadDecimal:
1412
+ return OBS_KEY_NUMPERIOD;
1413
+ case kVK_ANSI_KeypadEquals:
1414
+ return OBS_KEY_NUMEQUAL;
1415
+
1416
+ case kVK_F13:
1417
+ return OBS_KEY_F13;
1418
+ case kVK_F14:
1419
+ return OBS_KEY_F14;
1420
+ case kVK_F15:
1421
+ return OBS_KEY_F15;
1422
+ case kVK_F16:
1423
+ return OBS_KEY_F16;
1424
+ case kVK_F17:
1425
+ return OBS_KEY_F17;
1426
+ case kVK_F18:
1427
+ return OBS_KEY_F18;
1428
+ case kVK_F19:
1429
+ return OBS_KEY_F19;
1430
+ case kVK_F20:
1431
+ return OBS_KEY_F20;
1432
+
1433
+ case kVK_Control:
1434
+ return OBS_KEY_CONTROL;
1435
+ case kVK_Shift:
1436
+ return OBS_KEY_SHIFT;
1437
+ case kVK_Option:
1438
+ return OBS_KEY_ALT;
1439
+ case kVK_Command:
1440
+ return OBS_KEY_META;
1441
+ case kVK_RightControl:
1442
+ return OBS_KEY_CONTROL;
1443
+ case kVK_RightShift:
1444
+ return OBS_KEY_SHIFT;
1445
+ case kVK_RightOption:
1446
+ return OBS_KEY_ALT;
1447
+ case 0x36:
1448
+ return OBS_KEY_META;
1449
+
1450
+ case kVK_Function:
1451
+ case kVK_Mute:
1452
+ case kVK_VolumeDown:
1453
+ case kVK_VolumeUp:
1454
+ break;
1455
+ }
1456
+ return OBS_KEY_NONE;
1457
+}
1458
+
1459
+static inline void load_key(obs_hotkeys_platform_t *plat, IOHIDElementRef key)
1460
+{
1461
+ UInt32 usage_code = IOHIDElementGetUsage(key);
1462
+ UInt16 carbon_code = usage_to_carbon(usage_code);
1463
+
1464
+ if (carbon_code == INVALID_KEY)
1465
+ return;
1466
+
1467
+ obs_key_t obs_key = obs_key_from_virtual_key(carbon_code);
1468
+ if (obs_key == OBS_KEY_NONE)
1469
+ return;
1470
+
1471
+ da_push_back(plat->keys[obs_key], &key);
1472
+ CFRetain(*(IOHIDElementRef *)da_end(plat->keys[obs_key]));
1473
+}
1474
+
1475
+static inline void load_keyboard(obs_hotkeys_platform_t *plat,
1476
+ IOHIDDeviceRef keyboard)
1477
+{
1478
+ CFArrayRef keys = IOHIDDeviceCopyMatchingElements(
1479
+ keyboard, NULL, kIOHIDOptionsTypeNone);
1480
+
1481
+ if (!keys) {
1482
+ blog(LOG_ERROR, "hotkeys-cocoa: Getting keyboard keys failed");
1483
+ return;
1484
+ }
1485
+
1486
+ CFIndex count = CFArrayGetCount(keys);
1487
+ if (!count) {
1488
+ blog(LOG_ERROR, "hotkeys-cocoa: Keyboard has no keys");
1489
+ CFRelease(keys);
1490
+ return;
1491
+ }
1492
+
1493
+ for (CFIndex i = 0; i < count; i++) {
1494
+ IOHIDElementRef key =
1495
+ (IOHIDElementRef)CFArrayGetValueAtIndex(keys, i);
1496
+
1497
+ // Skip non-matching keys elements
1498
+ if (IOHIDElementGetUsagePage(key) != kHIDPage_KeyboardOrKeypad)
1499
+ continue;
1500
+
1501
+ load_key(plat, key);
1502
+ }
1503
+
1504
+ CFRelease(keys);
1505
+}
1506
+
1507
+static bool init_keyboard(obs_hotkeys_platform_t *plat)
1508
+{
1509
+ CFSetRef keyboards = copy_devices(plat, kHIDPage_GenericDesktop,
1510
+ kHIDUsage_GD_Keyboard);
1511
+ if (!keyboards)
1512
+ return false;
1513
+
1514
+ CFIndex count = CFSetGetCount(keyboards);
1515
+
1516
+ CFTypeRef devices[count];
1517
+ CFSetGetValues(keyboards, devices);
1518
+
1519
+ for (CFIndex i = 0; i < count; i++)
1520
+ load_keyboard(plat, (IOHIDDeviceRef)devices[i]);
1521
+
1522
+ CFRelease(keyboards);
1523
+ return true;
1524
+}
1525
+
1526
+static inline void free_hotkeys_platform(obs_hotkeys_platform_t *plat)
1527
+{
1528
+ if (!plat)
1529
+ return;
1530
+
1531
+ if (plat->tis) {
1532
+ CFRelease(plat->tis);
1533
+ plat->tis = NULL;
1534
+ }
1535
+
1536
+ if (plat->layout_data) {
1537
+ CFRelease(plat->layout_data);
1538
+ plat->layout_data = NULL;
1539
+ }
1540
+
1541
+ if (plat->manager) {
1542
+ CFRelease(plat->manager);
1543
+ plat->manager = NULL;
1544
+ }
1545
+
1546
+ for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++) {
1547
+ for (size_t j = 0; j < plat->keys[i].num; j++)
1548
+ CFRelease(plat->keys[i].array[j]);
1549
+
1550
+ da_free(plat->keys[i]);
1551
+ }
1552
+
1553
+ bfree(plat);
1554
+}
1555
+
1556
+static bool log_layout_name(TISInputSourceRef tis)
1557
+{
1558
+ struct dstr layout_name = {0};
1559
+ CFStringRef sid = (CFStringRef)TISGetInputSourceProperty(
1560
+ tis, kTISPropertyInputSourceID);
1561
+ if (!sid) {
1562
+ blog(LOG_ERROR, "hotkeys-cocoa: Failed getting InputSourceID");
1563
+ return false;
1564
+ }
1565
+
1566
+ if (!dstr_from_cfstring(&layout_name, sid)) {
1567
+ blog(LOG_ERROR, "hotkeys-cocoa: Could not convert InputSourceID"
1568
+ " to CString");
1569
+ goto fail;
1570
+ }
1571
+
1572
+ blog(LOG_INFO, "hotkeys-cocoa: Using layout '%s'", layout_name.array);
1573
+
1574
+ dstr_free(&layout_name);
1575
+ return true;
1576
+
1577
+fail:
1578
+ dstr_free(&layout_name);
1579
+ return false;
1580
+}
1581
+
1582
+static bool init_hotkeys_platform(obs_hotkeys_platform_t **plat_)
1583
+{
1584
+ if (!plat_)
1585
+ return false;
1586
+
1587
+ *plat_ = bzalloc(sizeof(obs_hotkeys_platform_t));
1588
+ obs_hotkeys_platform_t *plat = *plat_;
1589
+ if (!plat) {
1590
+ *plat_ = NULL;
1591
+ return false;
1592
+ }
1593
+
1594
+ plat->tis = TISCopyCurrentKeyboardLayoutInputSource();
1595
+ plat->layout_data = (CFDataRef)TISGetInputSourceProperty(
1596
+ plat->tis, kTISPropertyUnicodeKeyLayoutData);
1597
+
1598
+ if (!plat->layout_data) {
1599
+ blog(LOG_ERROR, "hotkeys-cocoa: Failed getting LayoutData");
1600
+ goto fail;
1601
+ }
1602
+
1603
+ CFRetain(plat->layout_data);
1604
+ plat->layout = (UCKeyboardLayout *)CFDataGetBytePtr(plat->layout_data);
1605
+
1606
+ plat->manager =
1607
+ IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
1608
+
1609
+ IOReturn openStatus =
1610
+ IOHIDManagerOpen(plat->manager, kIOHIDOptionsTypeNone);
1611
+ if (openStatus != kIOReturnSuccess) {
1612
+ blog(LOG_ERROR, "hotkeys-cocoa: Failed opening HIDManager");
1613
+ goto fail;
1614
+ }
1615
+
1616
+ init_keyboard(plat);
1617
+
1618
+ return true;
1619
+
1620
+fail:
1621
+ hotkeys_release(plat);
1622
+ *plat_ = NULL;
1623
+ return false;
1624
+}
1625
+
1626
+static void input_method_changed(CFNotificationCenterRef nc, void *observer,
1627
+ CFStringRef name, const void *object,
1628
+ CFDictionaryRef user_info)
1629
+{
1630
+ UNUSED_PARAMETER(nc);
1631
+ UNUSED_PARAMETER(name);
1632
+ UNUSED_PARAMETER(object);
1633
+ UNUSED_PARAMETER(user_info);
1634
+
1635
+ struct obs_core_hotkeys *hotkeys = observer;
1636
+ obs_hotkeys_platform_t *new_plat;
1637
+
1638
+ if (init_hotkeys_platform(&new_plat)) {
1639
+ obs_hotkeys_platform_t *plat;
1640
+
1641
+ pthread_mutex_lock(&hotkeys->mutex);
1642
+ plat = hotkeys->platform_context;
1643
+
1644
+ if (new_plat && plat &&
1645
+ new_plat->layout_data == plat->layout_data) {
1646
+ pthread_mutex_unlock(&hotkeys->mutex);
1647
+ hotkeys_release(new_plat);
1648
+ return;
1649
+ }
1650
+
1651
+ hotkeys->platform_context = new_plat;
1652
+ if (new_plat)
1653
+ log_layout_name(new_plat->tis);
1654
+ pthread_mutex_unlock(&hotkeys->mutex);
1655
+
1656
+ calldata_t params = {0};
1657
+ signal_handler_signal(hotkeys->signals, "hotkey_layout_change",
1658
+ ¶ms);
1659
+ if (plat)
1660
+ hotkeys_release(plat);
1661
+ }
1662
+}
1663
+
1664
+bool obs_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys)
1665
+{
1666
+ CFNotificationCenterAddObserver(
1667
+ CFNotificationCenterGetDistributedCenter(), hotkeys,
1668
+ input_method_changed,
1669
+ kTISNotifySelectedKeyboardInputSourceChanged, NULL,
1670
+ CFNotificationSuspensionBehaviorDeliverImmediately);
1671
+
1672
+ input_method_changed(NULL, hotkeys, NULL, NULL, NULL);
1673
+ return hotkeys->platform_context != NULL;
1674
+}
1675
+
1676
+void obs_hotkeys_platform_free(struct obs_core_hotkeys *hotkeys)
1677
+{
1678
+ CFNotificationCenterRemoveEveryObserver(
1679
+ CFNotificationCenterGetDistributedCenter(), hotkeys);
1680
+
1681
+ hotkeys_release(hotkeys->platform_context);
1682
+}
1683
+
1684
+typedef unsigned long NSUInteger;
1685
+static bool mouse_button_pressed(obs_key_t key, bool *pressed)
1686
+{
1687
+ int button = 0;
1688
+ switch (key) {
1689
+#define MAP_BUTTON(n) \
1690
+ case OBS_KEY_MOUSE##n: \
1691
+ button = n - 1; \
1692
+ break
1693
+ MAP_BUTTON(1);
1694
+ MAP_BUTTON(2);
1695
+ MAP_BUTTON(3);
1696
+ MAP_BUTTON(4);
1697
+ MAP_BUTTON(5);
1698
+ MAP_BUTTON(6);
1699
+ MAP_BUTTON(7);
1700
+ MAP_BUTTON(8);
1701
+ MAP_BUTTON(9);
1702
+ MAP_BUTTON(10);
1703
+ MAP_BUTTON(11);
1704
+ MAP_BUTTON(12);
1705
+ MAP_BUTTON(13);
1706
+ MAP_BUTTON(14);
1707
+ MAP_BUTTON(15);
1708
+ MAP_BUTTON(16);
1709
+ MAP_BUTTON(17);
1710
+ MAP_BUTTON(18);
1711
+ MAP_BUTTON(19);
1712
+ MAP_BUTTON(20);
1713
+ MAP_BUTTON(21);
1714
+ MAP_BUTTON(22);
1715
+ MAP_BUTTON(23);
1716
+ MAP_BUTTON(24);
1717
+ MAP_BUTTON(25);
1718
+ MAP_BUTTON(26);
1719
+ MAP_BUTTON(27);
1720
+ MAP_BUTTON(28);
1721
+ MAP_BUTTON(29);
1722
+ break;
1723
+#undef MAP_BUTTON
1724
+
1725
+ default:
1726
+ return false;
1727
+ }
1728
+
1729
+ Class NSEvent = objc_getClass("NSEvent");
1730
+ SEL pressedMouseButtonsSel = sel_registerName("pressedMouseButtons");
1731
+ typedef int (*func)(id, SEL);
1732
+ func pressedMouseButtons = (func)objc_msgSend;
1733
+ NSUInteger buttons = (NSUInteger)pressedMouseButtons(
1734
+ (id)NSEvent, pressedMouseButtonsSel);
1735
+
1736
+ *pressed = (buttons & (1 << button)) != 0;
1737
+ return true;
1738
+}
1739
+
1740
+bool obs_hotkeys_platform_is_pressed(obs_hotkeys_platform_t *plat,
1741
+ obs_key_t key)
1742
+{
1743
+ bool mouse_pressed = false;
1744
+ if (mouse_button_pressed(key, &mouse_pressed))
1745
+ return mouse_pressed;
1746
+
1747
+ if (!plat)
1748
+ return false;
1749
+
1750
+ if (key >= OBS_KEY_LAST_VALUE)
1751
+ return false;
1752
+
1753
+ for (size_t i = 0; i < plat->keys[key].num;) {
1754
+ IOHIDElementRef element = plat->keys[key].array[i];
1755
+ IOHIDValueRef value = 0;
1756
+ IOHIDDeviceRef device = IOHIDElementGetDevice(element);
1757
+
1758
+ if (IOHIDDeviceGetValue(device, element, &value) !=
1759
+ kIOReturnSuccess) {
1760
+ i += 1;
1761
+ continue;
1762
+ }
1763
+
1764
+ if (!value) {
1765
+ CFRelease(element);
1766
+ da_erase(plat->keys[key], i);
1767
+ continue;
1768
+ }
1769
+
1770
+ if (IOHIDValueGetIntegerValue(value) == 1)
1771
+ return true;
1772
+
1773
+ i += 1;
1774
+ }
1775
+
1776
+ return false;
1777
+}
1778
obs-studio-24.0.3.tar.xz/libobs/obs-config.h -> obs-studio-24.0.5.tar.xz/libobs/obs-config.h
Changed
10
1
2
*
3
* Reset to zero each major or minor version
4
*/
5
-#define LIBOBS_API_PATCH_VER 3
6
+#define LIBOBS_API_PATCH_VER 5
7
8
#define MAKE_SEMANTIC_VERSION(major, minor, patch) \
9
((major << 24) | (minor << 16) | patch)
10
obs-studio-24.0.3.tar.xz/libobs/obs-video-gpu-encode.c -> obs-studio-24.0.5.tar.xz/libobs/obs-video-gpu-encode.c
Changed
15
1
2
video_output_inc_texture_frames(video->video);
3
4
for (size_t i = 0; i < video->gpu_encoders.num; i++) {
5
- obs_encoder_t *encoder = video->gpu_encoders.array[i];
6
- da_push_back(encoders, &encoder);
7
- obs_encoder_addref(encoder);
8
+ obs_encoder_t *encoder = obs_encoder_get_ref(
9
+ video->gpu_encoders.array[i]);
10
+ if (encoder)
11
+ da_push_back(encoders, &encoder);
12
}
13
14
pthread_mutex_unlock(&video->gpu_encoder_mutex);
15
obs-studio-24.0.3.tar.xz/plugins/linux-capture/xcompcap-main.cpp -> obs-studio-24.0.5.tar.xz/plugins/linux-capture/xcompcap-main.cpp
Changed
11
1
2
effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
3
4
while (gs_effect_loop(effect, "Draw")) {
5
- xcursor_render(p->cursor);
6
+ xcursor_render(p->cursor, -p->cur_cut_left,
7
+ -p->cur_cut_top);
8
}
9
}
10
}
11
obs-studio-24.0.3.tar.xz/plugins/linux-capture/xcursor.c -> obs-studio-24.0.5.tar.xz/plugins/linux-capture/xcursor.c
Changed
20
1
2
XFree(xc);
3
}
4
5
-void xcursor_render(xcursor_t *data)
6
+void xcursor_render(xcursor_t *data, int x_offset, int y_offset)
7
{
8
if (!data->tex)
9
return;
10
11
gs_enable_color(true, true, true, false);
12
13
gs_matrix_push();
14
- gs_matrix_translate3f(data->render_x, data->render_y, 0.0f);
15
+ gs_matrix_translate3f(data->render_x + x_offset,
16
+ data->render_y + y_offset, 0.0f);
17
gs_draw_sprite(data->tex, 0, 0, 0);
18
gs_matrix_pop();
19
20
obs-studio-24.0.3.tar.xz/plugins/linux-capture/xcursor.h -> obs-studio-24.0.5.tar.xz/plugins/linux-capture/xcursor.h
Changed
10
1
2
*
3
* This needs to be executed within a valid render context
4
*/
5
-void xcursor_render(xcursor_t *data);
6
+void xcursor_render(xcursor_t *data, int x_offset, int y_offset);
7
8
/**
9
* Specify offset for the cursor
10
obs-studio-24.0.3.tar.xz/plugins/linux-capture/xhelpers.c -> obs-studio-24.0.5.tar.xz/plugins/linux-capture/xhelpers.c
Changed
9
1
2
{
3
if (!xcb)
4
return 0;
5
-
6
xcb_screen_t *screen;
7
screen = xcb_setup_roots_iterator(xcb_get_setup(xcb)).data;
8
9
obs-studio-24.0.3.tar.xz/plugins/linux-capture/xshm-input.c -> obs-studio-24.0.5.tar.xz/plugins/linux-capture/xshm-input.c
Changed
12
1
2
")",
3
i, w, h, x, y);
4
5
- obs_property_list_add_int(screens, screen_info.array, i);
6
+ if (h > 0 && w > 0)
7
+ obs_property_list_add_int(screens, screen_info.array,
8
+ i);
9
}
10
11
/* handle missing screen */
12
obs-studio-24.0.3.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-output.c -> obs-studio-24.0.5.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-output.c
Changed
11
1
2
*assign = 0;
3
value = assign + 1;
4
5
- if (av_opt_set(context->priv_data, name, value, 0)) {
6
+ if (av_opt_set(context, name, value,
7
+ AV_OPT_SEARCH_CHILDREN)) {
8
blog(LOG_WARNING, "Failed to set %s=%s", name,
9
value);
10
ret = false;
11
obs-studio-24.0.3.tar.xz/plugins/obs-outputs/rtmp-stream.c -> obs-studio-24.0.5.tar.xz/plugins/obs-outputs/rtmp-stream.c
Changed
10
1
2
return;
3
}
4
5
- if (buffer_duration_usec >= DBR_TRIGGER_USEC) {
6
+ if ((uint64_t)buffer_duration_usec >= DBR_TRIGGER_USEC) {
7
pthread_mutex_lock(&stream->dbr_mutex);
8
bitrate_changed = dbr_bitrate_lowered(stream);
9
pthread_mutex_unlock(&stream->dbr_mutex);
10
obs-studio-24.0.3.tar.xz/plugins/rtmp-services/CMakeLists.txt -> obs-studio-24.0.5.tar.xz/plugins/rtmp-services/CMakeLists.txt
Changed
37
1
2
project(rtmp-services)
3
4
+find_package(Libcurl REQUIRED)
5
+
6
+include_directories(${LIBCURL_INCLUDE_DIRS})
7
+
8
include_directories(${OBS_JANSSON_INCLUDE_DIRS})
9
10
set(rtmp-services_SOURCES
11
twitch.c
12
+ younow.c
13
rtmp-common.c
14
rtmp-custom.c
15
rtmp-services-main.c)
16
17
set(rtmp-services_HEADERS
18
twitch.h
19
+ younow.h
20
rtmp-format-ver.h)
21
22
set(RTMP_SERVICES_URL
23
24
${rtmp-services_SOURCES}
25
${rtmp-services_HEADERS}
26
${rtmp-services_config_HEADERS})
27
+
28
target_link_libraries(rtmp-services
29
libobs
30
file-updater
31
- ${OBS_JANSSON_IMPORT})
32
+ ${OBS_JANSSON_IMPORT}
33
+ ${LIBCURL_LIBRARIES})
34
35
target_include_directories(rtmp-services
36
PUBLIC
37
obs-studio-24.0.3.tar.xz/plugins/rtmp-services/data/package.json -> obs-studio-24.0.5.tar.xz/plugins/rtmp-services/data/package.json
Changed
14
1
2
{
3
"url": "https://obsproject.com/obs2_update/rtmp-services",
4
- "version": 112,
5
+ "version": 114,
6
"files": [
7
{
8
"name": "services.json",
9
- "version": 112
10
+ "version": 114
11
}
12
]
13
}
14
obs-studio-24.0.3.tar.xz/plugins/rtmp-services/data/services.json -> obs-studio-24.0.5.tar.xz/plugins/rtmp-services/data/services.json
Changed
71
1
2
}
3
},
4
{
5
+ "name": "ChathostessModels",
6
+ "servers": [
7
+ {
8
+ "name": "ChathostessModels - Default",
9
+ "url": "rtmp://wowza01.foobarweb.com/cmschatsys_video"
10
+ }
11
+ ],
12
+ "recommended": {
13
+ "keyint": 2,
14
+ "max video bitrate": 3000,
15
+ "max audio bitrate": 128
16
+ }
17
+ },
18
+ {
19
"name": "Camplace",
20
"servers": [
21
{
22
23
}
24
},
25
{
26
+ "name": "YouNow",
27
+ "common": false,
28
+ "servers": [
29
+ {
30
+ "name": "younow.com",
31
+ "url": "https://signaling-api.younow-prod.video.propsproject.com/api/v1/ingest/server/"
32
+ }
33
+ ],
34
+ "recommended": {
35
+ "keyint": 2,
36
+ "output": "ftl_output",
37
+ "max audio bitrate": 160,
38
+ "max video bitrate": 7000,
39
+ "profile": "main",
40
+ "bframes": 0
41
+ }
42
+ },
43
+ {
44
"name": "Steam",
45
"common": false,
46
"servers": [
47
48
"max video bitrate": 7000,
49
"max audio bitrate": 128
50
}
51
+ },
52
+ {
53
+ "name": "Stars.AVN.com",
54
+ "servers": [
55
+ {
56
+ "name": "Default",
57
+ "url": "rtmp://alpha.gateway.stars.avn.com/live"
58
+ }
59
+ ],
60
+ "recommended": {
61
+ "keyint": 2,
62
+ "profile": "main",
63
+ "max video bitrate": 2500,
64
+ "max audio bitrate": 192,
65
+ "bframes": 0,
66
+ "x264opts": "tune=zerolatency"
67
+ }
68
}
69
]
70
}
71
obs-studio-24.0.3.tar.xz/plugins/rtmp-services/rtmp-common.c -> obs-studio-24.0.5.tar.xz/plugins/rtmp-services/rtmp-common.c
Changed
33
1
2
3
#include "rtmp-format-ver.h"
4
#include "twitch.h"
5
+#include "younow.h"
6
7
struct rtmp_common {
8
char *service;
9
10
obs_data_set_string(settings, "rate_control", "CBR");
11
12
item = json_object_get(recommended, "profile");
13
- if (json_is_string(item)) {
14
+ obs_data_item_t *enc_item = obs_data_item_byname(settings, "profile");
15
+ if (json_is_string(item) &&
16
+ obs_data_item_gettype(enc_item) == OBS_DATA_STRING) {
17
const char *profile = json_string_value(item);
18
obs_data_set_string(settings, "profile", profile);
19
}
20
21
}
22
}
23
24
+ if (service->service && strcmp(service->service, "YouNow") == 0) {
25
+ if (service->server && service->key) {
26
+ return younow_get_ingest(service->server, service->key);
27
+ }
28
+ }
29
+
30
return service->server;
31
}
32
33
obs-studio-24.0.5.tar.xz/plugins/rtmp-services/younow.c
Added
115
1
2
+#include <curl/curl.h>
3
+#include <stdlib.h>
4
+#include <string.h>
5
+
6
+#include <util/dstr.h>
7
+#include "util/base.h"
8
+#include "younow.h"
9
+
10
+struct younow_mem_struct {
11
+ char *memory;
12
+ size_t size;
13
+};
14
+
15
+static char *current_ingest = NULL;
16
+
17
+static size_t younow_write_cb(void *contents, size_t size, size_t nmemb,
18
+ void *userp)
19
+{
20
+ size_t realsize = size * nmemb;
21
+ struct younow_mem_struct *mem = (struct younow_mem_struct *)userp;
22
+
23
+ mem->memory = realloc(mem->memory, mem->size + realsize + 1);
24
+ if (mem->memory == NULL) {
25
+ blog(LOG_WARNING, "yyounow_write_cb: realloc returned NULL");
26
+ return 0;
27
+ }
28
+
29
+ memcpy(&(mem->memory[mem->size]), contents, realsize);
30
+ mem->size += realsize;
31
+ mem->memory[mem->size] = 0;
32
+
33
+ return realsize;
34
+}
35
+
36
+const char *younow_get_ingest(const char *server, const char *key)
37
+{
38
+ CURL *curl_handle;
39
+ CURLcode res;
40
+ struct younow_mem_struct chunk;
41
+ struct dstr uri;
42
+ long response_code;
43
+
44
+ // find the delimiter in stream key
45
+ const char *delim = strchr(key, '_');
46
+ if (delim == NULL) {
47
+ blog(LOG_WARNING,
48
+ "younow_get_ingest: delimiter not found in stream key");
49
+ return server;
50
+ }
51
+
52
+ curl_handle = curl_easy_init();
53
+
54
+ chunk.memory = malloc(1); /* will be grown as needed by realloc */
55
+ chunk.size = 0; /* no data at this point */
56
+
57
+ dstr_init(&uri);
58
+ dstr_copy(&uri, server);
59
+ dstr_ncat(&uri, key, delim - key);
60
+
61
+ curl_easy_setopt(curl_handle, CURLOPT_URL, uri.array);
62
+ curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, true);
63
+ curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2L);
64
+ curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 3L);
65
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, younow_write_cb);
66
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
67
+
68
+#if LIBCURL_VERSION_NUM >= 0x072400
69
+ // A lot of servers don't yet support ALPN
70
+ curl_easy_setopt(curl_handle, CURLOPT_SSL_ENABLE_ALPN, 0);
71
+#endif
72
+
73
+ res = curl_easy_perform(curl_handle);
74
+ dstr_free(&uri);
75
+
76
+ if (res != CURLE_OK) {
77
+ blog(LOG_WARNING,
78
+ "younow_get_ingest: curl_easy_perform() failed: %s",
79
+ curl_easy_strerror(res));
80
+ curl_easy_cleanup(curl_handle);
81
+ free(chunk.memory);
82
+ return server;
83
+ }
84
+
85
+ curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &response_code);
86
+ if (response_code != 200) {
87
+ blog(LOG_WARNING,
88
+ "younow_get_ingest: curl_easy_perform() returned code: %ld",
89
+ response_code);
90
+ curl_easy_cleanup(curl_handle);
91
+ free(chunk.memory);
92
+ return server;
93
+ }
94
+
95
+ curl_easy_cleanup(curl_handle);
96
+
97
+ if (chunk.size == 0) {
98
+ blog(LOG_WARNING,
99
+ "younow_get_ingest: curl_easy_perform() returned empty response");
100
+ free(chunk.memory);
101
+ return server;
102
+ }
103
+
104
+ if (current_ingest) {
105
+ free(current_ingest);
106
+ current_ingest = NULL;
107
+ }
108
+
109
+ current_ingest = strdup(chunk.memory);
110
+ free(chunk.memory);
111
+ blog(LOG_INFO, "younow_get_ingest: returning ingest: %s",
112
+ current_ingest);
113
+ return current_ingest;
114
+}
115
obs-studio-24.0.5.tar.xz/plugins/rtmp-services/younow.h
Added
6
1
2
+#pragma once
3
+
4
+extern const char *younow_get_ingest(const char *server, const char *key);
5
\ No newline at end of file
6
obs-studio-24.0.3.tar.xz/plugins/win-capture/window-helpers.c -> obs-studio-24.0.5.tar.xz/plugins/win-capture/window-helpers.c
Changed
25
1
2
3
/* not capturable or internal windows */
4
static const char *internal_microsoft_exes[] = {
5
+ "startmenuexperiencehost",
6
"applicationframehost",
7
+ "peopleexperiencehost",
8
"shellexperiencehost",
9
+ "microsoft.notes",
10
"windowsinternal",
11
+ "systemsettings",
12
+ "textinputhost",
13
"winstore.app",
14
+ "searchapp",
15
+ "video.ui",
16
"searchui",
17
"lockapp",
18
+ "cortana",
19
+ "gamebar",
20
+ "tabtip",
21
+ "time",
22
NULL,
23
};
24
25
obs-studio-24.0.3.tar.xz/plugins/win-dshow/win-dshow.cpp -> obs-studio-24.0.5.tar.xz/plugins/win-dshow/win-dshow.cpp
Changed
14
1
2
void DShowInput::OnEncodedVideoData(enum AVCodecID id, unsigned char *data,
3
size_t size, long long ts)
4
{
5
+ /* If format changes, free and allow it to recreate the decoder */
6
+ if (ffmpeg_decode_valid(video_decoder) &&
7
+ video_decoder->codec->id != id) {
8
+ ffmpeg_decode_free(video_decoder);
9
+ }
10
+
11
if (!ffmpeg_decode_valid(video_decoder)) {
12
/* Only use MJPEG hardware decoding on resolutions higher
13
* than 1920x1080. The reason why is because we want to strike
14
obs-studio-24.0.3.tar.xz/plugins/win-wasapi/enum-wasapi.hpp -> obs-studio-24.0.5.tar.xz/plugins/win-wasapi/enum-wasapi.hpp
Changed
9
1
2
3
#define WIN32_MEAN_AND_LEAN
4
#include <windows.h>
5
+#include <initguid.h>
6
#include <mmdeviceapi.h>
7
#include <audioclient.h>
8
#include <propsys.h>
9
obs-studio-24.0.3.tar.xz/plugins/win-wasapi/win-wasapi.cpp -> obs-studio-24.0.5.tar.xz/plugins/win-wasapi/win-wasapi.cpp
Changed
42
1
2
obs_source_t *source;
3
string device_id;
4
string device_name;
5
+ string device_sample = "-";
6
bool isInputDevice;
7
bool useDeviceTiming = false;
8
bool isDefaultDevice = false;
9
10
client->Start();
11
active = true;
12
13
- blog(LOG_INFO, "WASAPI: Device '%s' initialized", device_name.c_str());
14
+ blog(LOG_INFO, "WASAPI: Device '%s' [%s Hz] initialized",
15
+ device_name.c_str(), device_sample.c_str());
16
}
17
18
void WASAPISource::Initialize()
19
20
21
device_name = GetDeviceName(device);
22
23
+ HRESULT resSample;
24
+ IPropertyStore *store = nullptr;
25
+ PWAVEFORMATEX deviceFormatProperties;
26
+ PROPVARIANT prop;
27
+ resSample = device->OpenPropertyStore(STGM_READ, &store);
28
+ if (!FAILED(resSample)) {
29
+ resSample =
30
+ store->GetValue(PKEY_AudioEngine_DeviceFormat, &prop);
31
+ if (!FAILED(resSample)) {
32
+ deviceFormatProperties =
33
+ (PWAVEFORMATEX)prop.blob.pBlobData;
34
+ device_sample = std::to_string(
35
+ deviceFormatProperties->nSamplesPerSec);
36
+ }
37
+ }
38
+
39
InitClient();
40
if (!isInputDevice)
41
InitRender();
42