Overview
Request 4651 (accepted)
- Update to version 24.0.5:
* libobs: Update version to 24.0.5
* CI: Don't run clang format on some submodule plugins
* Merge pull request #2010 from wanhongqing123/master
* Merge pull request #2042 from WizardCM/custom-twitch-docks
* Merge pull request #2183 from ratwithacompiler/macos-python-fix-2
* Merge pull request #2085 from ratwithacompiler/macos-python-fix
* Merge pull request #2090 from jpark37/dxgi-refresh-rate
* Merge pull request #2089 from jpark37/dxgi-driver-version
* UI: Delete cookies before connecting account
* UI: Fix bug in untested/unused function code path
* deps/media-playback: Don't use interrupt cb for local files
* deps/media-playback: Don't exit thread on AVERROR_EXIT
* deps/obs-scripting: Fix formatting
* Merge pull request #2152 from Rosuav/fix-cursor-position
* UI: Fix Twitch panels not using dark first time
* Merge pull request #1914 from YouNow/master
* Merge pull request #2140 from DevWolk/avn-obs
* Merge pull request #2045 from wolf247/master
* Merge pull request #2179 from WizardCM/remove-help-interact
* Merge pull request #2125 from DDRBoxman/appbundle
* Merge pull request #2168 from kkartaltepe/vaapi-profile-fix
* Merge pull request #2148 from eulertour/master
* Merge pull request #2146 from Fenrirthviti/recording-bitrate-fix
* libobs: Fix race condition
* Merge pull request #2147 from JohannMG/vscode-ignore
* Merge pull request #2134 from WizardCM/wasapi-samplerate
* Merge pull request #2129 from Fenrirthviti/win-blacklist-update
* Merge pull request #2131 from jpark37/input-layout-error
* Merge pull request #2128 from Xaymar/return-to-break
- Created by boombatower over 5 years ago
- In state accepted
-
Package maintainers:
boombatower,
darix, and
frispete
obs-studio.changes
Changed
-------------------------------------------------------------------
+Fri Dec 13 21:17:57 UTC 2019 - jimmy@boombatower.com
+
+- Update to version 24.0.5:
+ * libobs: Update version to 24.0.5
+ * CI: Don't run clang format on some submodule plugins
+ * Merge pull request #2010 from wanhongqing123/master
+ * Merge pull request #2042 from WizardCM/custom-twitch-docks
+ * Merge pull request #2183 from ratwithacompiler/macos-python-fix-2
+ * Merge pull request #2085 from ratwithacompiler/macos-python-fix
+ * Merge pull request #2090 from jpark37/dxgi-refresh-rate
+ * Merge pull request #2089 from jpark37/dxgi-driver-version
+ * UI: Delete cookies before connecting account
+ * UI: Fix bug in untested/unused function code path
+ * deps/media-playback: Don't use interrupt cb for local files
+ * deps/media-playback: Don't exit thread on AVERROR_EXIT
+ * deps/obs-scripting: Fix formatting
+ * Merge pull request #2152 from Rosuav/fix-cursor-position
+ * UI: Fix Twitch panels not using dark first time
+ * Merge pull request #1914 from YouNow/master
+ * Merge pull request #2140 from DevWolk/avn-obs
+ * Merge pull request #2045 from wolf247/master
+ * Merge pull request #2179 from WizardCM/remove-help-interact
+ * Merge pull request #2125 from DDRBoxman/appbundle
+ * Merge pull request #2168 from kkartaltepe/vaapi-profile-fix
+ * Merge pull request #2148 from eulertour/master
+ * Merge pull request #2146 from Fenrirthviti/recording-bitrate-fix
+ * libobs: Fix race condition
+ * Merge pull request #2147 from JohannMG/vscode-ignore
+ * Merge pull request #2134 from WizardCM/wasapi-samplerate
+ * Merge pull request #2129 from Fenrirthviti/win-blacklist-update
+ * Merge pull request #2131 from jpark37/input-layout-error
+ * Merge pull request #2128 from Xaymar/return-to-break
+ * Merge pull request #2121 from cg2121/fix-warning
+ * Merge pull request #2110 from derrod/ffmpeg-output-fix
+ * Merge pull request #2106 from cg2121/fix-preview-bug
+ * Merge pull request #2126 from Fenrirthviti/linux-ci-fix
+ * Merge pull request #2091 from Programatic/xshm_wrong_windows
+ * Merge pull request #2120 from jpark37/objc-msgsend
+
+-------------------------------------------------------------------
Tue Oct 15 14:33:53 UTC 2019 - jimmy@boombatower.com
- Update to version 24.0.3:
obs-studio.spec
Changed
Name: obs-studio
-Version: 24.0.3
+Version: 24.0.5
Release: 0
Summary: A recording/broadcasting program
Group: Productivity/Multimedia/Video/Editors and Convertors
_service
Changed
<services>
<service name="tar_scm" mode="disabled">
<param name="versionformat">@PARENT_TAG@</param>
- <param name="revision">refs/tags/24.0.3</param>
+ <param name="revision">refs/tags/24.0.5</param>
<param name="url">git://github.com/jp9000/obs-studio.git</param>
<param name="scm">git</param>
<param name="changesgenerate">enable</param>
_servicedata
Changed
<servicedata>
<service name="tar_scm">
<param name="url">git://github.com/jp9000/obs-studio.git</param>
- <param name="changesrevision">d88a5a5a60bcdcbdde6d5dc54dc352ae8d431070</param>
+ <param name="changesrevision">99638ba69782bdb10531a305093bbd25e5d3baef</param>
</service>
</servicedata>
obs-studio-24.0.3.tar.xz/libobs/obs-cocoa.c
Deleted
-/******************************************************************************
- Copyright (C) 2013 by Ruwen Hahn <palana@stunned.de>
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-******************************************************************************/
-
-#include "util/platform.h"
-#include "util/dstr.h"
-#include "obs.h"
-#include "obs-internal.h"
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/sysctl.h>
-
-#include <objc/objc.h>
-#include <Carbon/Carbon.h>
-#include <IOKit/hid/IOHIDDevice.h>
-#include <IOKit/hid/IOHIDManager.h>
-
-const char *get_module_extension(void)
-{
- return ".so";
-}
-
-static const char *module_bin[] = {
- "../obs-plugins",
- OBS_INSTALL_PREFIX "obs-plugins",
-};
-
-static const char *module_data[] = {
- "../data/obs-plugins/%module%",
- OBS_INSTALL_DATA_PATH "obs-plugins/%module%",
-};
-
-static const int module_patterns_size =
- sizeof(module_bin) / sizeof(module_bin[0]);
-
-void add_default_module_paths(void)
-{
- for (int i = 0; i < module_patterns_size; i++)
- obs_add_module_path(module_bin[i], module_data[i]);
-}
-
-char *find_libobs_data_file(const char *file)
-{
- struct dstr path;
- dstr_init_copy(&path, OBS_INSTALL_DATA_PATH "/libobs/");
- dstr_cat(&path, file);
- return path.array;
-}
-
-static void log_processor_name(void)
-{
- char *name = NULL;
- size_t size;
- int ret;
-
- ret = sysctlbyname("machdep.cpu.brand_string", NULL, &size, NULL, 0);
- if (ret != 0)
- return;
-
- name = malloc(size);
-
- ret = sysctlbyname("machdep.cpu.brand_string", name, &size, NULL, 0);
- if (ret == 0)
- blog(LOG_INFO, "CPU Name: %s", name);
-
- free(name);
-}
-
-static void log_processor_speed(void)
-{
- size_t size;
- long long freq;
- int ret;
-
- size = sizeof(freq);
- ret = sysctlbyname("hw.cpufrequency", &freq, &size, NULL, 0);
- if (ret == 0)
- blog(LOG_INFO, "CPU Speed: %lldMHz", freq / 1000000);
-}
-
-static void log_processor_cores(void)
-{
- blog(LOG_INFO, "Physical Cores: %d, Logical Cores: %d",
- os_get_physical_cores(), os_get_logical_cores());
-}
-
-static void log_available_memory(void)
-{
- size_t size;
- long long memory_available;
- int ret;
-
- size = sizeof(memory_available);
- ret = sysctlbyname("hw.memsize", &memory_available, &size, NULL, 0);
- if (ret == 0)
- blog(LOG_INFO, "Physical Memory: %lldMB Total",
- memory_available / 1024 / 1024);
-}
-
-static void log_os_name(id pi, SEL UTF8String)
-{
- unsigned long os_id = (unsigned long)objc_msgSend(
- pi, sel_registerName("operatingSystem"));
-
- id os = objc_msgSend(pi, sel_registerName("operatingSystemName"));
- const char *name = (const char *)objc_msgSend(os, UTF8String);
-
- if (os_id == 5 /*NSMACHOperatingSystem*/) {
- blog(LOG_INFO, "OS Name: Mac OS X (%s)", name);
- return;
- }
-
- blog(LOG_INFO, "OS Name: %s", name ? name : "Unknown");
-}
-
-static void log_os_version(id pi, SEL UTF8String)
-{
- id vs = objc_msgSend(pi,
- sel_registerName("operatingSystemVersionString"));
- const char *version = (const char *)objc_msgSend(vs, UTF8String);
-
- blog(LOG_INFO, "OS Version: %s", version ? version : "Unknown");
-}
-
-static void log_os(void)
-{
- Class NSProcessInfo = objc_getClass("NSProcessInfo");
- id pi = objc_msgSend((id)NSProcessInfo,
- sel_registerName("processInfo"));
-
- SEL UTF8String = sel_registerName("UTF8String");
-
- log_os_name(pi, UTF8String);
- log_os_version(pi, UTF8String);
-}
-
-static void log_kernel_version(void)
-{
- char kernel_version[1024];
- size_t size = sizeof(kernel_version);
- int ret;
-
- ret = sysctlbyname("kern.osrelease", kernel_version, &size, NULL, 0);
- if (ret == 0)
- blog(LOG_INFO, "Kernel Version: %s", kernel_version);
-}
-
-void log_system_info(void)
-{
- log_processor_name();
- log_processor_speed();
- log_processor_cores();
- log_available_memory();
- log_os();
- log_kernel_version();
-}
-
-static bool dstr_from_cfstring(struct dstr *str, CFStringRef ref)
-{
- CFIndex length = CFStringGetLength(ref);
- CFIndex max_size = CFStringGetMaximumSizeForEncoding(
- length, kCFStringEncodingUTF8);
- dstr_reserve(str, max_size);
-
- if (!CFStringGetCString(ref, str->array, max_size,
- kCFStringEncodingUTF8))
- return false;
-
- str->len = strlen(str->array);
- return true;
-}
-
-struct obs_hotkeys_platform {
- volatile long refs;
- TISInputSourceRef tis;
- CFDataRef layout_data;
- UCKeyboardLayout *layout;
- IOHIDManagerRef manager;
- DARRAY(IOHIDElementRef) keys[OBS_KEY_LAST_VALUE];
-};
-
-static void hotkeys_retain(struct obs_hotkeys_platform *plat)
-{
- os_atomic_inc_long(&plat->refs);
-}
-
-static inline void free_hotkeys_platform(obs_hotkeys_platform_t *plat);
-static void hotkeys_release(struct obs_hotkeys_platform *plat)
-{
- if (os_atomic_dec_long(&plat->refs) == -1)
- free_hotkeys_platform(plat);
-}
-
-#define INVALID_KEY 0xff
-
-int obs_key_to_virtual_key(obs_key_t code)
-{
- switch (code) {
- case OBS_KEY_A:
- return kVK_ANSI_A;
- case OBS_KEY_B:
- return kVK_ANSI_B;
- case OBS_KEY_C:
- return kVK_ANSI_C;
- case OBS_KEY_D:
- return kVK_ANSI_D;
- case OBS_KEY_E:
- return kVK_ANSI_E;
- case OBS_KEY_F:
- return kVK_ANSI_F;
- case OBS_KEY_G:
- return kVK_ANSI_G;
- case OBS_KEY_H:
- return kVK_ANSI_H;
- case OBS_KEY_I:
- return kVK_ANSI_I;
- case OBS_KEY_J:
- return kVK_ANSI_J;
- case OBS_KEY_K:
- return kVK_ANSI_K;
- case OBS_KEY_L:
- return kVK_ANSI_L;
- case OBS_KEY_M:
- return kVK_ANSI_M;
- case OBS_KEY_N:
- return kVK_ANSI_N;
- case OBS_KEY_O:
- return kVK_ANSI_O;
- case OBS_KEY_P:
- return kVK_ANSI_P;
- case OBS_KEY_Q:
- return kVK_ANSI_Q;
- case OBS_KEY_R:
- return kVK_ANSI_R;
- case OBS_KEY_S:
- return kVK_ANSI_S;
- case OBS_KEY_T:
- return kVK_ANSI_T;
- case OBS_KEY_U:
- return kVK_ANSI_U;
- case OBS_KEY_V:
- return kVK_ANSI_V;
- case OBS_KEY_W:
- return kVK_ANSI_W;
- case OBS_KEY_X:
- return kVK_ANSI_X;
- case OBS_KEY_Y:
- return kVK_ANSI_Y;
- case OBS_KEY_Z:
- return kVK_ANSI_Z;
-
- case OBS_KEY_1:
- return kVK_ANSI_1;
- case OBS_KEY_2:
- return kVK_ANSI_2;
- case OBS_KEY_3:
- return kVK_ANSI_3;
- case OBS_KEY_4:
- return kVK_ANSI_4;
- case OBS_KEY_5:
- return kVK_ANSI_5;
- case OBS_KEY_6:
- return kVK_ANSI_6;
- case OBS_KEY_7:
- return kVK_ANSI_7;
- case OBS_KEY_8:
- return kVK_ANSI_8;
- case OBS_KEY_9:
- return kVK_ANSI_9;
- case OBS_KEY_0:
- return kVK_ANSI_0;
-
- case OBS_KEY_RETURN:
- return kVK_Return;
- case OBS_KEY_ESCAPE:
- return kVK_Escape;
- case OBS_KEY_BACKSPACE:
- return kVK_Delete;
- case OBS_KEY_TAB:
- return kVK_Tab;
- case OBS_KEY_SPACE:
- return kVK_Space;
- case OBS_KEY_MINUS:
- return kVK_ANSI_Minus;
- case OBS_KEY_EQUAL:
- return kVK_ANSI_Equal;
- case OBS_KEY_BRACKETLEFT:
- return kVK_ANSI_LeftBracket;
- case OBS_KEY_BRACKETRIGHT:
- return kVK_ANSI_RightBracket;
- case OBS_KEY_BACKSLASH:
- return kVK_ANSI_Backslash;
- case OBS_KEY_SEMICOLON:
- return kVK_ANSI_Semicolon;
- case OBS_KEY_QUOTE:
- return kVK_ANSI_Quote;
- case OBS_KEY_DEAD_GRAVE:
- return kVK_ANSI_Grave;
- case OBS_KEY_COMMA:
- return kVK_ANSI_Comma;
- case OBS_KEY_PERIOD:
- return kVK_ANSI_Period;
- case OBS_KEY_SLASH:
- return kVK_ANSI_Slash;
- case OBS_KEY_CAPSLOCK:
- return kVK_CapsLock;
- case OBS_KEY_SECTION:
- return kVK_ISO_Section;
-
- case OBS_KEY_F1:
- return kVK_F1;
- case OBS_KEY_F2:
- return kVK_F2;
- case OBS_KEY_F3:
- return kVK_F3;
- case OBS_KEY_F4:
- return kVK_F4;
- case OBS_KEY_F5:
- return kVK_F5;
- case OBS_KEY_F6:
- return kVK_F6;
- case OBS_KEY_F7:
- return kVK_F7;
- case OBS_KEY_F8:
- return kVK_F8;
- case OBS_KEY_F9:
- return kVK_F9;
- case OBS_KEY_F10:
- return kVK_F10;
- case OBS_KEY_F11:
- return kVK_F11;
- case OBS_KEY_F12:
- return kVK_F12;
-
- case OBS_KEY_HELP:
- return kVK_Help;
- case OBS_KEY_HOME:
- return kVK_Home;
- case OBS_KEY_PAGEUP:
- return kVK_PageUp;
- case OBS_KEY_DELETE:
- return kVK_ForwardDelete;
- case OBS_KEY_END:
- return kVK_End;
- case OBS_KEY_PAGEDOWN:
- return kVK_PageDown;
-
- case OBS_KEY_RIGHT:
- return kVK_RightArrow;
- case OBS_KEY_LEFT:
- return kVK_LeftArrow;
- case OBS_KEY_DOWN:
- return kVK_DownArrow;
- case OBS_KEY_UP:
- return kVK_UpArrow;
-
- case OBS_KEY_CLEAR:
- return kVK_ANSI_KeypadClear;
- case OBS_KEY_NUMSLASH:
- return kVK_ANSI_KeypadDivide;
- case OBS_KEY_NUMASTERISK:
- return kVK_ANSI_KeypadMultiply;
- case OBS_KEY_NUMMINUS:
- return kVK_ANSI_KeypadMinus;
- case OBS_KEY_NUMPLUS:
- return kVK_ANSI_KeypadPlus;
- case OBS_KEY_ENTER:
- return kVK_ANSI_KeypadEnter;
-
- case OBS_KEY_NUM1:
- return kVK_ANSI_Keypad1;
- case OBS_KEY_NUM2:
- return kVK_ANSI_Keypad2;
- case OBS_KEY_NUM3:
- return kVK_ANSI_Keypad3;
- case OBS_KEY_NUM4:
- return kVK_ANSI_Keypad4;
- case OBS_KEY_NUM5:
- return kVK_ANSI_Keypad5;
- case OBS_KEY_NUM6:
- return kVK_ANSI_Keypad6;
- case OBS_KEY_NUM7:
- return kVK_ANSI_Keypad7;
- case OBS_KEY_NUM8:
- return kVK_ANSI_Keypad8;
- case OBS_KEY_NUM9:
- return kVK_ANSI_Keypad9;
- case OBS_KEY_NUM0:
- return kVK_ANSI_Keypad0;
-
- case OBS_KEY_NUMPERIOD:
- return kVK_ANSI_KeypadDecimal;
- case OBS_KEY_NUMEQUAL:
- return kVK_ANSI_KeypadEquals;
-
- case OBS_KEY_F13:
- return kVK_F13;
- case OBS_KEY_F14:
- return kVK_F14;
- case OBS_KEY_F15:
- return kVK_F15;
- case OBS_KEY_F16:
- return kVK_F16;
- case OBS_KEY_F17:
- return kVK_F17;
- case OBS_KEY_F18:
- return kVK_F18;
- case OBS_KEY_F19:
- return kVK_F19;
- case OBS_KEY_F20:
- return kVK_F20;
-
- case OBS_KEY_CONTROL:
- return kVK_Control;
- case OBS_KEY_SHIFT:
- return kVK_Shift;
- case OBS_KEY_ALT:
- return kVK_Option;
- case OBS_KEY_META:
- return kVK_Command;
- //case OBS_KEY_CONTROL: return kVK_RightControl;
- //case OBS_KEY_SHIFT: return kVK_RightShift;
- //case OBS_KEY_ALT: return kVK_RightOption;
- //case OBS_KEY_META: return 0x36;
-
- case OBS_KEY_NONE:
- case OBS_KEY_LAST_VALUE:
- default:
- break;
- }
- return INVALID_KEY;
-}
-
-static bool localized_key_to_str(obs_key_t key, struct dstr *str)
-{
-#define MAP_KEY(k, s) \
- case k: \
- dstr_copy(str, obs_get_hotkey_translation(k, s)); \
- return true
-
-#define MAP_BUTTON(i) \
- case OBS_KEY_MOUSE##i: \
- dstr_copy(str, obs_get_hotkey_translation(key, "Mouse " #i)); \
- return true
-
- switch (key) {
- MAP_KEY(OBS_KEY_SPACE, "Space");
- MAP_KEY(OBS_KEY_NUMEQUAL, "= (Keypad)");
- MAP_KEY(OBS_KEY_NUMASTERISK, "* (Keypad)");
- MAP_KEY(OBS_KEY_NUMPLUS, "+ (Keypad)");
- MAP_KEY(OBS_KEY_NUMMINUS, "- (Keypad)");
- MAP_KEY(OBS_KEY_NUMPERIOD, ". (Keypad)");
- MAP_KEY(OBS_KEY_NUMSLASH, "/ (Keypad)");
- MAP_KEY(OBS_KEY_NUM0, "0 (Keypad)");
- MAP_KEY(OBS_KEY_NUM1, "1 (Keypad)");
- MAP_KEY(OBS_KEY_NUM2, "2 (Keypad)");
- MAP_KEY(OBS_KEY_NUM3, "3 (Keypad)");
- MAP_KEY(OBS_KEY_NUM4, "4 (Keypad)");
- MAP_KEY(OBS_KEY_NUM5, "5 (Keypad)");
- MAP_KEY(OBS_KEY_NUM6, "6 (Keypad)");
- MAP_KEY(OBS_KEY_NUM7, "7 (Keypad)");
- MAP_KEY(OBS_KEY_NUM8, "8 (Keypad)");
- MAP_KEY(OBS_KEY_NUM9, "9 (Keypad)");
-
- MAP_BUTTON(1);
- MAP_BUTTON(2);
- MAP_BUTTON(3);
- MAP_BUTTON(4);
- MAP_BUTTON(5);
- MAP_BUTTON(6);
- MAP_BUTTON(7);
- MAP_BUTTON(8);
- MAP_BUTTON(9);
- MAP_BUTTON(10);
- MAP_BUTTON(11);
- MAP_BUTTON(12);
- MAP_BUTTON(13);
- MAP_BUTTON(14);
- MAP_BUTTON(15);
- MAP_BUTTON(16);
- MAP_BUTTON(17);
- MAP_BUTTON(18);
- MAP_BUTTON(19);
- MAP_BUTTON(20);
- MAP_BUTTON(21);
- MAP_BUTTON(22);
- MAP_BUTTON(23);
- MAP_BUTTON(24);
- MAP_BUTTON(25);
- MAP_BUTTON(26);
- MAP_BUTTON(27);
- MAP_BUTTON(28);
- MAP_BUTTON(29);
- default:
- break;
- }
-#undef MAP_BUTTON
-#undef MAP_KEY
-
- return false;
-}
-
-static bool code_to_str(int code, struct dstr *str)
-{
-#define MAP_GLYPH(c, g) \
- case c: \
- dstr_from_wcs(str, (wchar_t[]){g, 0}); \
- return true
-#define MAP_STR(c, s) \
- case c: \
- dstr_copy(str, s); \
- return true
- switch (code) {
- MAP_GLYPH(kVK_Return, 0x21A9);
- MAP_GLYPH(kVK_Escape, 0x238B);
- MAP_GLYPH(kVK_Delete, 0x232B);
- MAP_GLYPH(kVK_Tab, 0x21e5);
- MAP_GLYPH(kVK_CapsLock, 0x21EA);
- MAP_GLYPH(kVK_ANSI_KeypadClear, 0x2327);
- MAP_GLYPH(kVK_ANSI_KeypadEnter, 0x2305);
- MAP_GLYPH(kVK_Help, 0x003F);
- MAP_GLYPH(kVK_Home, 0x2196);
- MAP_GLYPH(kVK_PageUp, 0x21de);
- MAP_GLYPH(kVK_ForwardDelete, 0x2326);
- MAP_GLYPH(kVK_End, 0x2198);
- MAP_GLYPH(kVK_PageDown, 0x21df);
-
- MAP_GLYPH(kVK_RightArrow, 0x2192);
- MAP_GLYPH(kVK_LeftArrow, 0x2190);
- MAP_GLYPH(kVK_DownArrow, 0x2193);
- MAP_GLYPH(kVK_UpArrow, 0x2191);
-
- MAP_STR(kVK_F1, "F1");
- MAP_STR(kVK_F2, "F2");
- MAP_STR(kVK_F3, "F3");
- MAP_STR(kVK_F4, "F4");
- MAP_STR(kVK_F5, "F5");
- MAP_STR(kVK_F6, "F6");
- MAP_STR(kVK_F7, "F7");
- MAP_STR(kVK_F8, "F8");
- MAP_STR(kVK_F9, "F9");
- MAP_STR(kVK_F10, "F10");
- MAP_STR(kVK_F11, "F11");
- MAP_STR(kVK_F12, "F12");
- MAP_STR(kVK_F13, "F13");
- MAP_STR(kVK_F14, "F14");
- MAP_STR(kVK_F15, "F15");
- MAP_STR(kVK_F16, "F16");
- MAP_STR(kVK_F17, "F17");
- MAP_STR(kVK_F18, "F18");
- MAP_STR(kVK_F19, "F19");
- MAP_STR(kVK_F20, "F20");
- MAP_GLYPH(kVK_Control, kControlUnicode);
- MAP_GLYPH(kVK_Shift, kShiftUnicode);
- MAP_GLYPH(kVK_Option, kOptionUnicode);
- MAP_GLYPH(kVK_Command, kCommandUnicode);
- MAP_GLYPH(kVK_RightControl, kControlUnicode);
- MAP_GLYPH(kVK_RightShift, kShiftUnicode);
- MAP_GLYPH(kVK_RightOption, kOptionUnicode);
- }
-#undef MAP_STR
-#undef MAP_GLYPH
-
- return false;
-}
-
-void obs_key_to_str(obs_key_t key, struct dstr *str)
-{
- if (localized_key_to_str(key, str))
- return;
-
- int code = obs_key_to_virtual_key(key);
- if (code_to_str(code, str))
- return;
-
- if (code == INVALID_KEY) {
- blog(LOG_ERROR,
- "hotkey-cocoa: Got invalid key while "
- "translating key '%d' (%s)",
- key, obs_key_to_name(key));
- goto err;
- }
-
- struct obs_hotkeys_platform *plat = NULL;
-
- if (obs) {
- pthread_mutex_lock(&obs->hotkeys.mutex);
- plat = obs->hotkeys.platform_context;
- hotkeys_retain(plat);
- pthread_mutex_unlock(&obs->hotkeys.mutex);
- }
-
- if (!plat) {
- blog(LOG_ERROR,
- "hotkey-cocoa: Could not get hotkey platform "
- "while translating key '%d' (%s)",
- key, obs_key_to_name(key));
- goto err;
- }
-
- const UniCharCount max_length = 16;
- UInt32 dead_key_state = 0;
- UniChar buffer[max_length];
- UniCharCount len = 0;
-
- OSStatus err =
- UCKeyTranslate(plat->layout, code, kUCKeyActionDown,
- 0x104, //caps lock for upper case letters
- LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit,
- &dead_key_state, max_length, &len, buffer);
-
- if (err == noErr && len <= 0 && dead_key_state) {
- err = UCKeyTranslate(plat->layout, kVK_Space, kUCKeyActionDown,
- 0x104, LMGetKbdType(),
- kUCKeyTranslateNoDeadKeysBit,
- &dead_key_state, max_length, &len, buffer);
- }
-
- hotkeys_release(plat);
-
- if (err != noErr) {
- blog(LOG_ERROR,
- "hotkey-cocoa: Error while translating key '%d'"
- " (0x%x, %s) to string: %d",
- key, code, obs_key_to_name(key), err);
- goto err;
- }
-
- if (len == 0) {
- blog(LOG_ERROR,
- "hotkey-cocoa: Got 0 length string while "
- "translating '%d' (0x%x, %s) to string",
- key, code, obs_key_to_name(key));
- goto err;
- }
-
- CFStringRef string = CFStringCreateWithCharactersNoCopy(
- NULL, buffer, len, kCFAllocatorNull);
- if (!string) {
- blog(LOG_ERROR,
- "hotkey-cocoa: Could not create CFStringRef "
- "while translating '%d' (0x%x, %s) to string",
- key, code, obs_key_to_name(key));
- goto err;
- }
-
- if (!dstr_from_cfstring(str, string)) {
- blog(LOG_ERROR,
- "hotkey-cocoa: Could not translate CFStringRef "
- "to CString while translating '%d' (0x%x, %s)",
- key, code, obs_key_to_name(key));
-
- goto release;
- }
-
- CFRelease(string);
- return;
-
-release:
- CFRelease(string);
-err:
- dstr_copy(str, obs_key_to_name(key));
-}
-
-#define OBS_COCOA_MODIFIER_SIZE 7
-static void unichar_to_utf8(const UniChar *c, char *buff)
-{
- CFStringRef string = CFStringCreateWithCharactersNoCopy(
- NULL, c, 2, kCFAllocatorNull);
- if (!string) {
- blog(LOG_ERROR, "hotkey-cocoa: Could not create CFStringRef "
- "while populating modifier strings");
- return;
- }
-
- if (!CFStringGetCString(string, buff, OBS_COCOA_MODIFIER_SIZE,
- kCFStringEncodingUTF8))
- blog(LOG_ERROR,
- "hotkey-cocoa: Error while populating "
- " modifier string with glyph %d (0x%x)",
- c[0], c[0]);
-
- CFRelease(string);
-}
-
-static char ctrl_str[OBS_COCOA_MODIFIER_SIZE];
-static char opt_str[OBS_COCOA_MODIFIER_SIZE];
-static char shift_str[OBS_COCOA_MODIFIER_SIZE];
-static char cmd_str[OBS_COCOA_MODIFIER_SIZE];
-static void init_utf_8_strings(void)
-{
- const UniChar ctrl_uni[] = {kControlUnicode, 0};
- const UniChar opt_uni[] = {kOptionUnicode, 0};
- const UniChar shift_uni[] = {kShiftUnicode, 0};
- const UniChar cmd_uni[] = {kCommandUnicode, 0};
-
- unichar_to_utf8(ctrl_uni, ctrl_str);
- unichar_to_utf8(opt_uni, opt_str);
- unichar_to_utf8(shift_uni, shift_str);
- unichar_to_utf8(cmd_uni, cmd_str);
-}
-
-static pthread_once_t strings_token = PTHREAD_ONCE_INIT;
-void obs_key_combination_to_str(obs_key_combination_t key, struct dstr *str)
-{
- struct dstr key_str = {0};
- if (key.key != OBS_KEY_NONE)
- obs_key_to_str(key.key, &key_str);
-
- int res = pthread_once(&strings_token, init_utf_8_strings);
- if (res) {
- blog(LOG_ERROR,
- "hotkeys-cocoa: Error while translating "
- "modifiers %d (0x%x)",
- res, res);
- dstr_move(str, &key_str);
- return;
- }
-
-#define CHECK_MODIFIER(mod, str) ((key.modifiers & mod) ? str : "")
- dstr_printf(str, "%s%s%s%s%s",
- CHECK_MODIFIER(INTERACT_CONTROL_KEY, ctrl_str),
- CHECK_MODIFIER(INTERACT_ALT_KEY, opt_str),
- CHECK_MODIFIER(INTERACT_SHIFT_KEY, shift_str),
- CHECK_MODIFIER(INTERACT_COMMAND_KEY, cmd_str),
- key_str.len ? key_str.array : "");
-#undef CHECK_MODIFIER
-
- dstr_free(&key_str);
-}
-
-static inline CFDictionaryRef copy_device_mask(UInt32 page, UInt32 usage)
-{
- CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
- kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
-
- CFNumberRef value;
- // Add the page value.
- value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
- CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), value);
- CFRelease(value);
-
- // Add the usage value (which is only valid if page value exists).
- value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
- CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), value);
- CFRelease(value);
-
- return dict;
-}
-
-static CFSetRef copy_devices(obs_hotkeys_platform_t *plat, UInt32 page,
- UInt32 usage)
-{
- CFDictionaryRef mask = copy_device_mask(page, usage);
- IOHIDManagerSetDeviceMatching(plat->manager, mask);
- CFRelease(mask);
-
- CFSetRef devices = IOHIDManagerCopyDevices(plat->manager);
- if (!devices)
- return NULL;
-
- if (CFSetGetCount(devices) < 1) {
- CFRelease(devices);
- return NULL;
- }
-
- return devices;
-}
-
-static UInt16 usage_to_carbon(UInt32 usage)
-{
- switch (usage) {
- case kHIDUsage_KeyboardErrorRollOver:
- return INVALID_KEY;
- case kHIDUsage_KeyboardPOSTFail:
- return INVALID_KEY;
- case kHIDUsage_KeyboardErrorUndefined:
- return INVALID_KEY;
-
- case kHIDUsage_KeyboardA:
- return kVK_ANSI_A;
- case kHIDUsage_KeyboardB:
- return kVK_ANSI_B;
- case kHIDUsage_KeyboardC:
- return kVK_ANSI_C;
- case kHIDUsage_KeyboardD:
- return kVK_ANSI_D;
- case kHIDUsage_KeyboardE:
- return kVK_ANSI_E;
- case kHIDUsage_KeyboardF:
- return kVK_ANSI_F;
- case kHIDUsage_KeyboardG:
- return kVK_ANSI_G;
- case kHIDUsage_KeyboardH:
- return kVK_ANSI_H;
- case kHIDUsage_KeyboardI:
- return kVK_ANSI_I;
- case kHIDUsage_KeyboardJ:
- return kVK_ANSI_J;
- case kHIDUsage_KeyboardK:
- return kVK_ANSI_K;
- case kHIDUsage_KeyboardL:
- return kVK_ANSI_L;
- case kHIDUsage_KeyboardM:
- return kVK_ANSI_M;
- case kHIDUsage_KeyboardN:
- return kVK_ANSI_N;
- case kHIDUsage_KeyboardO:
- return kVK_ANSI_O;
- case kHIDUsage_KeyboardP:
- return kVK_ANSI_P;
- case kHIDUsage_KeyboardQ:
- return kVK_ANSI_Q;
- case kHIDUsage_KeyboardR:
- return kVK_ANSI_R;
- case kHIDUsage_KeyboardS:
- return kVK_ANSI_S;
- case kHIDUsage_KeyboardT:
- return kVK_ANSI_T;
- case kHIDUsage_KeyboardU:
- return kVK_ANSI_U;
- case kHIDUsage_KeyboardV:
- return kVK_ANSI_V;
- case kHIDUsage_KeyboardW:
- return kVK_ANSI_W;
- case kHIDUsage_KeyboardX:
- return kVK_ANSI_X;
- case kHIDUsage_KeyboardY:
- return kVK_ANSI_Y;
- case kHIDUsage_KeyboardZ:
- return kVK_ANSI_Z;
-
- case kHIDUsage_Keyboard1:
- return kVK_ANSI_1;
- case kHIDUsage_Keyboard2:
- return kVK_ANSI_2;
- case kHIDUsage_Keyboard3:
- return kVK_ANSI_3;
- case kHIDUsage_Keyboard4:
- return kVK_ANSI_4;
- case kHIDUsage_Keyboard5:
- return kVK_ANSI_5;
- case kHIDUsage_Keyboard6:
- return kVK_ANSI_6;
- case kHIDUsage_Keyboard7:
- return kVK_ANSI_7;
- case kHIDUsage_Keyboard8:
- return kVK_ANSI_8;
- case kHIDUsage_Keyboard9:
- return kVK_ANSI_9;
- case kHIDUsage_Keyboard0:
- return kVK_ANSI_0;
-
- case kHIDUsage_KeyboardReturnOrEnter:
- return kVK_Return;
- case kHIDUsage_KeyboardEscape:
- return kVK_Escape;
- case kHIDUsage_KeyboardDeleteOrBackspace:
- return kVK_Delete;
- case kHIDUsage_KeyboardTab:
- return kVK_Tab;
- case kHIDUsage_KeyboardSpacebar:
- return kVK_Space;
- case kHIDUsage_KeyboardHyphen:
- return kVK_ANSI_Minus;
- case kHIDUsage_KeyboardEqualSign:
- return kVK_ANSI_Equal;
- case kHIDUsage_KeyboardOpenBracket:
- return kVK_ANSI_LeftBracket;
- case kHIDUsage_KeyboardCloseBracket:
- return kVK_ANSI_RightBracket;
- case kHIDUsage_KeyboardBackslash:
- return kVK_ANSI_Backslash;
- case kHIDUsage_KeyboardNonUSPound:
- return INVALID_KEY;
- case kHIDUsage_KeyboardSemicolon:
- return kVK_ANSI_Semicolon;
- case kHIDUsage_KeyboardQuote:
- return kVK_ANSI_Quote;
- case kHIDUsage_KeyboardGraveAccentAndTilde:
- return kVK_ANSI_Grave;
- case kHIDUsage_KeyboardComma:
- return kVK_ANSI_Comma;
- case kHIDUsage_KeyboardPeriod:
- return kVK_ANSI_Period;
- case kHIDUsage_KeyboardSlash:
- return kVK_ANSI_Slash;
- case kHIDUsage_KeyboardCapsLock:
- return kVK_CapsLock;
-
- case kHIDUsage_KeyboardF1:
- return kVK_F1;
- case kHIDUsage_KeyboardF2:
- return kVK_F2;
- case kHIDUsage_KeyboardF3:
- return kVK_F3;
- case kHIDUsage_KeyboardF4:
- return kVK_F4;
- case kHIDUsage_KeyboardF5:
- return kVK_F5;
- case kHIDUsage_KeyboardF6:
- return kVK_F6;
- case kHIDUsage_KeyboardF7:
- return kVK_F7;
- case kHIDUsage_KeyboardF8:
- return kVK_F8;
- case kHIDUsage_KeyboardF9:
- return kVK_F9;
- case kHIDUsage_KeyboardF10:
- return kVK_F10;
- case kHIDUsage_KeyboardF11:
- return kVK_F11;
- case kHIDUsage_KeyboardF12:
- return kVK_F12;
-
- case kHIDUsage_KeyboardPrintScreen:
- return INVALID_KEY;
- case kHIDUsage_KeyboardScrollLock:
- return INVALID_KEY;
- case kHIDUsage_KeyboardPause:
- return INVALID_KEY;
- case kHIDUsage_KeyboardInsert:
- return kVK_Help;
- case kHIDUsage_KeyboardHome:
- return kVK_Home;
- case kHIDUsage_KeyboardPageUp:
- return kVK_PageUp;
- case kHIDUsage_KeyboardDeleteForward:
- return kVK_ForwardDelete;
- case kHIDUsage_KeyboardEnd:
- return kVK_End;
- case kHIDUsage_KeyboardPageDown:
- return kVK_PageDown;
-
- case kHIDUsage_KeyboardRightArrow:
- return kVK_RightArrow;
- case kHIDUsage_KeyboardLeftArrow:
- return kVK_LeftArrow;
- case kHIDUsage_KeyboardDownArrow:
- return kVK_DownArrow;
- case kHIDUsage_KeyboardUpArrow:
- return kVK_UpArrow;
-
- case kHIDUsage_KeypadNumLock:
- return kVK_ANSI_KeypadClear;
- case kHIDUsage_KeypadSlash:
- return kVK_ANSI_KeypadDivide;
- case kHIDUsage_KeypadAsterisk:
- return kVK_ANSI_KeypadMultiply;
- case kHIDUsage_KeypadHyphen:
- return kVK_ANSI_KeypadMinus;
- case kHIDUsage_KeypadPlus:
- return kVK_ANSI_KeypadPlus;
- case kHIDUsage_KeypadEnter:
- return kVK_ANSI_KeypadEnter;
-
- case kHIDUsage_Keypad1:
- return kVK_ANSI_Keypad1;
- case kHIDUsage_Keypad2:
- return kVK_ANSI_Keypad2;
- case kHIDUsage_Keypad3:
- return kVK_ANSI_Keypad3;
- case kHIDUsage_Keypad4:
- return kVK_ANSI_Keypad4;
- case kHIDUsage_Keypad5:
- return kVK_ANSI_Keypad5;
- case kHIDUsage_Keypad6:
- return kVK_ANSI_Keypad6;
- case kHIDUsage_Keypad7:
- return kVK_ANSI_Keypad7;
- case kHIDUsage_Keypad8:
- return kVK_ANSI_Keypad8;
- case kHIDUsage_Keypad9:
- return kVK_ANSI_Keypad9;
- case kHIDUsage_Keypad0:
- return kVK_ANSI_Keypad0;
-
- case kHIDUsage_KeypadPeriod:
- return kVK_ANSI_KeypadDecimal;
- case kHIDUsage_KeyboardNonUSBackslash:
- return INVALID_KEY;
- case kHIDUsage_KeyboardApplication:
- return kVK_F13;
- case kHIDUsage_KeyboardPower:
- return INVALID_KEY;
- case kHIDUsage_KeypadEqualSign:
- return kVK_ANSI_KeypadEquals;
-
- case kHIDUsage_KeyboardF13:
- return kVK_F13;
- case kHIDUsage_KeyboardF14:
- return kVK_F14;
- case kHIDUsage_KeyboardF15:
- return kVK_F15;
- case kHIDUsage_KeyboardF16:
- return kVK_F16;
- case kHIDUsage_KeyboardF17:
- return kVK_F17;
- case kHIDUsage_KeyboardF18:
- return kVK_F18;
- case kHIDUsage_KeyboardF19:
- return kVK_F19;
- case kHIDUsage_KeyboardF20:
- return kVK_F20;
- case kHIDUsage_KeyboardF21:
- return INVALID_KEY;
- case kHIDUsage_KeyboardF22:
- return INVALID_KEY;
- case kHIDUsage_KeyboardF23:
- return INVALID_KEY;
- case kHIDUsage_KeyboardF24:
- return INVALID_KEY;
-
- case kHIDUsage_KeyboardExecute:
- return INVALID_KEY;
- case kHIDUsage_KeyboardHelp:
- return INVALID_KEY;
- case kHIDUsage_KeyboardMenu:
- return 0x7F;
- case kHIDUsage_KeyboardSelect:
- return kVK_ANSI_KeypadEnter;
- case kHIDUsage_KeyboardStop:
- return INVALID_KEY;
- case kHIDUsage_KeyboardAgain:
- return INVALID_KEY;
- case kHIDUsage_KeyboardUndo:
- return INVALID_KEY;
- case kHIDUsage_KeyboardCut:
- return INVALID_KEY;
- case kHIDUsage_KeyboardCopy:
- return INVALID_KEY;
- case kHIDUsage_KeyboardPaste:
- return INVALID_KEY;
- case kHIDUsage_KeyboardFind:
- return INVALID_KEY;
-
- case kHIDUsage_KeyboardMute:
- return kVK_Mute;
- case kHIDUsage_KeyboardVolumeUp:
- return kVK_VolumeUp;
- case kHIDUsage_KeyboardVolumeDown:
- return kVK_VolumeDown;
-
- case kHIDUsage_KeyboardLockingCapsLock:
- return INVALID_KEY;
- case kHIDUsage_KeyboardLockingNumLock:
- return INVALID_KEY;
- case kHIDUsage_KeyboardLockingScrollLock:
- return INVALID_KEY;
-
- case kHIDUsage_KeypadComma:
- return INVALID_KEY;
- case kHIDUsage_KeypadEqualSignAS400:
- return INVALID_KEY;
- case kHIDUsage_KeyboardInternational1:
- return INVALID_KEY;
- case kHIDUsage_KeyboardInternational2:
- return INVALID_KEY;
- case kHIDUsage_KeyboardInternational3:
- return INVALID_KEY;
- case kHIDUsage_KeyboardInternational4:
- return INVALID_KEY;
- case kHIDUsage_KeyboardInternational5:
- return INVALID_KEY;
- case kHIDUsage_KeyboardInternational6:
- return INVALID_KEY;
- case kHIDUsage_KeyboardInternational7:
- return INVALID_KEY;
- case kHIDUsage_KeyboardInternational8:
- return INVALID_KEY;
- case kHIDUsage_KeyboardInternational9:
- return INVALID_KEY;
-
- case kHIDUsage_KeyboardLANG1:
- return INVALID_KEY;
- case kHIDUsage_KeyboardLANG2:
- return INVALID_KEY;
- case kHIDUsage_KeyboardLANG3:
- return INVALID_KEY;
- case kHIDUsage_KeyboardLANG4:
- return INVALID_KEY;
- case kHIDUsage_KeyboardLANG5:
- return INVALID_KEY;
- case kHIDUsage_KeyboardLANG6:
- return INVALID_KEY;
- case kHIDUsage_KeyboardLANG7:
- return INVALID_KEY;
- case kHIDUsage_KeyboardLANG8:
- return INVALID_KEY;
- case kHIDUsage_KeyboardLANG9:
- return INVALID_KEY;
-
- case kHIDUsage_KeyboardAlternateErase:
- return INVALID_KEY;
- case kHIDUsage_KeyboardSysReqOrAttention:
- return INVALID_KEY;
- case kHIDUsage_KeyboardCancel:
- return INVALID_KEY;
- case kHIDUsage_KeyboardClear:
- return INVALID_KEY;
- case kHIDUsage_KeyboardPrior:
- return INVALID_KEY;
- case kHIDUsage_KeyboardReturn:
- return INVALID_KEY;
- case kHIDUsage_KeyboardSeparator:
- return INVALID_KEY;
- case kHIDUsage_KeyboardOut:
- return INVALID_KEY;
- case kHIDUsage_KeyboardOper:
- return INVALID_KEY;
- case kHIDUsage_KeyboardClearOrAgain:
- return INVALID_KEY;
- case kHIDUsage_KeyboardCrSelOrProps:
- return INVALID_KEY;
- case kHIDUsage_KeyboardExSel:
- return INVALID_KEY;
-
- /* 0xa5-0xdf Reserved */
-
- case kHIDUsage_KeyboardLeftControl:
- return kVK_Control;
- case kHIDUsage_KeyboardLeftShift:
- return kVK_Shift;
- case kHIDUsage_KeyboardLeftAlt:
- return kVK_Option;
- case kHIDUsage_KeyboardLeftGUI:
- return kVK_Command;
- case kHIDUsage_KeyboardRightControl:
- return kVK_RightControl;
- case kHIDUsage_KeyboardRightShift:
- return kVK_RightShift;
- case kHIDUsage_KeyboardRightAlt:
- return kVK_RightOption;
- case kHIDUsage_KeyboardRightGUI:
- return 0x36; //??
-
- /* 0xe8-0xffff Reserved */
-
- case kHIDUsage_Keyboard_Reserved:
- return INVALID_KEY;
- default:
- return INVALID_KEY;
- }
- return INVALID_KEY;
-}
-
-obs_key_t obs_key_from_virtual_key(int code)
-{
- switch (code) {
- case kVK_ANSI_A:
- return OBS_KEY_A;
- case kVK_ANSI_B:
- return OBS_KEY_B;
- case kVK_ANSI_C:
- return OBS_KEY_C;
- case kVK_ANSI_D:
- return OBS_KEY_D;
- case kVK_ANSI_E:
- return OBS_KEY_E;
- case kVK_ANSI_F:
- return OBS_KEY_F;
- case kVK_ANSI_G:
- return OBS_KEY_G;
- case kVK_ANSI_H:
- return OBS_KEY_H;
- case kVK_ANSI_I:
- return OBS_KEY_I;
- case kVK_ANSI_J:
- return OBS_KEY_J;
- case kVK_ANSI_K:
- return OBS_KEY_K;
- case kVK_ANSI_L:
- return OBS_KEY_L;
- case kVK_ANSI_M:
- return OBS_KEY_M;
- case kVK_ANSI_N:
- return OBS_KEY_N;
- case kVK_ANSI_O:
- return OBS_KEY_O;
- case kVK_ANSI_P:
- return OBS_KEY_P;
- case kVK_ANSI_Q:
- return OBS_KEY_Q;
- case kVK_ANSI_R:
- return OBS_KEY_R;
- case kVK_ANSI_S:
- return OBS_KEY_S;
- case kVK_ANSI_T:
- return OBS_KEY_T;
- case kVK_ANSI_U:
- return OBS_KEY_U;
- case kVK_ANSI_V:
- return OBS_KEY_V;
- case kVK_ANSI_W:
- return OBS_KEY_W;
- case kVK_ANSI_X:
- return OBS_KEY_X;
- case kVK_ANSI_Y:
- return OBS_KEY_Y;
- case kVK_ANSI_Z:
- return OBS_KEY_Z;
-
- case kVK_ANSI_1:
- return OBS_KEY_1;
- case kVK_ANSI_2:
- return OBS_KEY_2;
- case kVK_ANSI_3:
- return OBS_KEY_3;
- case kVK_ANSI_4:
- return OBS_KEY_4;
- case kVK_ANSI_5:
- return OBS_KEY_5;
- case kVK_ANSI_6:
- return OBS_KEY_6;
- case kVK_ANSI_7:
- return OBS_KEY_7;
- case kVK_ANSI_8:
- return OBS_KEY_8;
- case kVK_ANSI_9:
- return OBS_KEY_9;
- case kVK_ANSI_0:
- return OBS_KEY_0;
-
- case kVK_Return:
- return OBS_KEY_RETURN;
- case kVK_Escape:
- return OBS_KEY_ESCAPE;
- case kVK_Delete:
- return OBS_KEY_BACKSPACE;
- case kVK_Tab:
- return OBS_KEY_TAB;
- case kVK_Space:
- return OBS_KEY_SPACE;
- case kVK_ANSI_Minus:
- return OBS_KEY_MINUS;
- case kVK_ANSI_Equal:
- return OBS_KEY_EQUAL;
- case kVK_ANSI_LeftBracket:
- return OBS_KEY_BRACKETLEFT;
- case kVK_ANSI_RightBracket:
- return OBS_KEY_BRACKETRIGHT;
- case kVK_ANSI_Backslash:
- return OBS_KEY_BACKSLASH;
- case kVK_ANSI_Semicolon:
- return OBS_KEY_SEMICOLON;
- case kVK_ANSI_Quote:
- return OBS_KEY_QUOTE;
- case kVK_ANSI_Grave:
- return OBS_KEY_DEAD_GRAVE;
- case kVK_ANSI_Comma:
- return OBS_KEY_COMMA;
- case kVK_ANSI_Period:
- return OBS_KEY_PERIOD;
- case kVK_ANSI_Slash:
- return OBS_KEY_SLASH;
- case kVK_CapsLock:
- return OBS_KEY_CAPSLOCK;
- case kVK_ISO_Section:
- return OBS_KEY_SECTION;
-
- case kVK_F1:
- return OBS_KEY_F1;
- case kVK_F2:
- return OBS_KEY_F2;
- case kVK_F3:
- return OBS_KEY_F3;
- case kVK_F4:
- return OBS_KEY_F4;
- case kVK_F5:
- return OBS_KEY_F5;
- case kVK_F6:
- return OBS_KEY_F6;
- case kVK_F7:
- return OBS_KEY_F7;
- case kVK_F8:
- return OBS_KEY_F8;
- case kVK_F9:
- return OBS_KEY_F9;
- case kVK_F10:
- return OBS_KEY_F10;
- case kVK_F11:
- return OBS_KEY_F11;
- case kVK_F12:
- return OBS_KEY_F12;
-
- case kVK_Help:
- return OBS_KEY_HELP;
- case kVK_Home:
- return OBS_KEY_HOME;
- case kVK_PageUp:
- return OBS_KEY_PAGEUP;
- case kVK_ForwardDelete:
- return OBS_KEY_DELETE;
- case kVK_End:
- return OBS_KEY_END;
- case kVK_PageDown:
- return OBS_KEY_PAGEDOWN;
-
- case kVK_RightArrow:
- return OBS_KEY_RIGHT;
- case kVK_LeftArrow:
- return OBS_KEY_LEFT;
- case kVK_DownArrow:
- return OBS_KEY_DOWN;
- case kVK_UpArrow:
- return OBS_KEY_UP;
-
- case kVK_ANSI_KeypadClear:
- return OBS_KEY_CLEAR;
- case kVK_ANSI_KeypadDivide:
- return OBS_KEY_NUMSLASH;
- case kVK_ANSI_KeypadMultiply:
- return OBS_KEY_NUMASTERISK;
- case kVK_ANSI_KeypadMinus:
- return OBS_KEY_NUMMINUS;
- case kVK_ANSI_KeypadPlus:
- return OBS_KEY_NUMPLUS;
- case kVK_ANSI_KeypadEnter:
- return OBS_KEY_ENTER;
-
- case kVK_ANSI_Keypad1:
- return OBS_KEY_NUM1;
- case kVK_ANSI_Keypad2:
- return OBS_KEY_NUM2;
- case kVK_ANSI_Keypad3:
- return OBS_KEY_NUM3;
- case kVK_ANSI_Keypad4:
- return OBS_KEY_NUM4;
- case kVK_ANSI_Keypad5:
- return OBS_KEY_NUM5;
- case kVK_ANSI_Keypad6:
- return OBS_KEY_NUM6;
- case kVK_ANSI_Keypad7:
- return OBS_KEY_NUM7;
- case kVK_ANSI_Keypad8:
- return OBS_KEY_NUM8;
- case kVK_ANSI_Keypad9:
- return OBS_KEY_NUM9;
- case kVK_ANSI_Keypad0:
- return OBS_KEY_NUM0;
-
- case kVK_ANSI_KeypadDecimal:
- return OBS_KEY_NUMPERIOD;
- case kVK_ANSI_KeypadEquals:
- return OBS_KEY_NUMEQUAL;
-
- case kVK_F13:
- return OBS_KEY_F13;
- case kVK_F14:
- return OBS_KEY_F14;
- case kVK_F15:
- return OBS_KEY_F15;
- case kVK_F16:
- return OBS_KEY_F16;
- case kVK_F17:
- return OBS_KEY_F17;
- case kVK_F18:
- return OBS_KEY_F18;
- case kVK_F19:
- return OBS_KEY_F19;
- case kVK_F20:
- return OBS_KEY_F20;
-
- case kVK_Control:
- return OBS_KEY_CONTROL;
- case kVK_Shift:
- return OBS_KEY_SHIFT;
- case kVK_Option:
- return OBS_KEY_ALT;
- case kVK_Command:
- return OBS_KEY_META;
- case kVK_RightControl:
- return OBS_KEY_CONTROL;
- case kVK_RightShift:
- return OBS_KEY_SHIFT;
- case kVK_RightOption:
- return OBS_KEY_ALT;
- case 0x36:
- return OBS_KEY_META;
-
- case kVK_Function:
- case kVK_Mute:
- case kVK_VolumeDown:
- case kVK_VolumeUp:
- break;
- }
- return OBS_KEY_NONE;
-}
-
-static inline void load_key(obs_hotkeys_platform_t *plat, IOHIDElementRef key)
-{
- UInt32 usage_code = IOHIDElementGetUsage(key);
- UInt16 carbon_code = usage_to_carbon(usage_code);
-
- if (carbon_code == INVALID_KEY)
- return;
-
- obs_key_t obs_key = obs_key_from_virtual_key(carbon_code);
- if (obs_key == OBS_KEY_NONE)
- return;
-
- da_push_back(plat->keys[obs_key], &key);
- CFRetain(*(IOHIDElementRef *)da_end(plat->keys[obs_key]));
-}
-
-static inline void load_keyboard(obs_hotkeys_platform_t *plat,
- IOHIDDeviceRef keyboard)
-{
- CFArrayRef keys = IOHIDDeviceCopyMatchingElements(
- keyboard, NULL, kIOHIDOptionsTypeNone);
-
- if (!keys) {
- blog(LOG_ERROR, "hotkeys-cocoa: Getting keyboard keys failed");
- return;
- }
-
- CFIndex count = CFArrayGetCount(keys);
- if (!count) {
- blog(LOG_ERROR, "hotkeys-cocoa: Keyboard has no keys");
- CFRelease(keys);
- return;
- }
-
- for (CFIndex i = 0; i < count; i++) {
- IOHIDElementRef key =
- (IOHIDElementRef)CFArrayGetValueAtIndex(keys, i);
-
- // Skip non-matching keys elements
- if (IOHIDElementGetUsagePage(key) != kHIDPage_KeyboardOrKeypad)
- continue;
-
- load_key(plat, key);
- }
-
- CFRelease(keys);
-}
-
-static bool init_keyboard(obs_hotkeys_platform_t *plat)
-{
- CFSetRef keyboards = copy_devices(plat, kHIDPage_GenericDesktop,
- kHIDUsage_GD_Keyboard);
- if (!keyboards)
- return false;
-
- CFIndex count = CFSetGetCount(keyboards);
-
- CFTypeRef devices[count];
- CFSetGetValues(keyboards, devices);
-
- for (CFIndex i = 0; i < count; i++)
- load_keyboard(plat, (IOHIDDeviceRef)devices[i]);
-
- CFRelease(keyboards);
- return true;
-}
-
-static inline void free_hotkeys_platform(obs_hotkeys_platform_t *plat)
-{
- if (!plat)
- return;
-
- if (plat->tis) {
- CFRelease(plat->tis);
- plat->tis = NULL;
- }
-
- if (plat->layout_data) {
- CFRelease(plat->layout_data);
- plat->layout_data = NULL;
- }
-
- if (plat->manager) {
- CFRelease(plat->manager);
- plat->manager = NULL;
- }
-
- for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++) {
- for (size_t j = 0; j < plat->keys[i].num; j++)
- CFRelease(plat->keys[i].array[j]);
-
- da_free(plat->keys[i]);
- }
-
- bfree(plat);
-}
-
-static bool log_layout_name(TISInputSourceRef tis)
-{
- struct dstr layout_name = {0};
- CFStringRef sid = (CFStringRef)TISGetInputSourceProperty(
- tis, kTISPropertyInputSourceID);
- if (!sid) {
- blog(LOG_ERROR, "hotkeys-cocoa: Failed getting InputSourceID");
- return false;
- }
-
- if (!dstr_from_cfstring(&layout_name, sid)) {
- blog(LOG_ERROR, "hotkeys-cocoa: Could not convert InputSourceID"
- " to CString");
- goto fail;
- }
-
- blog(LOG_INFO, "hotkeys-cocoa: Using layout '%s'", layout_name.array);
-
- dstr_free(&layout_name);
- return true;
-
-fail:
- dstr_free(&layout_name);
- return false;
-}
-
-static bool init_hotkeys_platform(obs_hotkeys_platform_t **plat_)
-{
- if (!plat_)
- return false;
-
- *plat_ = bzalloc(sizeof(obs_hotkeys_platform_t));
- obs_hotkeys_platform_t *plat = *plat_;
- if (!plat) {
- *plat_ = NULL;
- return false;
- }
-
- plat->tis = TISCopyCurrentKeyboardLayoutInputSource();
- plat->layout_data = (CFDataRef)TISGetInputSourceProperty(
- plat->tis, kTISPropertyUnicodeKeyLayoutData);
-
- if (!plat->layout_data) {
- blog(LOG_ERROR, "hotkeys-cocoa: Failed getting LayoutData");
- goto fail;
- }
-
- CFRetain(plat->layout_data);
- plat->layout = (UCKeyboardLayout *)CFDataGetBytePtr(plat->layout_data);
-
- plat->manager =
- IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
-
- IOReturn openStatus =
- IOHIDManagerOpen(plat->manager, kIOHIDOptionsTypeNone);
- if (openStatus != kIOReturnSuccess) {
- blog(LOG_ERROR, "hotkeys-cocoa: Failed opening HIDManager");
- goto fail;
- }
-
- init_keyboard(plat);
-
- return true;
-
-fail:
- hotkeys_release(plat);
- *plat_ = NULL;
- return false;
-}
-
-static void input_method_changed(CFNotificationCenterRef nc, void *observer,
- CFStringRef name, const void *object,
- CFDictionaryRef user_info)
-{
- UNUSED_PARAMETER(nc);
- UNUSED_PARAMETER(name);
- UNUSED_PARAMETER(object);
- UNUSED_PARAMETER(user_info);
-
- struct obs_core_hotkeys *hotkeys = observer;
- obs_hotkeys_platform_t *new_plat;
-
- if (init_hotkeys_platform(&new_plat)) {
- obs_hotkeys_platform_t *plat;
-
- pthread_mutex_lock(&hotkeys->mutex);
- plat = hotkeys->platform_context;
-
- if (new_plat && plat &&
- new_plat->layout_data == plat->layout_data) {
- pthread_mutex_unlock(&hotkeys->mutex);
- hotkeys_release(new_plat);
- return;
- }
-
- hotkeys->platform_context = new_plat;
- if (new_plat)
- log_layout_name(new_plat->tis);
- pthread_mutex_unlock(&hotkeys->mutex);
-
- calldata_t params = {0};
- signal_handler_signal(hotkeys->signals, "hotkey_layout_change",
- ¶ms);
- if (plat)
- hotkeys_release(plat);
- }
-}
-
-bool obs_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys)
-{
- CFNotificationCenterAddObserver(
- CFNotificationCenterGetDistributedCenter(), hotkeys,
- input_method_changed,
- kTISNotifySelectedKeyboardInputSourceChanged, NULL,
- CFNotificationSuspensionBehaviorDeliverImmediately);
-
- input_method_changed(NULL, hotkeys, NULL, NULL, NULL);
- return hotkeys->platform_context != NULL;
-}
-
-void obs_hotkeys_platform_free(struct obs_core_hotkeys *hotkeys)
-{
- CFNotificationCenterRemoveEveryObserver(
- CFNotificationCenterGetDistributedCenter(), hotkeys);
-
- hotkeys_release(hotkeys->platform_context);
-}
-
-typedef unsigned long NSUInteger;
-static bool mouse_button_pressed(obs_key_t key, bool *pressed)
-{
- int button = 0;
- switch (key) {
-#define MAP_BUTTON(n) \
- case OBS_KEY_MOUSE##n: \
- button = n - 1; \
- break
- MAP_BUTTON(1);
- MAP_BUTTON(2);
- MAP_BUTTON(3);
- MAP_BUTTON(4);
- MAP_BUTTON(5);
- MAP_BUTTON(6);
- MAP_BUTTON(7);
- MAP_BUTTON(8);
- MAP_BUTTON(9);
- MAP_BUTTON(10);
- MAP_BUTTON(11);
- MAP_BUTTON(12);
- MAP_BUTTON(13);
- MAP_BUTTON(14);
- MAP_BUTTON(15);
- MAP_BUTTON(16);
- MAP_BUTTON(17);
- MAP_BUTTON(18);
- MAP_BUTTON(19);
- MAP_BUTTON(20);
- MAP_BUTTON(21);
- MAP_BUTTON(22);
- MAP_BUTTON(23);
- MAP_BUTTON(24);
- MAP_BUTTON(25);
- MAP_BUTTON(26);
- MAP_BUTTON(27);
- MAP_BUTTON(28);
- MAP_BUTTON(29);
- break;
-#undef MAP_BUTTON
-
- default:
- return false;
- }
-
- Class NSEvent = objc_getClass("NSEvent");
- SEL pressedMouseButtons = sel_registerName("pressedMouseButtons");
- NSUInteger buttons =
- (NSUInteger)objc_msgSend((id)NSEvent, pressedMouseButtons);
-
- *pressed = (buttons & (1 << button)) != 0;
- return true;
-}
-
-bool obs_hotkeys_platform_is_pressed(obs_hotkeys_platform_t *plat,
- obs_key_t key)
-{
- bool mouse_pressed = false;
- if (mouse_button_pressed(key, &mouse_pressed))
- return mouse_pressed;
-
- if (!plat)
- return false;
-
- if (key >= OBS_KEY_LAST_VALUE)
- return false;
-
- for (size_t i = 0; i < plat->keys[key].num;) {
- IOHIDElementRef element = plat->keys[key].array[i];
- IOHIDValueRef value = 0;
- IOHIDDeviceRef device = IOHIDElementGetDevice(element);
-
- if (IOHIDDeviceGetValue(device, element, &value) !=
- kIOReturnSuccess) {
- i += 1;
- continue;
- }
-
- if (!value) {
- CFRelease(element);
- da_erase(plat->keys[key], i);
- continue;
- }
-
- if (IOHIDValueGetIntegerValue(value) == 1)
- return true;
-
- i += 1;
- }
-
- return false;
-}
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
set -e
# Generate file name variables
+export GIT_TAG=$(git describe --abbrev=0)
export GIT_HASH=$(git rev-parse --short HEAD)
export FILE_DATE=$(date +%Y-%m-%d.%H-%M-%S)
-export FILENAME=$FILE_DATE-$GIT_HASH-$TRAVIS_BRANCH-osx.pkg
+export FILENAME=$FILE_DATE-$GIT_HASH-$TRAVIS_BRANCH-osx.dmg
+
+echo "git tag: $GIT_TAG"
cd ./build
mv ./rundir/RelWithDebInfo/data/obs-scripting/obslua.so ./rundir/RelWithDebInfo/bin/
# Move obspython
-# hr "Moving OBS Python"
-# mv ./rundir/RelWithDebInfo/data/obs-scripting/_obspython.so ./rundir/RelWithDebInfo/bin/
-# mv ./rundir/RelWithDebInfo/data/obs-scripting/obspython.py ./rundir/RelWithDebInfo/bin/
+hr "Moving OBS Python"
+mv ./rundir/RelWithDebInfo/data/obs-scripting/_obspython.so ./rundir/RelWithDebInfo/bin/
+mv ./rundir/RelWithDebInfo/data/obs-scripting/obspython.py ./rundir/RelWithDebInfo/bin/
# Package everything into a nice .app
hr "Packaging .app"
STABLE=true
fi
-sudo python ../CI/install/osx/build_app.py --public-key ../CI/install/osx/OBSPublicDSAKey.pem --sparkle-framework ../../sparkle/Sparkle.framework --stable=$STABLE
+#sudo python ../CI/install/osx/build_app.py --public-key ../CI/install/osx/OBSPublicDSAKey.pem --sparkle-framework ../../sparkle/Sparkle.framework --stable=$STABLE
+
+../CI/install/osx/packageApp.sh
+
+# fix obs outputs
+cp /usr/local/opt/mbedtls/lib/libmbedtls.12.dylib ./OBS.app/Contents/Frameworks/
+cp /usr/local/opt/mbedtls/lib/libmbedcrypto.3.dylib ./OBS.app/Contents/Frameworks/
+cp /usr/local/opt/mbedtls/lib/libmbedx509.0.dylib ./OBS.app/Contents/Frameworks/
+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
+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
+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
+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
+install_name_tool -change @rpath/libobs.0.dylib @executable_path/../Frameworks/libobs.0.dylib ./OBS.app/Contents/Plugins/obs-outputs.so
+
+# copy sparkle into the app
+hr "Copying Sparkle.framework"
+cp -r ../../sparkle/Sparkle.framework ./OBS.app/Contents/Frameworks/
+install_name_tool -change @rpath/Sparkle.framework/Versions/A/Sparkle @executable_path/../Frameworks/Sparkle.framework/Versions/A/Sparkle ./OBS.app/Contents/MacOS/obs
# Copy Chromium embedded framework to app Frameworks directory
hr "Copying Chromium Embedded Framework.framework"
sudo mkdir -p OBS.app/Contents/Frameworks
sudo cp -r ../../cef_binary_${CEF_BUILD_VERSION}_macosx64/Release/Chromium\ Embedded\ Framework.framework OBS.app/Contents/Frameworks/
-sudo install_name_tool -change \
- @rpath/Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
- ../../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
- OBS.app/Contents/Resources/obs-plugins/obs-browser.so
-sudo install_name_tool -change \
- @executable_path/../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
- ../../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
- OBS.app/Contents/Resources/obs-plugins/obs-browser.so
-sudo install_name_tool -change \
- @rpath/Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
- ../../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
- OBS.app/Contents/Resources/obs-plugins/obs-browser-page
-sudo install_name_tool -change \
- @executable_path/../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
- ../../Frameworks/Chromium\ Embedded\ Framework.framework/Chromium\ Embedded\ Framework \
- OBS.app/Contents/Resources/obs-plugins/obs-browser-page
-
-# Package app
-hr "Generating .pkg"
-packagesbuild ../CI/install/osx/CMakeLists.pkgproj
+
+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
+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
+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
+
+cp ../CI/install/osx/OBSPublicDSAKey.pem OBS.app/Contents/Resources
+
+# edit plist
+plutil -insert CFBundleVersion -string $GIT_TAG ./OBS.app/Contents/Info.plist
+plutil -insert CFBundleShortVersionString -string $GIT_TAG ./OBS.app/Contents/Info.plist
+plutil -insert OBSFeedsURL -string https://obsproject.com/osx_update/feeds.xml ./OBS.app/Contents/Info.plist
+plutil -insert SUFeedURL -string https://obsproject.com/osx_update/stable/updates.xml ./OBS.app/Contents/Info.plist
+plutil -insert SUPublicDSAKeyFile -string OBSPublicDSAKey.pem ./OBS.app/Contents/Info.plist
+
+dmgbuild -s ../CI/install/osx/settings.json "OBS" obs.dmg
if [ -v "$TRAVIS" ]; then
# Signing stuff
security import ./Certificates.p12 -k build.keychain -T /usr/bin/productsign -P ""
# macOS 10.12+
security set-key-partition-list -S apple-tool:,apple: -s -k mysecretpassword build.keychain
- hr "Signing Package"
- productsign --sign 2MMRE5MTB8 ./OBS.pkg ./$FILENAME
-else
- cp ./OBS.pkg ./$FILENAME
fi
+cp ./OBS.dmg ./$FILENAME
+
# Move to the folder that travis uses to upload artifacts from
hr "Moving package to nightly folder for distribution"
mkdir ../nightly
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
#!/bin/sh
set -ex
-sudo add-apt-repository ppa:jonathonf/ffmpeg-3 -y
curl -L https://packagecloud.io/github/git-lfs/gpgkey | sudo apt-key add -
# gets us newer clang
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
/bin/bash -c "sudo xcode-select -s /Applications/Xcode_9.4.1.app/Contents/Developer"
fi
+git fetch origin --tags
+
# Leave obs-studio folder
cd ../
brew update
#Base OBS Deps and ccache
-brew install jack speexdsp ccache mbedtls clang-format
+brew install jack speexdsp ccache mbedtls clang-format freetype fdk-aac
brew install https://gist.githubusercontent.com/DDRBoxman/b3956fab6073335a4bf151db0dcbd4ad/raw/ed1342a8a86793ea8c10d8b4d712a654da121ace/qt.rb
brew install https://gist.githubusercontent.com/DDRBoxman/4cada55c51803a2f963fa40ce55c9d3e/raw/572c67e908bfbc1bcb8c476ea77ea3935133f5b5/swig.rb
+pip install dmgbuild
+
export PATH=/usr/local/opt/ccache/libexec:$PATH
ccache -s || echo "CCache is not available."
obs-studio-24.0.5.tar.xz/CI/install/osx/Info.plist
Added
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleIconFile</key>
+ <string>obs.icns</string>
+ <key>CFBundleName</key>
+ <string>OBS</string>
+ <key>CFBundleGetInfoString</key>
+ <string>OBS - Free and Open Source Streaming/Recording Software</string>
+ <key>CFBundleExecutable</key>
+ <string>OBS</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.obsproject.obs-studio</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.8.5</string>
+ <key>NSHighResolutionCapable</key>
+ <true/>
+ <key>LSAppNapIsDisabled</key>
+ <true/>
+ <key>NSCameraUsageDescription</key>
+ <string>OBS needs to access the camera to enable camera sources to work.</string>
+ <key>NSMicrophoneUsageDescription</key>
+ <string>OBS needs to access the microphone to enable audio input.</string>
+</dict>
+</plist>
obs-studio-24.0.5.tar.xz/CI/install/osx/background.pxd
Added
+(directory)
obs-studio-24.0.5.tar.xz/CI/install/osx/background.pxd/QuickLook
Added
+(directory)
obs-studio-24.0.5.tar.xz/CI/install/osx/background.pxd/data
Added
+(directory)
obs-studio-24.0.5.tar.xz/CI/install/osx/buildDMG
Added
+dmgbuild -s ./settings.json "OBS" obs.dmg
obs-studio-24.0.5.tar.xz/CI/install/osx/makeRetinaBG
Added
+tiffutil -cathidpicheck background.png background@2x.png -out background.tiff
obs-studio-24.0.5.tar.xz/CI/install/osx/packageApp.sh
Added
+rm -rf ./OBS.app
+
+mkdir OBS.app
+mkdir OBS.app/Contents
+mkdir OBS.app/Contents/MacOS
+mkdir OBS.app/Contents/Plugins
+mkdir OBS.app/Contents/Resources
+
+cp -r rundir/RelWithDebInfo/bin/ ./OBS.app/Contents/MacOS
+cp -r rundir/RelWithDebInfo/data ./OBS.app/Contents/Resources
+cp ../CI/install/osx/obs.icns ./OBS.app/Contents/Resources
+cp -r rundir/RelWithDebInfo/obs-plugins/ ./OBS.app/Contents/Plugins
+cp ../CI/install/osx/Info.plist ./OBS.app/Contents
+
+../CI/install/osx/dylibBundler -b -cd -d ./OBS.app/Contents/Frameworks -p @executable_path/../Frameworks/ \
+-s ./OBS.app/Contents/MacOS \
+-s /usr/local/opt/mbedtls/lib/ \
+-x ./OBS.app/Contents/Plugins/coreaudio-encoder.so \
+-x ./OBS.app/Contents/Plugins/decklink-ouput-ui.so \
+-x ./OBS.app/Contents/Plugins/frontend-tools.so \
+-x ./OBS.app/Contents/Plugins/image-source.so \
+-x ./OBS.app/Contents/Plugins/linux-jack.so \
+-x ./OBS.app/Contents/Plugins/mac-avcapture.so \
+-x ./OBS.app/Contents/Plugins/mac-capture.so \
+-x ./OBS.app/Contents/Plugins/mac-decklink.so \
+-x ./OBS.app/Contents/Plugins/mac-syphon.so \
+-x ./OBS.app/Contents/Plugins/mac-vth264.so \
+-x ./OBS.app/Contents/Plugins/obs-browser.so \
+-x ./OBS.app/Contents/Plugins/obs-browser-page \
+-x ./OBS.app/Contents/Plugins/obs-ffmpeg.so \
+-x ./OBS.app/Contents/Plugins/obs-filters.so \
+-x ./OBS.app/Contents/Plugins/obs-transitions.so \
+-x ./OBS.app/Contents/Plugins/obs-vst.so \
+-x ./OBS.app/Contents/Plugins/rtmp-services.so \
+-x ./OBS.app/Contents/MacOS/obs \
+-x ./OBS.app/Contents/MacOS/obs-ffmpeg-mux \
+-x ./OBS.app/Contents/MacOS/obslua.so \
+-x ./OBS.app/Contents/MacOS/_obspython.so \
+-x ./OBS.app/Contents/Plugins/obs-x264.so \
+-x ./OBS.app/Contents/Plugins/text-freetype2.so \
+-x ./OBS.app/Contents/Plugins/obs-libfdk.so
+# -x ./OBS.app/Contents/Plugins/obs-outputs.so \
+
+/usr/local/Cellar/qt/5.10.1/bin/macdeployqt ./OBS.app
+
+mv ./OBS.app/Contents/MacOS/libobs-opengl.so ./OBS.app/Contents/Frameworks
+
+# put qt network in here becasuse streamdeck uses it
+cp -r /usr/local/opt/qt/lib/QtNetwork.framework ./OBS.app/Contents/Frameworks
+chmod +w ./OBS.app/Contents/Frameworks/QtNetwork.framework/Versions/5/QtNetwork
+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
+
+# decklink ui qt
+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
+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
+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
+
+# frontend tools qt
+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
+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
+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
+
+# vst qt
+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
+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
+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
+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
obs-studio-24.0.5.tar.xz/CI/install/osx/settings.json
Added
+{
+ "title": "OBS",
+ "background": "../CI/install/osx/background.tiff",
+ "format": "UDZO",
+ "compression-level": 9,
+ "window": { "position": { "x": 100, "y": 100 },
+ "size": { "width": 540, "height": 380 } },
+ "contents": [
+ { "x": 120, "y": 180, "type": "file",
+ "path": "./OBS.app" },
+ { "x": 420, "y": 180, "type": "link", "path": "/Applications" }
+ ]
+}
obs-studio-24.0.3.tar.xz/UI/CMakeLists.txt -> obs-studio-24.0.5.tar.xz/UI/CMakeLists.txt
Changed
target_link_libraries(obs
Qt5::MacExtras)
set_target_properties(obs PROPERTIES LINK_FLAGS "-pagezero_size 10000 -image_base 100000000")
- set_property(
- TARGET obs
- APPEND
- PROPERTY INSTALL_RPATH
- "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/"
- "/Library/Frameworks/Python.framework/Versions/3.6/lib/"
- "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/"
- )
endif()
define_graphic_modules(obs)
obs-studio-24.0.3.tar.xz/UI/auth-twitch.cpp -> obs-studio-24.0.5.tar.xz/UI/auth-twitch.cpp
Changed
chat->SetWidget(browser);
cef->add_force_popup_url(moderation_tools_url, chat.data());
- script = bttv_script;
+ script = "localStorage.setItem('twilight.theme', 1);";
+ script += bttv_script;
script += ffz_script;
browser->setStartupScript(script);
obs-studio-24.0.3.tar.xz/UI/forms/OBSBasicSettings.ui -> obs-studio-24.0.5.tar.xz/UI/forms/OBSBasicSettings.ui
Changed
<item row="0" column="1">
<widget class="QComboBox" name="sampleRate">
<property name="currentText">
- <string notr="true">44.1khz</string>
+ <string notr="true">44.1 kHz</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
- <string>44.1khz</string>
+ <string>44.1 kHz</string>
</property>
</item>
<item>
<property name="text">
- <string>48khz</string>
+ <string>48 kHz</string>
</property>
</item>
</widget>
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
if (status >= Success && name != nullptr) {
std::string str(name);
windowTitle = str;
+ XFree(name);
+ } else {
+ XTextProperty xtp_new_name;
+ if (XGetWMName(disp(), w, &xtp_new_name) != 0 &&
+ xtp_new_name.value != nullptr) {
+ std::string str((const char *)xtp_new_name.value);
+ windowTitle = str;
+ XFree(xtp_new_name.value);
+ }
}
- XFree(name);
-
return windowTitle;
}
obs-studio-24.0.3.tar.xz/UI/platform-osx.mm -> obs-studio-24.0.5.tar.xz/UI/platform-osx.mm
Changed
using namespace std;
+bool isInBundle()
+{
+ NSRunningApplication *app = [NSRunningApplication currentApplication];
+ return [app bundleIdentifier] != nil;
+}
+
bool GetDataFilePath(const char *data, string &output)
{
- stringstream str;
- str << OBS_DATA_PATH "/obs-studio/" << data;
- output = str.str();
+ if (isInBundle()) {
+ NSRunningApplication *app =
+ [NSRunningApplication currentApplication];
+ NSURL *bundleURL = [app bundleURL];
+ NSString *path = [NSString
+ stringWithFormat:@"Contents/Resources/data/obs-studio/%@",
+ [NSString stringWithUTF8String:data]];
+ NSURL *dataURL = [bundleURL URLByAppendingPathComponent:path];
+ output = [[dataURL path] UTF8String];
+ } else {
+ stringstream str;
+ str << OBS_DATA_PATH "/obs-studio/" << data;
+ output = str.str();
+ }
+
return !access(output.c_str(), R_OK);
}
obs-studio-24.0.3.tar.xz/UI/properties-view.cpp -> obs-studio-24.0.5.tar.xz/UI/properties-view.cpp
Changed
break;
case OBS_PROPERTY_GROUP:
GroupChanged(setting);
- return;
+ break;
}
if (view->callback && !view->deferUpdate)
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
#ifdef BROWSER_AVAILABLE
std::string service = QT_TO_UTF8(ui->service->currentText());
+ OAuth::DeleteCookies(service);
+
auth = OAuthStreamKey::Login(this, service);
if (!!auth)
OnAuthConnected();
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
const char *name = obs_source_get_name(source);
setWindowTitle(QTStr("Basic.InteractionWindow").arg(QT_UTF8(name)));
+ Qt::WindowFlags flags = windowFlags();
+ Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint;
+ setWindowFlags(flags & (~helpFlag));
+
auto addDrawCallback = [this]() {
obs_display_add_draw_callback(ui->preview->GetDisplay(),
OBSBasicInteraction::DrawPreview,
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
} else if (videoEncoder == SIMPLE_ENCODER_NVENC) {
UpdateRecordingSettings_nvenc(crf);
}
+ UpdateRecordingAudioSettings();
}
inline void SimpleOutput::SetupOutputs()
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
return found;
}
+static bool GetUnusedSceneCollectionFile(std::string &name, std::string &file)
+{
+ char path[512];
+ size_t len;
+ int ret;
+
+ if (!GetFileSafeName(name.c_str(), file)) {
+ blog(LOG_WARNING, "Failed to create safe file name for '%s'",
+ name.c_str());
+ return false;
+ }
+
+ ret = GetConfigPath(path, sizeof(path), "obs-studio/basic/scenes/");
+ if (ret <= 0) {
+ blog(LOG_WARNING, "Failed to get scene collection config path");
+ return false;
+ }
+
+ len = file.size();
+ file.insert(0, path);
+
+ if (!GetClosestUnusedFileName(file, "json")) {
+ blog(LOG_WARNING, "Failed to get closest file name for %s",
+ file.c_str());
+ return false;
+ }
+
+ file.erase(file.size() - 5, 5);
+ file.erase(0, file.size() - len);
+ return true;
+}
+
static bool GetSceneCollectionName(QWidget *parent, std::string &name,
std::string &file,
const char *oldName = nullptr)
bool rename = oldName != nullptr;
const char *title;
const char *text;
- char path[512];
- size_t len;
- int ret;
if (rename) {
title = Str("Basic.Main.RenameSceneCollection.Title");
break;
}
- if (!GetFileSafeName(name.c_str(), file)) {
- blog(LOG_WARNING, "Failed to create safe file name for '%s'",
- name.c_str());
- return false;
- }
-
- ret = GetConfigPath(path, sizeof(path), "obs-studio/basic/scenes/");
- if (ret <= 0) {
- blog(LOG_WARNING, "Failed to get scene collection config path");
- return false;
- }
-
- len = file.size();
- file.insert(0, path);
-
- if (!GetClosestUnusedFileName(file, "json")) {
- blog(LOG_WARNING, "Failed to get closest file name for %s",
- file.c_str());
+ if (!GetUnusedSceneCollectionFile(name, file)) {
return false;
}
- file.erase(file.size() - 5, 5);
- file.erase(0, file.size() - len);
return true;
}
name = QT_TO_UTF8(qname);
if (SceneCollectionExists(name.c_str()))
return false;
+
+ if (!GetUnusedSceneCollectionFile(name, file)) {
+ return false;
+ }
}
SaveProjectNow();
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
#ifdef BROWSER_AVAILABLE
std::string service = QT_TO_UTF8(ui->service->currentText());
+ OAuth::DeleteCookies(service);
+
auth = OAuthStreamKey::Login(this, service);
if (!!auth)
OnAuthConnected();
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
const char *str;
if (sampleRate == 48000)
- str = "48khz";
+ str = "48 kHz";
else
- str = "44.1khz";
+ str = "44.1 kHz";
int sampleRateIdx = ui->sampleRate->findText(str);
if (sampleRateIdx != -1)
}
int sampleRate = 44100;
- if (sampleRateStr == "48khz")
+ if (sampleRateStr == "48 kHz")
sampleRate = 48000;
if (WidgetChanged(ui->sampleRate))
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
dock->SetWidget(browser);
+ /* Add support for Twitch Dashboard panels */
+ if (url.contains("twitch.tv/popout") &&
+ url.contains("dashboard/live")) {
+ QRegularExpression re("twitch.tv\/popout\/([^/]+)\/");
+ QRegularExpressionMatch match = re.match(url);
+ QString username = match.captured(1);
+ if (username.length() > 0) {
+ std::string script;
+ script =
+ "Object.defineProperty(document, 'referrer', { get: () => '";
+ script += "https://twitch.tv/";
+ script += QT_TO_UTF8(username);
+ script += "/dashboard/live";
+ script += "'});";
+ browser->setStartupScript(script);
+ }
+ }
+
addDockWidget(Qt::RightDockWidgetArea, dock);
if (firstCreate) {
obs-studio-24.0.3.tar.xz/UI/window-projector.cpp -> obs-studio-24.0.5.tar.xz/UI/window-projector.cpp
Changed
source = curSource;
window->source = source;
}
+ } else if (window->type == ProjectorType::Preview &&
+ !main->IsPreviewProgramMode()) {
+ window->source = nullptr;
}
if (source)
obs-studio-24.0.3.tar.xz/cmake/Modules/ObsHelpers.cmake -> obs-studio-24.0.5.tar.xz/cmake/Modules/ObsHelpers.cmake
Changed
set(OBS_INSTALL_PREFIX "")
set(OBS_RELATIVE_PREFIX "../")
- set(OBS_SCRIPT_PLUGIN_DESTINATION "${OBS_DATA_DESTINATION}/obs-scripting/${_lib_suffix}bit")
+ set(OBS_SCRIPT_PLUGIN_DESTINATION "${OBS_DATA_DESTINATION}/obs-scripting")
else()
set(OBS_EXECUTABLE_DESTINATION "bin/${_lib_suffix}bit")
set(OBS_EXECUTABLE32_DESTINATION "bin/32bit")
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
int ret = av_read_frame(media->fmt, &pkt);
if (ret < 0) {
- if (ret != AVERROR_EOF)
+ if (ret != AVERROR_EOF && ret != AVERROR_EXIT)
blog(LOG_WARNING, "MP: av_read_frame failed: %s (%d)",
av_err2str(ret), ret);
return ret;
while (!mp_media_ready_to_start(m)) {
if (!m->eof) {
int ret = mp_media_next_packet(m);
- if (ret == AVERROR_EOF)
+ if (ret == AVERROR_EOF || ret == AVERROR_EXIT)
m->eof = true;
else if (ret < 0)
return false;
av_dict_set_int(&opts, "buffer_size", m->buffering, 0);
m->fmt = avformat_alloc_context();
- m->fmt->interrupt_callback.callback = interrupt_callback;
- m->fmt->interrupt_callback.opaque = m;
+ if (!m->is_local_file) {
+ m->fmt->interrupt_callback.callback = interrupt_callback;
+ m->fmt->interrupt_callback.opaque = m;
+ }
int ret = avformat_open_input(&m->fmt, m->path, format,
opts ? &opts : NULL);
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
w32-pthreads)
endif()
+if(APPLE)
+ set(obs-scripting_PLATFORM_DEPS
+ objc)
+endif()
+
option(DISABLE_LUA "Disable Lua scripting support" OFF)
option(DISABLE_PYTHON "Disable Python scripting support" OFF)
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
for val in pairs(package.preload) do\n\
package.preload[val] = nil\n\
end\n\
-package.cpath = package.cpath .. \";\" .. \"%s\" .. \"/?." SO_EXT "\"\n\
+package.cpath = package.cpath .. \";\" .. \"%s/Contents/MacOS/?.so\" .. \";\" .. \"%s\" .. \"/?." SO_EXT
+ "\"\n\
require \"obslua\"\n";
static const char *get_script_path_func = "\
/* ---------------------------------------------- */
/* Initialize Lua startup script */
- dstr_printf(&tmp, startup_script_template, SCRIPT_DIR);
+ char *bundlePath = "./";
+
+#ifdef __APPLE__
+ Class nsRunningApplication = objc_lookUpClass("NSRunningApplication");
+ SEL currentAppSel = sel_getUid("currentApplication");
+
+ typedef id (*running_app_func)(Class, SEL);
+ running_app_func operatingSystemName = (running_app_func)objc_msgSend;
+ id app = operatingSystemName(nsRunningApplication, currentAppSel);
+
+ typedef id (*bundle_url_func)(id, SEL);
+ bundle_url_func bundleURL = (bundle_url_func)objc_msgSend;
+ id url = bundleURL(app, sel_getUid("bundleURL"));
+
+ typedef id (*url_path_func)(id, SEL);
+ url_path_func urlPath = (url_path_func)objc_msgSend;
+
+ id path = urlPath(url, sel_getUid("path"));
+
+ typedef id (*string_func)(id, SEL);
+ string_func utf8String = (string_func)objc_msgSend;
+ bundlePath = (char *)utf8String(path, sel_registerName("UTF8String"));
+#endif
+
+ dstr_printf(&tmp, startup_script_template, bundlePath, SCRIPT_DIR);
startup_script = tmp.array;
dstr_free(&dep_paths);
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
#define SO_EXT ".dylib"
#endif
+#ifdef __APPLE__
+#define PYTHON_LIB_SUBDIR "lib/"
+#else
+#define PYTHON_LIB_SUBDIR ""
+#endif
+
bool import_python(const char *python_path)
{
struct dstr lib_path;
dstr_init_copy(&lib_path, python_path);
dstr_replace(&lib_path, "\\", "/");
if (!dstr_is_empty(&lib_path)) {
- dstr_cat(&lib_path, "/");
+ dstr_cat(&lib_path, "/" PYTHON_LIB_SUBDIR);
}
dstr_cat(&lib_path, PYTHON_LIB SO_EXT);
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
add_to_python_path(SCRIPT_DIR);
+#if __APPLE__
+ char *exec_path = os_get_executable_path_ptr("");
+ if (exec_path)
+ add_to_python_path(exec_path);
+ bfree(exec_path);
+#endif
+
py_obspython = PyImport_ImportModule("obspython");
bool success = !py_error();
if (!success) {
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
else()
SWIG_ADD_MODULE(obspython python obspython.i ../cstrcache.cpp ../cstrcache.h)
endif()
-SWIG_LINK_LIBRARIES(obspython obs-scripting libobs ${PYTHON_LIBRARIES})
+
+IF(APPLE)
+ SWIG_LINK_LIBRARIES(obspython obs-scripting libobs)
+ELSE()
+ SWIG_LINK_LIBRARIES(obspython obs-scripting libobs ${PYTHON_LIBRARIES})
+ENDIF()
function(install_plugin_bin_swig target additional_target)
if(APPLE)
PREFIX "")
if (APPLE)
- set_property(
- TARGET ${additional_target}
- APPEND
- PROPERTY INSTALL_RPATH
- "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/"
- "/Library/Frameworks/Python.framework/Versions/3.6/lib/"
- "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/"
- )
+ SET_TARGET_PROPERTIES(${additional_target} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
endif()
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/obspython.py"
obs-studio-24.0.3.tar.xz/formatcode.sh -> obs-studio-24.0.5.tar.xz/formatcode.sh
Changed
CLANG_FORMAT=clang-format
fi
-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' \
+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 ./plugins/enc-amf \
+-o -path ./plugins/mac-syphon/syphon-framework \
+-o -path ./plugins/obs-outputs/ftl-sdk \
+-o -path ./plugins/obs-vst \
+-o -path ./build \) -prune -type f -o -name '*.h' -or -name '*.hpp' -or -name '*.m' -or -name '*.mm' -or -name '*.c' -or -name '*.cpp' \
| xargs -I{} -P ${NPROC} ${CLANG_FORMAT} -i -style=file -fallback-style=none {}
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
if (FAILED(hr))
throw HRError("Failed to create vertex shader", hr);
- hr = dev->CreateInputLayout(layoutData.data(), (UINT)layoutData.size(),
- data.data(), data.size(), &layout);
- if (FAILED(hr))
- throw HRError("Failed to create input layout", hr);
+ const UINT layoutSize = (UINT)layoutData.size();
+ if (layoutSize > 0) {
+ hr = dev->CreateInputLayout(layoutData.data(), layoutSize,
+ data.data(), data.size(), &layout);
+ if (FAILED(hr))
+ throw HRError("Failed to create input layout", hr);
+ }
if (constantSize) {
hr = dev->CreateBuffer(&bd, NULL, &constants);
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
}
}
+static bool GetMonitorTarget(const MONITORINFOEX &info,
+ DISPLAYCONFIG_TARGET_DEVICE_NAME &target)
+{
+ bool found = false;
+
+ UINT32 numPath, numMode;
+ if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPath,
+ &numMode) == ERROR_SUCCESS) {
+ std::vector<DISPLAYCONFIG_PATH_INFO> paths(numPath);
+ std::vector<DISPLAYCONFIG_MODE_INFO> modes(numMode);
+ if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPath,
+ paths.data(), &numMode, modes.data(),
+ nullptr) == ERROR_SUCCESS) {
+ paths.resize(numPath);
+ for (size_t i = 0; i < numPath; ++i) {
+ const DISPLAYCONFIG_PATH_INFO &path = paths[i];
+
+ DISPLAYCONFIG_SOURCE_DEVICE_NAME
+ source;
+ source.header.type =
+ DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
+ source.header.size = sizeof(source);
+ source.header.adapterId =
+ path.sourceInfo.adapterId;
+ source.header.id = path.sourceInfo.id;
+ if (DisplayConfigGetDeviceInfo(
+ &source.header) == ERROR_SUCCESS &&
+ wcscmp(info.szDevice,
+ source.viewGdiDeviceName) == 0) {
+ target.header.type =
+ DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
+ target.header.size = sizeof(target);
+ target.header.adapterId =
+ path.sourceInfo.adapterId;
+ target.header.id = path.targetInfo.id;
+ found = DisplayConfigGetDeviceInfo(
+ &target.header) ==
+ ERROR_SUCCESS;
+ break;
+ }
+ }
+ }
+ }
+
+ return found;
+}
+
static inline void LogAdapterMonitors(IDXGIAdapter1 *adapter)
{
UINT i;
if (FAILED(output->GetDesc(&desc)))
continue;
- RECT rect = desc.DesktopCoordinates;
+ unsigned refresh = 0;
+
+ bool target_found = false;
+ DISPLAYCONFIG_TARGET_DEVICE_NAME target;
+
+ MONITORINFOEX info;
+ info.cbSize = sizeof(info);
+ if (GetMonitorInfo(desc.Monitor, &info)) {
+ target_found = GetMonitorTarget(info, target);
+
+ DEVMODE mode;
+ mode.dmSize = sizeof(mode);
+ mode.dmDriverExtra = 0;
+ if (EnumDisplaySettings(info.szDevice,
+ ENUM_CURRENT_SETTINGS, &mode)) {
+ refresh = mode.dmDisplayFrequency;
+ }
+ }
+
+ if (!target_found) {
+ target.monitorFriendlyDeviceName[0] = 0;
+ }
+
+ const RECT &rect = desc.DesktopCoordinates;
blog(LOG_INFO,
"\t output %u: "
"pos={%d, %d}, "
"size={%d, %d}, "
- "attached=%s",
+ "attached=%s, "
+ "refresh=%u, "
+ "name=%ls",
i, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top,
- desc.AttachedToDesktop ? "true" : "false");
+ desc.AttachedToDesktop ? "true" : "false", refresh,
+ target.monitorFriendlyDeviceName);
}
}
blog(LOG_INFO, "\t Shared VRAM: %u",
desc.SharedSystemMemory);
+ /* driver version */
+ LARGE_INTEGER umd;
+ hr = adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice),
+ &umd);
+ if (SUCCEEDED(hr)) {
+ const uint64_t version = umd.QuadPart;
+ const uint16_t aa = (version >> 48) & 0xffff;
+ const uint16_t bb = (version >> 32) & 0xffff;
+ const uint16_t ccccc = (version >> 16) & 0xffff;
+ const uint16_t ddddd = version & 0xffff;
+ blog(LOG_INFO,
+ "\t Driver Version: %" PRIu16 ".%" PRIu16
+ ".%" PRIu16 ".%" PRIu16,
+ aa, bb, ccccc, ddddd);
+ } else {
+ blog(LOG_INFO, "\t Driver Version: Unknown (0x%X)",
+ (unsigned)hr);
+ }
+
LogAdapterMonitors(adapter);
}
}
obs-studio-24.0.3.tar.xz/libobs/CMakeLists.txt -> obs-studio-24.0.5.tar.xz/libobs/CMakeLists.txt
Changed
endif()
elseif(APPLE)
set(libobs_PLATFORM_SOURCES
- obs-cocoa.c
+ obs-cocoa.m
util/threading-posix.c
util/pipe-posix.c
util/platform-nix.c
obs-studio-24.0.5.tar.xz/libobs/obs-cocoa.m
Added
+/******************************************************************************
+ Copyright (C) 2013 by Ruwen Hahn <palana@stunned.de>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+******************************************************************************/
+
+#include "util/platform.h"
+#include "util/dstr.h"
+#include "obs.h"
+#include "obs-internal.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <objc/objc.h>
+#include <Carbon/Carbon.h>
+#include <IOKit/hid/IOHIDDevice.h>
+#include <IOKit/hid/IOHIDManager.h>
+
+#import <AppKit/AppKit.h>
+
+bool is_in_bundle()
+{
+ NSRunningApplication *app = [NSRunningApplication currentApplication];
+ return [app bundleIdentifier] != nil;
+}
+
+const char *get_module_extension(void)
+{
+ return ".so";
+}
+
+static const char *module_bin[] = {
+ "../obs-plugins",
+ OBS_INSTALL_PREFIX "obs-plugins",
+};
+
+static const char *module_data[] = {
+ "../data/obs-plugins/%module%",
+ OBS_INSTALL_DATA_PATH "obs-plugins/%module%",
+};
+
+static const int module_patterns_size =
+ sizeof(module_bin) / sizeof(module_bin[0]);
+
+void add_default_module_paths(void)
+{
+ for (int i = 0; i < module_patterns_size; i++)
+ obs_add_module_path(module_bin[i], module_data[i]);
+
+ if (is_in_bundle()) {
+ NSRunningApplication *app =
+ [NSRunningApplication currentApplication];
+ NSURL *bundleURL = [app bundleURL];
+ NSURL *pluginsURL = [bundleURL
+ URLByAppendingPathComponent:@"Contents/Plugins"];
+ NSURL *dataURL = [bundleURL
+ URLByAppendingPathComponent:
+ @"Contents/Resources/data/obs-plugins/%module%"];
+
+ const char *binPath = [[pluginsURL path]
+ cStringUsingEncoding:NSUTF8StringEncoding];
+ const char *dataPath = [[dataURL path]
+ cStringUsingEncoding:NSUTF8StringEncoding];
+
+ obs_add_module_path(binPath, dataPath);
+ }
+}
+
+char *find_libobs_data_file(const char *file)
+{
+ struct dstr path;
+
+ if (is_in_bundle()) {
+ NSRunningApplication *app =
+ [NSRunningApplication currentApplication];
+ NSURL *bundleURL = [app bundleURL];
+ NSURL *libobsDataURL =
+ [bundleURL URLByAppendingPathComponent:
+ @"Contents/Resources/data/libobs/"];
+ const char *libobsDataPath = [[libobsDataURL path]
+ cStringUsingEncoding:NSUTF8StringEncoding];
+ dstr_init_copy(&path, libobsDataPath);
+ dstr_cat(&path, "/");
+ } else {
+ dstr_init_copy(&path, OBS_INSTALL_DATA_PATH "/libobs/");
+ }
+
+ dstr_cat(&path, file);
+ return path.array;
+}
+
+static void log_processor_name(void)
+{
+ char *name = NULL;
+ size_t size;
+ int ret;
+
+ ret = sysctlbyname("machdep.cpu.brand_string", NULL, &size, NULL, 0);
+ if (ret != 0)
+ return;
+
+ name = malloc(size);
+
+ ret = sysctlbyname("machdep.cpu.brand_string", name, &size, NULL, 0);
+ if (ret == 0)
+ blog(LOG_INFO, "CPU Name: %s", name);
+
+ free(name);
+}
+
+static void log_processor_speed(void)
+{
+ size_t size;
+ long long freq;
+ int ret;
+
+ size = sizeof(freq);
+ ret = sysctlbyname("hw.cpufrequency", &freq, &size, NULL, 0);
+ if (ret == 0)
+ blog(LOG_INFO, "CPU Speed: %lldMHz", freq / 1000000);
+}
+
+static void log_processor_cores(void)
+{
+ blog(LOG_INFO, "Physical Cores: %d, Logical Cores: %d",
+ os_get_physical_cores(), os_get_logical_cores());
+}
+
+static void log_available_memory(void)
+{
+ size_t size;
+ long long memory_available;
+ int ret;
+
+ size = sizeof(memory_available);
+ ret = sysctlbyname("hw.memsize", &memory_available, &size, NULL, 0);
+ if (ret == 0)
+ blog(LOG_INFO, "Physical Memory: %lldMB Total",
+ memory_available / 1024 / 1024);
+}
+
+static void log_os_name(id pi, SEL UTF8StringSel)
+{
+ typedef int (*os_func)(id, SEL);
+ os_func operatingSystem = (os_func)objc_msgSend;
+ unsigned long os_id = (unsigned long)operatingSystem(
+ pi, sel_registerName("operatingSystem"));
+
+ typedef id (*os_name_func)(id, SEL);
+ os_name_func operatingSystemName = (os_name_func)objc_msgSend;
+ id os = operatingSystemName(pi,
+ sel_registerName("operatingSystemName"));
+ typedef const char *(*utf8_func)(id, SEL);
+ utf8_func UTF8String = (utf8_func)objc_msgSend;
+ const char *name = UTF8String(os, UTF8StringSel);
+
+ if (os_id == 5 /*NSMACHOperatingSystem*/) {
+ blog(LOG_INFO, "OS Name: Mac OS X (%s)", name);
+ return;
+ }
+
+ blog(LOG_INFO, "OS Name: %s", name ? name : "Unknown");
+}
+
+static void log_os_version(id pi, SEL UTF8StringSel)
+{
+ typedef id (*version_func)(id, SEL);
+ version_func operatingSystemVersionString = (version_func)objc_msgSend;
+ id vs = operatingSystemVersionString(
+ pi, sel_registerName("operatingSystemVersionString"));
+ typedef const char *(*utf8_func)(id, SEL);
+ utf8_func UTF8String = (utf8_func)objc_msgSend;
+ const char *version = UTF8String(vs, UTF8StringSel);
+
+ blog(LOG_INFO, "OS Version: %s", version ? version : "Unknown");
+}
+
+static void log_os(void)
+{
+ Class NSProcessInfo = objc_getClass("NSProcessInfo");
+ typedef id (*func)(id, SEL);
+ func processInfo = (func)objc_msgSend;
+ id pi = processInfo((id)NSProcessInfo, sel_registerName("processInfo"));
+
+ SEL UTF8String = sel_registerName("UTF8String");
+
+ log_os_name(pi, UTF8String);
+ log_os_version(pi, UTF8String);
+}
+
+static void log_kernel_version(void)
+{
+ char kernel_version[1024];
+ size_t size = sizeof(kernel_version);
+ int ret;
+
+ ret = sysctlbyname("kern.osrelease", kernel_version, &size, NULL, 0);
+ if (ret == 0)
+ blog(LOG_INFO, "Kernel Version: %s", kernel_version);
+}
+
+void log_system_info(void)
+{
+ log_processor_name();
+ log_processor_speed();
+ log_processor_cores();
+ log_available_memory();
+ log_os();
+ log_kernel_version();
+}
+
+static bool dstr_from_cfstring(struct dstr *str, CFStringRef ref)
+{
+ CFIndex length = CFStringGetLength(ref);
+ CFIndex max_size = CFStringGetMaximumSizeForEncoding(
+ length, kCFStringEncodingUTF8);
+ dstr_reserve(str, max_size);
+
+ if (!CFStringGetCString(ref, str->array, max_size,
+ kCFStringEncodingUTF8))
+ return false;
+
+ str->len = strlen(str->array);
+ return true;
+}
+
+struct obs_hotkeys_platform {
+ volatile long refs;
+ TISInputSourceRef tis;
+ CFDataRef layout_data;
+ UCKeyboardLayout *layout;
+ IOHIDManagerRef manager;
+ DARRAY(IOHIDElementRef) keys[OBS_KEY_LAST_VALUE];
+};
+
+static void hotkeys_retain(struct obs_hotkeys_platform *plat)
+{
+ os_atomic_inc_long(&plat->refs);
+}
+
+static inline void free_hotkeys_platform(obs_hotkeys_platform_t *plat);
+static void hotkeys_release(struct obs_hotkeys_platform *plat)
+{
+ if (os_atomic_dec_long(&plat->refs) == -1)
+ free_hotkeys_platform(plat);
+}
+
+#define INVALID_KEY 0xff
+
+int obs_key_to_virtual_key(obs_key_t code)
+{
+ switch (code) {
+ case OBS_KEY_A:
+ return kVK_ANSI_A;
+ case OBS_KEY_B:
+ return kVK_ANSI_B;
+ case OBS_KEY_C:
+ return kVK_ANSI_C;
+ case OBS_KEY_D:
+ return kVK_ANSI_D;
+ case OBS_KEY_E:
+ return kVK_ANSI_E;
+ case OBS_KEY_F:
+ return kVK_ANSI_F;
+ case OBS_KEY_G:
+ return kVK_ANSI_G;
+ case OBS_KEY_H:
+ return kVK_ANSI_H;
+ case OBS_KEY_I:
+ return kVK_ANSI_I;
+ case OBS_KEY_J:
+ return kVK_ANSI_J;
+ case OBS_KEY_K:
+ return kVK_ANSI_K;
+ case OBS_KEY_L:
+ return kVK_ANSI_L;
+ case OBS_KEY_M:
+ return kVK_ANSI_M;
+ case OBS_KEY_N:
+ return kVK_ANSI_N;
+ case OBS_KEY_O:
+ return kVK_ANSI_O;
+ case OBS_KEY_P:
+ return kVK_ANSI_P;
+ case OBS_KEY_Q:
+ return kVK_ANSI_Q;
+ case OBS_KEY_R:
+ return kVK_ANSI_R;
+ case OBS_KEY_S:
+ return kVK_ANSI_S;
+ case OBS_KEY_T:
+ return kVK_ANSI_T;
+ case OBS_KEY_U:
+ return kVK_ANSI_U;
+ case OBS_KEY_V:
+ return kVK_ANSI_V;
+ case OBS_KEY_W:
+ return kVK_ANSI_W;
+ case OBS_KEY_X:
+ return kVK_ANSI_X;
+ case OBS_KEY_Y:
+ return kVK_ANSI_Y;
+ case OBS_KEY_Z:
+ return kVK_ANSI_Z;
+
+ case OBS_KEY_1:
+ return kVK_ANSI_1;
+ case OBS_KEY_2:
+ return kVK_ANSI_2;
+ case OBS_KEY_3:
+ return kVK_ANSI_3;
+ case OBS_KEY_4:
+ return kVK_ANSI_4;
+ case OBS_KEY_5:
+ return kVK_ANSI_5;
+ case OBS_KEY_6:
+ return kVK_ANSI_6;
+ case OBS_KEY_7:
+ return kVK_ANSI_7;
+ case OBS_KEY_8:
+ return kVK_ANSI_8;
+ case OBS_KEY_9:
+ return kVK_ANSI_9;
+ case OBS_KEY_0:
+ return kVK_ANSI_0;
+
+ case OBS_KEY_RETURN:
+ return kVK_Return;
+ case OBS_KEY_ESCAPE:
+ return kVK_Escape;
+ case OBS_KEY_BACKSPACE:
+ return kVK_Delete;
+ case OBS_KEY_TAB:
+ return kVK_Tab;
+ case OBS_KEY_SPACE:
+ return kVK_Space;
+ case OBS_KEY_MINUS:
+ return kVK_ANSI_Minus;
+ case OBS_KEY_EQUAL:
+ return kVK_ANSI_Equal;
+ case OBS_KEY_BRACKETLEFT:
+ return kVK_ANSI_LeftBracket;
+ case OBS_KEY_BRACKETRIGHT:
+ return kVK_ANSI_RightBracket;
+ case OBS_KEY_BACKSLASH:
+ return kVK_ANSI_Backslash;
+ case OBS_KEY_SEMICOLON:
+ return kVK_ANSI_Semicolon;
+ case OBS_KEY_QUOTE:
+ return kVK_ANSI_Quote;
+ case OBS_KEY_DEAD_GRAVE:
+ return kVK_ANSI_Grave;
+ case OBS_KEY_COMMA:
+ return kVK_ANSI_Comma;
+ case OBS_KEY_PERIOD:
+ return kVK_ANSI_Period;
+ case OBS_KEY_SLASH:
+ return kVK_ANSI_Slash;
+ case OBS_KEY_CAPSLOCK:
+ return kVK_CapsLock;
+ case OBS_KEY_SECTION:
+ return kVK_ISO_Section;
+
+ case OBS_KEY_F1:
+ return kVK_F1;
+ case OBS_KEY_F2:
+ return kVK_F2;
+ case OBS_KEY_F3:
+ return kVK_F3;
+ case OBS_KEY_F4:
+ return kVK_F4;
+ case OBS_KEY_F5:
+ return kVK_F5;
+ case OBS_KEY_F6:
+ return kVK_F6;
+ case OBS_KEY_F7:
+ return kVK_F7;
+ case OBS_KEY_F8:
+ return kVK_F8;
+ case OBS_KEY_F9:
+ return kVK_F9;
+ case OBS_KEY_F10:
+ return kVK_F10;
+ case OBS_KEY_F11:
+ return kVK_F11;
+ case OBS_KEY_F12:
+ return kVK_F12;
+
+ case OBS_KEY_HELP:
+ return kVK_Help;
+ case OBS_KEY_HOME:
+ return kVK_Home;
+ case OBS_KEY_PAGEUP:
+ return kVK_PageUp;
+ case OBS_KEY_DELETE:
+ return kVK_ForwardDelete;
+ case OBS_KEY_END:
+ return kVK_End;
+ case OBS_KEY_PAGEDOWN:
+ return kVK_PageDown;
+
+ case OBS_KEY_RIGHT:
+ return kVK_RightArrow;
+ case OBS_KEY_LEFT:
+ return kVK_LeftArrow;
+ case OBS_KEY_DOWN:
+ return kVK_DownArrow;
+ case OBS_KEY_UP:
+ return kVK_UpArrow;
+
+ case OBS_KEY_CLEAR:
+ return kVK_ANSI_KeypadClear;
+ case OBS_KEY_NUMSLASH:
+ return kVK_ANSI_KeypadDivide;
+ case OBS_KEY_NUMASTERISK:
+ return kVK_ANSI_KeypadMultiply;
+ case OBS_KEY_NUMMINUS:
+ return kVK_ANSI_KeypadMinus;
+ case OBS_KEY_NUMPLUS:
+ return kVK_ANSI_KeypadPlus;
+ case OBS_KEY_ENTER:
+ return kVK_ANSI_KeypadEnter;
+
+ case OBS_KEY_NUM1:
+ return kVK_ANSI_Keypad1;
+ case OBS_KEY_NUM2:
+ return kVK_ANSI_Keypad2;
+ case OBS_KEY_NUM3:
+ return kVK_ANSI_Keypad3;
+ case OBS_KEY_NUM4:
+ return kVK_ANSI_Keypad4;
+ case OBS_KEY_NUM5:
+ return kVK_ANSI_Keypad5;
+ case OBS_KEY_NUM6:
+ return kVK_ANSI_Keypad6;
+ case OBS_KEY_NUM7:
+ return kVK_ANSI_Keypad7;
+ case OBS_KEY_NUM8:
+ return kVK_ANSI_Keypad8;
+ case OBS_KEY_NUM9:
+ return kVK_ANSI_Keypad9;
+ case OBS_KEY_NUM0:
+ return kVK_ANSI_Keypad0;
+
+ case OBS_KEY_NUMPERIOD:
+ return kVK_ANSI_KeypadDecimal;
+ case OBS_KEY_NUMEQUAL:
+ return kVK_ANSI_KeypadEquals;
+
+ case OBS_KEY_F13:
+ return kVK_F13;
+ case OBS_KEY_F14:
+ return kVK_F14;
+ case OBS_KEY_F15:
+ return kVK_F15;
+ case OBS_KEY_F16:
+ return kVK_F16;
+ case OBS_KEY_F17:
+ return kVK_F17;
+ case OBS_KEY_F18:
+ return kVK_F18;
+ case OBS_KEY_F19:
+ return kVK_F19;
+ case OBS_KEY_F20:
+ return kVK_F20;
+
+ case OBS_KEY_CONTROL:
+ return kVK_Control;
+ case OBS_KEY_SHIFT:
+ return kVK_Shift;
+ case OBS_KEY_ALT:
+ return kVK_Option;
+ case OBS_KEY_META:
+ return kVK_Command;
+ //case OBS_KEY_CONTROL: return kVK_RightControl;
+ //case OBS_KEY_SHIFT: return kVK_RightShift;
+ //case OBS_KEY_ALT: return kVK_RightOption;
+ //case OBS_KEY_META: return 0x36;
+
+ case OBS_KEY_NONE:
+ case OBS_KEY_LAST_VALUE:
+ default:
+ break;
+ }
+ return INVALID_KEY;
+}
+
+static bool localized_key_to_str(obs_key_t key, struct dstr *str)
+{
+#define MAP_KEY(k, s) \
+ case k: \
+ dstr_copy(str, obs_get_hotkey_translation(k, s)); \
+ return true
+
+#define MAP_BUTTON(i) \
+ case OBS_KEY_MOUSE##i: \
+ dstr_copy(str, obs_get_hotkey_translation(key, "Mouse " #i)); \
+ return true
+
+ switch (key) {
+ MAP_KEY(OBS_KEY_SPACE, "Space");
+ MAP_KEY(OBS_KEY_NUMEQUAL, "= (Keypad)");
+ MAP_KEY(OBS_KEY_NUMASTERISK, "* (Keypad)");
+ MAP_KEY(OBS_KEY_NUMPLUS, "+ (Keypad)");
+ MAP_KEY(OBS_KEY_NUMMINUS, "- (Keypad)");
+ MAP_KEY(OBS_KEY_NUMPERIOD, ". (Keypad)");
+ MAP_KEY(OBS_KEY_NUMSLASH, "/ (Keypad)");
+ MAP_KEY(OBS_KEY_NUM0, "0 (Keypad)");
+ MAP_KEY(OBS_KEY_NUM1, "1 (Keypad)");
+ MAP_KEY(OBS_KEY_NUM2, "2 (Keypad)");
+ MAP_KEY(OBS_KEY_NUM3, "3 (Keypad)");
+ MAP_KEY(OBS_KEY_NUM4, "4 (Keypad)");
+ MAP_KEY(OBS_KEY_NUM5, "5 (Keypad)");
+ MAP_KEY(OBS_KEY_NUM6, "6 (Keypad)");
+ MAP_KEY(OBS_KEY_NUM7, "7 (Keypad)");
+ MAP_KEY(OBS_KEY_NUM8, "8 (Keypad)");
+ MAP_KEY(OBS_KEY_NUM9, "9 (Keypad)");
+
+ MAP_BUTTON(1);
+ MAP_BUTTON(2);
+ MAP_BUTTON(3);
+ MAP_BUTTON(4);
+ MAP_BUTTON(5);
+ MAP_BUTTON(6);
+ MAP_BUTTON(7);
+ MAP_BUTTON(8);
+ MAP_BUTTON(9);
+ MAP_BUTTON(10);
+ MAP_BUTTON(11);
+ MAP_BUTTON(12);
+ MAP_BUTTON(13);
+ MAP_BUTTON(14);
+ MAP_BUTTON(15);
+ MAP_BUTTON(16);
+ MAP_BUTTON(17);
+ MAP_BUTTON(18);
+ MAP_BUTTON(19);
+ MAP_BUTTON(20);
+ MAP_BUTTON(21);
+ MAP_BUTTON(22);
+ MAP_BUTTON(23);
+ MAP_BUTTON(24);
+ MAP_BUTTON(25);
+ MAP_BUTTON(26);
+ MAP_BUTTON(27);
+ MAP_BUTTON(28);
+ MAP_BUTTON(29);
+ default:
+ break;
+ }
+#undef MAP_BUTTON
+#undef MAP_KEY
+
+ return false;
+}
+
+static bool code_to_str(int code, struct dstr *str)
+{
+#define MAP_GLYPH(c, g) \
+ case c: \
+ dstr_from_wcs(str, (wchar_t[]){g, 0}); \
+ return true
+#define MAP_STR(c, s) \
+ case c: \
+ dstr_copy(str, s); \
+ return true
+ switch (code) {
+ MAP_GLYPH(kVK_Return, 0x21A9);
+ MAP_GLYPH(kVK_Escape, 0x238B);
+ MAP_GLYPH(kVK_Delete, 0x232B);
+ MAP_GLYPH(kVK_Tab, 0x21e5);
+ MAP_GLYPH(kVK_CapsLock, 0x21EA);
+ MAP_GLYPH(kVK_ANSI_KeypadClear, 0x2327);
+ MAP_GLYPH(kVK_ANSI_KeypadEnter, 0x2305);
+ MAP_GLYPH(kVK_Help, 0x003F);
+ MAP_GLYPH(kVK_Home, 0x2196);
+ MAP_GLYPH(kVK_PageUp, 0x21de);
+ MAP_GLYPH(kVK_ForwardDelete, 0x2326);
+ MAP_GLYPH(kVK_End, 0x2198);
+ MAP_GLYPH(kVK_PageDown, 0x21df);
+
+ MAP_GLYPH(kVK_RightArrow, 0x2192);
+ MAP_GLYPH(kVK_LeftArrow, 0x2190);
+ MAP_GLYPH(kVK_DownArrow, 0x2193);
+ MAP_GLYPH(kVK_UpArrow, 0x2191);
+
+ MAP_STR(kVK_F1, "F1");
+ MAP_STR(kVK_F2, "F2");
+ MAP_STR(kVK_F3, "F3");
+ MAP_STR(kVK_F4, "F4");
+ MAP_STR(kVK_F5, "F5");
+ MAP_STR(kVK_F6, "F6");
+ MAP_STR(kVK_F7, "F7");
+ MAP_STR(kVK_F8, "F8");
+ MAP_STR(kVK_F9, "F9");
+ MAP_STR(kVK_F10, "F10");
+ MAP_STR(kVK_F11, "F11");
+ MAP_STR(kVK_F12, "F12");
+ MAP_STR(kVK_F13, "F13");
+ MAP_STR(kVK_F14, "F14");
+ MAP_STR(kVK_F15, "F15");
+ MAP_STR(kVK_F16, "F16");
+ MAP_STR(kVK_F17, "F17");
+ MAP_STR(kVK_F18, "F18");
+ MAP_STR(kVK_F19, "F19");
+ MAP_STR(kVK_F20, "F20");
+ MAP_GLYPH(kVK_Control, kControlUnicode);
+ MAP_GLYPH(kVK_Shift, kShiftUnicode);
+ MAP_GLYPH(kVK_Option, kOptionUnicode);
+ MAP_GLYPH(kVK_Command, kCommandUnicode);
+ MAP_GLYPH(kVK_RightControl, kControlUnicode);
+ MAP_GLYPH(kVK_RightShift, kShiftUnicode);
+ MAP_GLYPH(kVK_RightOption, kOptionUnicode);
+ }
+#undef MAP_STR
+#undef MAP_GLYPH
+
+ return false;
+}
+
+void obs_key_to_str(obs_key_t key, struct dstr *str)
+{
+ if (localized_key_to_str(key, str))
+ return;
+
+ int code = obs_key_to_virtual_key(key);
+ if (code_to_str(code, str))
+ return;
+
+ if (code == INVALID_KEY) {
+ blog(LOG_ERROR,
+ "hotkey-cocoa: Got invalid key while "
+ "translating key '%d' (%s)",
+ key, obs_key_to_name(key));
+ goto err;
+ }
+
+ struct obs_hotkeys_platform *plat = NULL;
+
+ if (obs) {
+ pthread_mutex_lock(&obs->hotkeys.mutex);
+ plat = obs->hotkeys.platform_context;
+ hotkeys_retain(plat);
+ pthread_mutex_unlock(&obs->hotkeys.mutex);
+ }
+
+ if (!plat) {
+ blog(LOG_ERROR,
+ "hotkey-cocoa: Could not get hotkey platform "
+ "while translating key '%d' (%s)",
+ key, obs_key_to_name(key));
+ goto err;
+ }
+
+ const UniCharCount max_length = 16;
+ UInt32 dead_key_state = 0;
+ UniChar buffer[max_length];
+ UniCharCount len = 0;
+
+ OSStatus err =
+ UCKeyTranslate(plat->layout, code, kUCKeyActionDown,
+ 0x104, //caps lock for upper case letters
+ LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit,
+ &dead_key_state, max_length, &len, buffer);
+
+ if (err == noErr && len <= 0 && dead_key_state) {
+ err = UCKeyTranslate(plat->layout, kVK_Space, kUCKeyActionDown,
+ 0x104, LMGetKbdType(),
+ kUCKeyTranslateNoDeadKeysBit,
+ &dead_key_state, max_length, &len, buffer);
+ }
+
+ hotkeys_release(plat);
+
+ if (err != noErr) {
+ blog(LOG_ERROR,
+ "hotkey-cocoa: Error while translating key '%d'"
+ " (0x%x, %s) to string: %d",
+ key, code, obs_key_to_name(key), err);
+ goto err;
+ }
+
+ if (len == 0) {
+ blog(LOG_ERROR,
+ "hotkey-cocoa: Got 0 length string while "
+ "translating '%d' (0x%x, %s) to string",
+ key, code, obs_key_to_name(key));
+ goto err;
+ }
+
+ CFStringRef string = CFStringCreateWithCharactersNoCopy(
+ NULL, buffer, len, kCFAllocatorNull);
+ if (!string) {
+ blog(LOG_ERROR,
+ "hotkey-cocoa: Could not create CFStringRef "
+ "while translating '%d' (0x%x, %s) to string",
+ key, code, obs_key_to_name(key));
+ goto err;
+ }
+
+ if (!dstr_from_cfstring(str, string)) {
+ blog(LOG_ERROR,
+ "hotkey-cocoa: Could not translate CFStringRef "
+ "to CString while translating '%d' (0x%x, %s)",
+ key, code, obs_key_to_name(key));
+
+ goto release;
+ }
+
+ CFRelease(string);
+ return;
+
+release:
+ CFRelease(string);
+err:
+ dstr_copy(str, obs_key_to_name(key));
+}
+
+#define OBS_COCOA_MODIFIER_SIZE 7
+static void unichar_to_utf8(const UniChar *c, char *buff)
+{
+ CFStringRef string = CFStringCreateWithCharactersNoCopy(
+ NULL, c, 2, kCFAllocatorNull);
+ if (!string) {
+ blog(LOG_ERROR, "hotkey-cocoa: Could not create CFStringRef "
+ "while populating modifier strings");
+ return;
+ }
+
+ if (!CFStringGetCString(string, buff, OBS_COCOA_MODIFIER_SIZE,
+ kCFStringEncodingUTF8))
+ blog(LOG_ERROR,
+ "hotkey-cocoa: Error while populating "
+ " modifier string with glyph %d (0x%x)",
+ c[0], c[0]);
+
+ CFRelease(string);
+}
+
+static char ctrl_str[OBS_COCOA_MODIFIER_SIZE];
+static char opt_str[OBS_COCOA_MODIFIER_SIZE];
+static char shift_str[OBS_COCOA_MODIFIER_SIZE];
+static char cmd_str[OBS_COCOA_MODIFIER_SIZE];
+static void init_utf_8_strings(void)
+{
+ const UniChar ctrl_uni[] = {kControlUnicode, 0};
+ const UniChar opt_uni[] = {kOptionUnicode, 0};
+ const UniChar shift_uni[] = {kShiftUnicode, 0};
+ const UniChar cmd_uni[] = {kCommandUnicode, 0};
+
+ unichar_to_utf8(ctrl_uni, ctrl_str);
+ unichar_to_utf8(opt_uni, opt_str);
+ unichar_to_utf8(shift_uni, shift_str);
+ unichar_to_utf8(cmd_uni, cmd_str);
+}
+
+static pthread_once_t strings_token = PTHREAD_ONCE_INIT;
+void obs_key_combination_to_str(obs_key_combination_t key, struct dstr *str)
+{
+ struct dstr key_str = {0};
+ if (key.key != OBS_KEY_NONE)
+ obs_key_to_str(key.key, &key_str);
+
+ int res = pthread_once(&strings_token, init_utf_8_strings);
+ if (res) {
+ blog(LOG_ERROR,
+ "hotkeys-cocoa: Error while translating "
+ "modifiers %d (0x%x)",
+ res, res);
+ dstr_move(str, &key_str);
+ return;
+ }
+
+#define CHECK_MODIFIER(mod, str) ((key.modifiers & mod) ? str : "")
+ dstr_printf(str, "%s%s%s%s%s",
+ CHECK_MODIFIER(INTERACT_CONTROL_KEY, ctrl_str),
+ CHECK_MODIFIER(INTERACT_ALT_KEY, opt_str),
+ CHECK_MODIFIER(INTERACT_SHIFT_KEY, shift_str),
+ CHECK_MODIFIER(INTERACT_COMMAND_KEY, cmd_str),
+ key_str.len ? key_str.array : "");
+#undef CHECK_MODIFIER
+
+ dstr_free(&key_str);
+}
+
+static inline CFDictionaryRef copy_device_mask(UInt32 page, UInt32 usage)
+{
+ CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
+ kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ CFNumberRef value;
+ // Add the page value.
+ value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
+ CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), value);
+ CFRelease(value);
+
+ // Add the usage value (which is only valid if page value exists).
+ value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
+ CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), value);
+ CFRelease(value);
+
+ return dict;
+}
+
+static CFSetRef copy_devices(obs_hotkeys_platform_t *plat, UInt32 page,
+ UInt32 usage)
+{
+ CFDictionaryRef mask = copy_device_mask(page, usage);
+ IOHIDManagerSetDeviceMatching(plat->manager, mask);
+ CFRelease(mask);
+
+ CFSetRef devices = IOHIDManagerCopyDevices(plat->manager);
+ if (!devices)
+ return NULL;
+
+ if (CFSetGetCount(devices) < 1) {
+ CFRelease(devices);
+ return NULL;
+ }
+
+ return devices;
+}
+
+static UInt16 usage_to_carbon(UInt32 usage)
+{
+ switch (usage) {
+ case kHIDUsage_KeyboardErrorRollOver:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardPOSTFail:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardErrorUndefined:
+ return INVALID_KEY;
+
+ case kHIDUsage_KeyboardA:
+ return kVK_ANSI_A;
+ case kHIDUsage_KeyboardB:
+ return kVK_ANSI_B;
+ case kHIDUsage_KeyboardC:
+ return kVK_ANSI_C;
+ case kHIDUsage_KeyboardD:
+ return kVK_ANSI_D;
+ case kHIDUsage_KeyboardE:
+ return kVK_ANSI_E;
+ case kHIDUsage_KeyboardF:
+ return kVK_ANSI_F;
+ case kHIDUsage_KeyboardG:
+ return kVK_ANSI_G;
+ case kHIDUsage_KeyboardH:
+ return kVK_ANSI_H;
+ case kHIDUsage_KeyboardI:
+ return kVK_ANSI_I;
+ case kHIDUsage_KeyboardJ:
+ return kVK_ANSI_J;
+ case kHIDUsage_KeyboardK:
+ return kVK_ANSI_K;
+ case kHIDUsage_KeyboardL:
+ return kVK_ANSI_L;
+ case kHIDUsage_KeyboardM:
+ return kVK_ANSI_M;
+ case kHIDUsage_KeyboardN:
+ return kVK_ANSI_N;
+ case kHIDUsage_KeyboardO:
+ return kVK_ANSI_O;
+ case kHIDUsage_KeyboardP:
+ return kVK_ANSI_P;
+ case kHIDUsage_KeyboardQ:
+ return kVK_ANSI_Q;
+ case kHIDUsage_KeyboardR:
+ return kVK_ANSI_R;
+ case kHIDUsage_KeyboardS:
+ return kVK_ANSI_S;
+ case kHIDUsage_KeyboardT:
+ return kVK_ANSI_T;
+ case kHIDUsage_KeyboardU:
+ return kVK_ANSI_U;
+ case kHIDUsage_KeyboardV:
+ return kVK_ANSI_V;
+ case kHIDUsage_KeyboardW:
+ return kVK_ANSI_W;
+ case kHIDUsage_KeyboardX:
+ return kVK_ANSI_X;
+ case kHIDUsage_KeyboardY:
+ return kVK_ANSI_Y;
+ case kHIDUsage_KeyboardZ:
+ return kVK_ANSI_Z;
+
+ case kHIDUsage_Keyboard1:
+ return kVK_ANSI_1;
+ case kHIDUsage_Keyboard2:
+ return kVK_ANSI_2;
+ case kHIDUsage_Keyboard3:
+ return kVK_ANSI_3;
+ case kHIDUsage_Keyboard4:
+ return kVK_ANSI_4;
+ case kHIDUsage_Keyboard5:
+ return kVK_ANSI_5;
+ case kHIDUsage_Keyboard6:
+ return kVK_ANSI_6;
+ case kHIDUsage_Keyboard7:
+ return kVK_ANSI_7;
+ case kHIDUsage_Keyboard8:
+ return kVK_ANSI_8;
+ case kHIDUsage_Keyboard9:
+ return kVK_ANSI_9;
+ case kHIDUsage_Keyboard0:
+ return kVK_ANSI_0;
+
+ case kHIDUsage_KeyboardReturnOrEnter:
+ return kVK_Return;
+ case kHIDUsage_KeyboardEscape:
+ return kVK_Escape;
+ case kHIDUsage_KeyboardDeleteOrBackspace:
+ return kVK_Delete;
+ case kHIDUsage_KeyboardTab:
+ return kVK_Tab;
+ case kHIDUsage_KeyboardSpacebar:
+ return kVK_Space;
+ case kHIDUsage_KeyboardHyphen:
+ return kVK_ANSI_Minus;
+ case kHIDUsage_KeyboardEqualSign:
+ return kVK_ANSI_Equal;
+ case kHIDUsage_KeyboardOpenBracket:
+ return kVK_ANSI_LeftBracket;
+ case kHIDUsage_KeyboardCloseBracket:
+ return kVK_ANSI_RightBracket;
+ case kHIDUsage_KeyboardBackslash:
+ return kVK_ANSI_Backslash;
+ case kHIDUsage_KeyboardNonUSPound:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardSemicolon:
+ return kVK_ANSI_Semicolon;
+ case kHIDUsage_KeyboardQuote:
+ return kVK_ANSI_Quote;
+ case kHIDUsage_KeyboardGraveAccentAndTilde:
+ return kVK_ANSI_Grave;
+ case kHIDUsage_KeyboardComma:
+ return kVK_ANSI_Comma;
+ case kHIDUsage_KeyboardPeriod:
+ return kVK_ANSI_Period;
+ case kHIDUsage_KeyboardSlash:
+ return kVK_ANSI_Slash;
+ case kHIDUsage_KeyboardCapsLock:
+ return kVK_CapsLock;
+
+ case kHIDUsage_KeyboardF1:
+ return kVK_F1;
+ case kHIDUsage_KeyboardF2:
+ return kVK_F2;
+ case kHIDUsage_KeyboardF3:
+ return kVK_F3;
+ case kHIDUsage_KeyboardF4:
+ return kVK_F4;
+ case kHIDUsage_KeyboardF5:
+ return kVK_F5;
+ case kHIDUsage_KeyboardF6:
+ return kVK_F6;
+ case kHIDUsage_KeyboardF7:
+ return kVK_F7;
+ case kHIDUsage_KeyboardF8:
+ return kVK_F8;
+ case kHIDUsage_KeyboardF9:
+ return kVK_F9;
+ case kHIDUsage_KeyboardF10:
+ return kVK_F10;
+ case kHIDUsage_KeyboardF11:
+ return kVK_F11;
+ case kHIDUsage_KeyboardF12:
+ return kVK_F12;
+
+ case kHIDUsage_KeyboardPrintScreen:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardScrollLock:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardPause:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardInsert:
+ return kVK_Help;
+ case kHIDUsage_KeyboardHome:
+ return kVK_Home;
+ case kHIDUsage_KeyboardPageUp:
+ return kVK_PageUp;
+ case kHIDUsage_KeyboardDeleteForward:
+ return kVK_ForwardDelete;
+ case kHIDUsage_KeyboardEnd:
+ return kVK_End;
+ case kHIDUsage_KeyboardPageDown:
+ return kVK_PageDown;
+
+ case kHIDUsage_KeyboardRightArrow:
+ return kVK_RightArrow;
+ case kHIDUsage_KeyboardLeftArrow:
+ return kVK_LeftArrow;
+ case kHIDUsage_KeyboardDownArrow:
+ return kVK_DownArrow;
+ case kHIDUsage_KeyboardUpArrow:
+ return kVK_UpArrow;
+
+ case kHIDUsage_KeypadNumLock:
+ return kVK_ANSI_KeypadClear;
+ case kHIDUsage_KeypadSlash:
+ return kVK_ANSI_KeypadDivide;
+ case kHIDUsage_KeypadAsterisk:
+ return kVK_ANSI_KeypadMultiply;
+ case kHIDUsage_KeypadHyphen:
+ return kVK_ANSI_KeypadMinus;
+ case kHIDUsage_KeypadPlus:
+ return kVK_ANSI_KeypadPlus;
+ case kHIDUsage_KeypadEnter:
+ return kVK_ANSI_KeypadEnter;
+
+ case kHIDUsage_Keypad1:
+ return kVK_ANSI_Keypad1;
+ case kHIDUsage_Keypad2:
+ return kVK_ANSI_Keypad2;
+ case kHIDUsage_Keypad3:
+ return kVK_ANSI_Keypad3;
+ case kHIDUsage_Keypad4:
+ return kVK_ANSI_Keypad4;
+ case kHIDUsage_Keypad5:
+ return kVK_ANSI_Keypad5;
+ case kHIDUsage_Keypad6:
+ return kVK_ANSI_Keypad6;
+ case kHIDUsage_Keypad7:
+ return kVK_ANSI_Keypad7;
+ case kHIDUsage_Keypad8:
+ return kVK_ANSI_Keypad8;
+ case kHIDUsage_Keypad9:
+ return kVK_ANSI_Keypad9;
+ case kHIDUsage_Keypad0:
+ return kVK_ANSI_Keypad0;
+
+ case kHIDUsage_KeypadPeriod:
+ return kVK_ANSI_KeypadDecimal;
+ case kHIDUsage_KeyboardNonUSBackslash:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardApplication:
+ return kVK_F13;
+ case kHIDUsage_KeyboardPower:
+ return INVALID_KEY;
+ case kHIDUsage_KeypadEqualSign:
+ return kVK_ANSI_KeypadEquals;
+
+ case kHIDUsage_KeyboardF13:
+ return kVK_F13;
+ case kHIDUsage_KeyboardF14:
+ return kVK_F14;
+ case kHIDUsage_KeyboardF15:
+ return kVK_F15;
+ case kHIDUsage_KeyboardF16:
+ return kVK_F16;
+ case kHIDUsage_KeyboardF17:
+ return kVK_F17;
+ case kHIDUsage_KeyboardF18:
+ return kVK_F18;
+ case kHIDUsage_KeyboardF19:
+ return kVK_F19;
+ case kHIDUsage_KeyboardF20:
+ return kVK_F20;
+ case kHIDUsage_KeyboardF21:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardF22:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardF23:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardF24:
+ return INVALID_KEY;
+
+ case kHIDUsage_KeyboardExecute:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardHelp:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardMenu:
+ return 0x7F;
+ case kHIDUsage_KeyboardSelect:
+ return kVK_ANSI_KeypadEnter;
+ case kHIDUsage_KeyboardStop:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardAgain:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardUndo:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardCut:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardCopy:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardPaste:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardFind:
+ return INVALID_KEY;
+
+ case kHIDUsage_KeyboardMute:
+ return kVK_Mute;
+ case kHIDUsage_KeyboardVolumeUp:
+ return kVK_VolumeUp;
+ case kHIDUsage_KeyboardVolumeDown:
+ return kVK_VolumeDown;
+
+ case kHIDUsage_KeyboardLockingCapsLock:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardLockingNumLock:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardLockingScrollLock:
+ return INVALID_KEY;
+
+ case kHIDUsage_KeypadComma:
+ return INVALID_KEY;
+ case kHIDUsage_KeypadEqualSignAS400:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardInternational1:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardInternational2:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardInternational3:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardInternational4:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardInternational5:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardInternational6:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardInternational7:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardInternational8:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardInternational9:
+ return INVALID_KEY;
+
+ case kHIDUsage_KeyboardLANG1:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardLANG2:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardLANG3:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardLANG4:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardLANG5:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardLANG6:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardLANG7:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardLANG8:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardLANG9:
+ return INVALID_KEY;
+
+ case kHIDUsage_KeyboardAlternateErase:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardSysReqOrAttention:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardCancel:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardClear:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardPrior:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardReturn:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardSeparator:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardOut:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardOper:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardClearOrAgain:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardCrSelOrProps:
+ return INVALID_KEY;
+ case kHIDUsage_KeyboardExSel:
+ return INVALID_KEY;
+
+ /* 0xa5-0xdf Reserved */
+
+ case kHIDUsage_KeyboardLeftControl:
+ return kVK_Control;
+ case kHIDUsage_KeyboardLeftShift:
+ return kVK_Shift;
+ case kHIDUsage_KeyboardLeftAlt:
+ return kVK_Option;
+ case kHIDUsage_KeyboardLeftGUI:
+ return kVK_Command;
+ case kHIDUsage_KeyboardRightControl:
+ return kVK_RightControl;
+ case kHIDUsage_KeyboardRightShift:
+ return kVK_RightShift;
+ case kHIDUsage_KeyboardRightAlt:
+ return kVK_RightOption;
+ case kHIDUsage_KeyboardRightGUI:
+ return 0x36; //??
+
+ /* 0xe8-0xffff Reserved */
+
+ case kHIDUsage_Keyboard_Reserved:
+ return INVALID_KEY;
+ default:
+ return INVALID_KEY;
+ }
+ return INVALID_KEY;
+}
+
+obs_key_t obs_key_from_virtual_key(int code)
+{
+ switch (code) {
+ case kVK_ANSI_A:
+ return OBS_KEY_A;
+ case kVK_ANSI_B:
+ return OBS_KEY_B;
+ case kVK_ANSI_C:
+ return OBS_KEY_C;
+ case kVK_ANSI_D:
+ return OBS_KEY_D;
+ case kVK_ANSI_E:
+ return OBS_KEY_E;
+ case kVK_ANSI_F:
+ return OBS_KEY_F;
+ case kVK_ANSI_G:
+ return OBS_KEY_G;
+ case kVK_ANSI_H:
+ return OBS_KEY_H;
+ case kVK_ANSI_I:
+ return OBS_KEY_I;
+ case kVK_ANSI_J:
+ return OBS_KEY_J;
+ case kVK_ANSI_K:
+ return OBS_KEY_K;
+ case kVK_ANSI_L:
+ return OBS_KEY_L;
+ case kVK_ANSI_M:
+ return OBS_KEY_M;
+ case kVK_ANSI_N:
+ return OBS_KEY_N;
+ case kVK_ANSI_O:
+ return OBS_KEY_O;
+ case kVK_ANSI_P:
+ return OBS_KEY_P;
+ case kVK_ANSI_Q:
+ return OBS_KEY_Q;
+ case kVK_ANSI_R:
+ return OBS_KEY_R;
+ case kVK_ANSI_S:
+ return OBS_KEY_S;
+ case kVK_ANSI_T:
+ return OBS_KEY_T;
+ case kVK_ANSI_U:
+ return OBS_KEY_U;
+ case kVK_ANSI_V:
+ return OBS_KEY_V;
+ case kVK_ANSI_W:
+ return OBS_KEY_W;
+ case kVK_ANSI_X:
+ return OBS_KEY_X;
+ case kVK_ANSI_Y:
+ return OBS_KEY_Y;
+ case kVK_ANSI_Z:
+ return OBS_KEY_Z;
+
+ case kVK_ANSI_1:
+ return OBS_KEY_1;
+ case kVK_ANSI_2:
+ return OBS_KEY_2;
+ case kVK_ANSI_3:
+ return OBS_KEY_3;
+ case kVK_ANSI_4:
+ return OBS_KEY_4;
+ case kVK_ANSI_5:
+ return OBS_KEY_5;
+ case kVK_ANSI_6:
+ return OBS_KEY_6;
+ case kVK_ANSI_7:
+ return OBS_KEY_7;
+ case kVK_ANSI_8:
+ return OBS_KEY_8;
+ case kVK_ANSI_9:
+ return OBS_KEY_9;
+ case kVK_ANSI_0:
+ return OBS_KEY_0;
+
+ case kVK_Return:
+ return OBS_KEY_RETURN;
+ case kVK_Escape:
+ return OBS_KEY_ESCAPE;
+ case kVK_Delete:
+ return OBS_KEY_BACKSPACE;
+ case kVK_Tab:
+ return OBS_KEY_TAB;
+ case kVK_Space:
+ return OBS_KEY_SPACE;
+ case kVK_ANSI_Minus:
+ return OBS_KEY_MINUS;
+ case kVK_ANSI_Equal:
+ return OBS_KEY_EQUAL;
+ case kVK_ANSI_LeftBracket:
+ return OBS_KEY_BRACKETLEFT;
+ case kVK_ANSI_RightBracket:
+ return OBS_KEY_BRACKETRIGHT;
+ case kVK_ANSI_Backslash:
+ return OBS_KEY_BACKSLASH;
+ case kVK_ANSI_Semicolon:
+ return OBS_KEY_SEMICOLON;
+ case kVK_ANSI_Quote:
+ return OBS_KEY_QUOTE;
+ case kVK_ANSI_Grave:
+ return OBS_KEY_DEAD_GRAVE;
+ case kVK_ANSI_Comma:
+ return OBS_KEY_COMMA;
+ case kVK_ANSI_Period:
+ return OBS_KEY_PERIOD;
+ case kVK_ANSI_Slash:
+ return OBS_KEY_SLASH;
+ case kVK_CapsLock:
+ return OBS_KEY_CAPSLOCK;
+ case kVK_ISO_Section:
+ return OBS_KEY_SECTION;
+
+ case kVK_F1:
+ return OBS_KEY_F1;
+ case kVK_F2:
+ return OBS_KEY_F2;
+ case kVK_F3:
+ return OBS_KEY_F3;
+ case kVK_F4:
+ return OBS_KEY_F4;
+ case kVK_F5:
+ return OBS_KEY_F5;
+ case kVK_F6:
+ return OBS_KEY_F6;
+ case kVK_F7:
+ return OBS_KEY_F7;
+ case kVK_F8:
+ return OBS_KEY_F8;
+ case kVK_F9:
+ return OBS_KEY_F9;
+ case kVK_F10:
+ return OBS_KEY_F10;
+ case kVK_F11:
+ return OBS_KEY_F11;
+ case kVK_F12:
+ return OBS_KEY_F12;
+
+ case kVK_Help:
+ return OBS_KEY_HELP;
+ case kVK_Home:
+ return OBS_KEY_HOME;
+ case kVK_PageUp:
+ return OBS_KEY_PAGEUP;
+ case kVK_ForwardDelete:
+ return OBS_KEY_DELETE;
+ case kVK_End:
+ return OBS_KEY_END;
+ case kVK_PageDown:
+ return OBS_KEY_PAGEDOWN;
+
+ case kVK_RightArrow:
+ return OBS_KEY_RIGHT;
+ case kVK_LeftArrow:
+ return OBS_KEY_LEFT;
+ case kVK_DownArrow:
+ return OBS_KEY_DOWN;
+ case kVK_UpArrow:
+ return OBS_KEY_UP;
+
+ case kVK_ANSI_KeypadClear:
+ return OBS_KEY_CLEAR;
+ case kVK_ANSI_KeypadDivide:
+ return OBS_KEY_NUMSLASH;
+ case kVK_ANSI_KeypadMultiply:
+ return OBS_KEY_NUMASTERISK;
+ case kVK_ANSI_KeypadMinus:
+ return OBS_KEY_NUMMINUS;
+ case kVK_ANSI_KeypadPlus:
+ return OBS_KEY_NUMPLUS;
+ case kVK_ANSI_KeypadEnter:
+ return OBS_KEY_ENTER;
+
+ case kVK_ANSI_Keypad1:
+ return OBS_KEY_NUM1;
+ case kVK_ANSI_Keypad2:
+ return OBS_KEY_NUM2;
+ case kVK_ANSI_Keypad3:
+ return OBS_KEY_NUM3;
+ case kVK_ANSI_Keypad4:
+ return OBS_KEY_NUM4;
+ case kVK_ANSI_Keypad5:
+ return OBS_KEY_NUM5;
+ case kVK_ANSI_Keypad6:
+ return OBS_KEY_NUM6;
+ case kVK_ANSI_Keypad7:
+ return OBS_KEY_NUM7;
+ case kVK_ANSI_Keypad8:
+ return OBS_KEY_NUM8;
+ case kVK_ANSI_Keypad9:
+ return OBS_KEY_NUM9;
+ case kVK_ANSI_Keypad0:
+ return OBS_KEY_NUM0;
+
+ case kVK_ANSI_KeypadDecimal:
+ return OBS_KEY_NUMPERIOD;
+ case kVK_ANSI_KeypadEquals:
+ return OBS_KEY_NUMEQUAL;
+
+ case kVK_F13:
+ return OBS_KEY_F13;
+ case kVK_F14:
+ return OBS_KEY_F14;
+ case kVK_F15:
+ return OBS_KEY_F15;
+ case kVK_F16:
+ return OBS_KEY_F16;
+ case kVK_F17:
+ return OBS_KEY_F17;
+ case kVK_F18:
+ return OBS_KEY_F18;
+ case kVK_F19:
+ return OBS_KEY_F19;
+ case kVK_F20:
+ return OBS_KEY_F20;
+
+ case kVK_Control:
+ return OBS_KEY_CONTROL;
+ case kVK_Shift:
+ return OBS_KEY_SHIFT;
+ case kVK_Option:
+ return OBS_KEY_ALT;
+ case kVK_Command:
+ return OBS_KEY_META;
+ case kVK_RightControl:
+ return OBS_KEY_CONTROL;
+ case kVK_RightShift:
+ return OBS_KEY_SHIFT;
+ case kVK_RightOption:
+ return OBS_KEY_ALT;
+ case 0x36:
+ return OBS_KEY_META;
+
+ case kVK_Function:
+ case kVK_Mute:
+ case kVK_VolumeDown:
+ case kVK_VolumeUp:
+ break;
+ }
+ return OBS_KEY_NONE;
+}
+
+static inline void load_key(obs_hotkeys_platform_t *plat, IOHIDElementRef key)
+{
+ UInt32 usage_code = IOHIDElementGetUsage(key);
+ UInt16 carbon_code = usage_to_carbon(usage_code);
+
+ if (carbon_code == INVALID_KEY)
+ return;
+
+ obs_key_t obs_key = obs_key_from_virtual_key(carbon_code);
+ if (obs_key == OBS_KEY_NONE)
+ return;
+
+ da_push_back(plat->keys[obs_key], &key);
+ CFRetain(*(IOHIDElementRef *)da_end(plat->keys[obs_key]));
+}
+
+static inline void load_keyboard(obs_hotkeys_platform_t *plat,
+ IOHIDDeviceRef keyboard)
+{
+ CFArrayRef keys = IOHIDDeviceCopyMatchingElements(
+ keyboard, NULL, kIOHIDOptionsTypeNone);
+
+ if (!keys) {
+ blog(LOG_ERROR, "hotkeys-cocoa: Getting keyboard keys failed");
+ return;
+ }
+
+ CFIndex count = CFArrayGetCount(keys);
+ if (!count) {
+ blog(LOG_ERROR, "hotkeys-cocoa: Keyboard has no keys");
+ CFRelease(keys);
+ return;
+ }
+
+ for (CFIndex i = 0; i < count; i++) {
+ IOHIDElementRef key =
+ (IOHIDElementRef)CFArrayGetValueAtIndex(keys, i);
+
+ // Skip non-matching keys elements
+ if (IOHIDElementGetUsagePage(key) != kHIDPage_KeyboardOrKeypad)
+ continue;
+
+ load_key(plat, key);
+ }
+
+ CFRelease(keys);
+}
+
+static bool init_keyboard(obs_hotkeys_platform_t *plat)
+{
+ CFSetRef keyboards = copy_devices(plat, kHIDPage_GenericDesktop,
+ kHIDUsage_GD_Keyboard);
+ if (!keyboards)
+ return false;
+
+ CFIndex count = CFSetGetCount(keyboards);
+
+ CFTypeRef devices[count];
+ CFSetGetValues(keyboards, devices);
+
+ for (CFIndex i = 0; i < count; i++)
+ load_keyboard(plat, (IOHIDDeviceRef)devices[i]);
+
+ CFRelease(keyboards);
+ return true;
+}
+
+static inline void free_hotkeys_platform(obs_hotkeys_platform_t *plat)
+{
+ if (!plat)
+ return;
+
+ if (plat->tis) {
+ CFRelease(plat->tis);
+ plat->tis = NULL;
+ }
+
+ if (plat->layout_data) {
+ CFRelease(plat->layout_data);
+ plat->layout_data = NULL;
+ }
+
+ if (plat->manager) {
+ CFRelease(plat->manager);
+ plat->manager = NULL;
+ }
+
+ for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++) {
+ for (size_t j = 0; j < plat->keys[i].num; j++)
+ CFRelease(plat->keys[i].array[j]);
+
+ da_free(plat->keys[i]);
+ }
+
+ bfree(plat);
+}
+
+static bool log_layout_name(TISInputSourceRef tis)
+{
+ struct dstr layout_name = {0};
+ CFStringRef sid = (CFStringRef)TISGetInputSourceProperty(
+ tis, kTISPropertyInputSourceID);
+ if (!sid) {
+ blog(LOG_ERROR, "hotkeys-cocoa: Failed getting InputSourceID");
+ return false;
+ }
+
+ if (!dstr_from_cfstring(&layout_name, sid)) {
+ blog(LOG_ERROR, "hotkeys-cocoa: Could not convert InputSourceID"
+ " to CString");
+ goto fail;
+ }
+
+ blog(LOG_INFO, "hotkeys-cocoa: Using layout '%s'", layout_name.array);
+
+ dstr_free(&layout_name);
+ return true;
+
+fail:
+ dstr_free(&layout_name);
+ return false;
+}
+
+static bool init_hotkeys_platform(obs_hotkeys_platform_t **plat_)
+{
+ if (!plat_)
+ return false;
+
+ *plat_ = bzalloc(sizeof(obs_hotkeys_platform_t));
+ obs_hotkeys_platform_t *plat = *plat_;
+ if (!plat) {
+ *plat_ = NULL;
+ return false;
+ }
+
+ plat->tis = TISCopyCurrentKeyboardLayoutInputSource();
+ plat->layout_data = (CFDataRef)TISGetInputSourceProperty(
+ plat->tis, kTISPropertyUnicodeKeyLayoutData);
+
+ if (!plat->layout_data) {
+ blog(LOG_ERROR, "hotkeys-cocoa: Failed getting LayoutData");
+ goto fail;
+ }
+
+ CFRetain(plat->layout_data);
+ plat->layout = (UCKeyboardLayout *)CFDataGetBytePtr(plat->layout_data);
+
+ plat->manager =
+ IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
+
+ IOReturn openStatus =
+ IOHIDManagerOpen(plat->manager, kIOHIDOptionsTypeNone);
+ if (openStatus != kIOReturnSuccess) {
+ blog(LOG_ERROR, "hotkeys-cocoa: Failed opening HIDManager");
+ goto fail;
+ }
+
+ init_keyboard(plat);
+
+ return true;
+
+fail:
+ hotkeys_release(plat);
+ *plat_ = NULL;
+ return false;
+}
+
+static void input_method_changed(CFNotificationCenterRef nc, void *observer,
+ CFStringRef name, const void *object,
+ CFDictionaryRef user_info)
+{
+ UNUSED_PARAMETER(nc);
+ UNUSED_PARAMETER(name);
+ UNUSED_PARAMETER(object);
+ UNUSED_PARAMETER(user_info);
+
+ struct obs_core_hotkeys *hotkeys = observer;
+ obs_hotkeys_platform_t *new_plat;
+
+ if (init_hotkeys_platform(&new_plat)) {
+ obs_hotkeys_platform_t *plat;
+
+ pthread_mutex_lock(&hotkeys->mutex);
+ plat = hotkeys->platform_context;
+
+ if (new_plat && plat &&
+ new_plat->layout_data == plat->layout_data) {
+ pthread_mutex_unlock(&hotkeys->mutex);
+ hotkeys_release(new_plat);
+ return;
+ }
+
+ hotkeys->platform_context = new_plat;
+ if (new_plat)
+ log_layout_name(new_plat->tis);
+ pthread_mutex_unlock(&hotkeys->mutex);
+
+ calldata_t params = {0};
+ signal_handler_signal(hotkeys->signals, "hotkey_layout_change",
+ ¶ms);
+ if (plat)
+ hotkeys_release(plat);
+ }
+}
+
+bool obs_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys)
+{
+ CFNotificationCenterAddObserver(
+ CFNotificationCenterGetDistributedCenter(), hotkeys,
+ input_method_changed,
+ kTISNotifySelectedKeyboardInputSourceChanged, NULL,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
+
+ input_method_changed(NULL, hotkeys, NULL, NULL, NULL);
+ return hotkeys->platform_context != NULL;
+}
+
+void obs_hotkeys_platform_free(struct obs_core_hotkeys *hotkeys)
+{
+ CFNotificationCenterRemoveEveryObserver(
+ CFNotificationCenterGetDistributedCenter(), hotkeys);
+
+ hotkeys_release(hotkeys->platform_context);
+}
+
+typedef unsigned long NSUInteger;
+static bool mouse_button_pressed(obs_key_t key, bool *pressed)
+{
+ int button = 0;
+ switch (key) {
+#define MAP_BUTTON(n) \
+ case OBS_KEY_MOUSE##n: \
+ button = n - 1; \
+ break
+ MAP_BUTTON(1);
+ MAP_BUTTON(2);
+ MAP_BUTTON(3);
+ MAP_BUTTON(4);
+ MAP_BUTTON(5);
+ MAP_BUTTON(6);
+ MAP_BUTTON(7);
+ MAP_BUTTON(8);
+ MAP_BUTTON(9);
+ MAP_BUTTON(10);
+ MAP_BUTTON(11);
+ MAP_BUTTON(12);
+ MAP_BUTTON(13);
+ MAP_BUTTON(14);
+ MAP_BUTTON(15);
+ MAP_BUTTON(16);
+ MAP_BUTTON(17);
+ MAP_BUTTON(18);
+ MAP_BUTTON(19);
+ MAP_BUTTON(20);
+ MAP_BUTTON(21);
+ MAP_BUTTON(22);
+ MAP_BUTTON(23);
+ MAP_BUTTON(24);
+ MAP_BUTTON(25);
+ MAP_BUTTON(26);
+ MAP_BUTTON(27);
+ MAP_BUTTON(28);
+ MAP_BUTTON(29);
+ break;
+#undef MAP_BUTTON
+
+ default:
+ return false;
+ }
+
+ Class NSEvent = objc_getClass("NSEvent");
+ SEL pressedMouseButtonsSel = sel_registerName("pressedMouseButtons");
+ typedef int (*func)(id, SEL);
+ func pressedMouseButtons = (func)objc_msgSend;
+ NSUInteger buttons = (NSUInteger)pressedMouseButtons(
+ (id)NSEvent, pressedMouseButtonsSel);
+
+ *pressed = (buttons & (1 << button)) != 0;
+ return true;
+}
+
+bool obs_hotkeys_platform_is_pressed(obs_hotkeys_platform_t *plat,
+ obs_key_t key)
+{
+ bool mouse_pressed = false;
+ if (mouse_button_pressed(key, &mouse_pressed))
+ return mouse_pressed;
+
+ if (!plat)
+ return false;
+
+ if (key >= OBS_KEY_LAST_VALUE)
+ return false;
+
+ for (size_t i = 0; i < plat->keys[key].num;) {
+ IOHIDElementRef element = plat->keys[key].array[i];
+ IOHIDValueRef value = 0;
+ IOHIDDeviceRef device = IOHIDElementGetDevice(element);
+
+ if (IOHIDDeviceGetValue(device, element, &value) !=
+ kIOReturnSuccess) {
+ i += 1;
+ continue;
+ }
+
+ if (!value) {
+ CFRelease(element);
+ da_erase(plat->keys[key], i);
+ continue;
+ }
+
+ if (IOHIDValueGetIntegerValue(value) == 1)
+ return true;
+
+ i += 1;
+ }
+
+ return false;
+}
obs-studio-24.0.3.tar.xz/libobs/obs-config.h -> obs-studio-24.0.5.tar.xz/libobs/obs-config.h
Changed
*
* Reset to zero each major or minor version
*/
-#define LIBOBS_API_PATCH_VER 3
+#define LIBOBS_API_PATCH_VER 5
#define MAKE_SEMANTIC_VERSION(major, minor, patch) \
((major << 24) | (minor << 16) | patch)
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
video_output_inc_texture_frames(video->video);
for (size_t i = 0; i < video->gpu_encoders.num; i++) {
- obs_encoder_t *encoder = video->gpu_encoders.array[i];
- da_push_back(encoders, &encoder);
- obs_encoder_addref(encoder);
+ obs_encoder_t *encoder = obs_encoder_get_ref(
+ video->gpu_encoders.array[i]);
+ if (encoder)
+ da_push_back(encoders, &encoder);
}
pthread_mutex_unlock(&video->gpu_encoder_mutex);
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
effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
while (gs_effect_loop(effect, "Draw")) {
- xcursor_render(p->cursor);
+ xcursor_render(p->cursor, -p->cur_cut_left,
+ -p->cur_cut_top);
}
}
}
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
XFree(xc);
}
-void xcursor_render(xcursor_t *data)
+void xcursor_render(xcursor_t *data, int x_offset, int y_offset)
{
if (!data->tex)
return;
gs_enable_color(true, true, true, false);
gs_matrix_push();
- gs_matrix_translate3f(data->render_x, data->render_y, 0.0f);
+ gs_matrix_translate3f(data->render_x + x_offset,
+ data->render_y + y_offset, 0.0f);
gs_draw_sprite(data->tex, 0, 0, 0);
gs_matrix_pop();
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
*
* This needs to be executed within a valid render context
*/
-void xcursor_render(xcursor_t *data);
+void xcursor_render(xcursor_t *data, int x_offset, int y_offset);
/**
* Specify offset for the cursor
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
{
if (!xcb)
return 0;
-
xcb_screen_t *screen;
screen = xcb_setup_roots_iterator(xcb_get_setup(xcb)).data;
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
")",
i, w, h, x, y);
- obs_property_list_add_int(screens, screen_info.array, i);
+ if (h > 0 && w > 0)
+ obs_property_list_add_int(screens, screen_info.array,
+ i);
}
/* handle missing screen */
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
*assign = 0;
value = assign + 1;
- if (av_opt_set(context->priv_data, name, value, 0)) {
+ if (av_opt_set(context, name, value,
+ AV_OPT_SEARCH_CHILDREN)) {
blog(LOG_WARNING, "Failed to set %s=%s", name,
value);
ret = false;
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
return;
}
- if (buffer_duration_usec >= DBR_TRIGGER_USEC) {
+ if ((uint64_t)buffer_duration_usec >= DBR_TRIGGER_USEC) {
pthread_mutex_lock(&stream->dbr_mutex);
bitrate_changed = dbr_bitrate_lowered(stream);
pthread_mutex_unlock(&stream->dbr_mutex);
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
project(rtmp-services)
+find_package(Libcurl REQUIRED)
+
+include_directories(${LIBCURL_INCLUDE_DIRS})
+
include_directories(${OBS_JANSSON_INCLUDE_DIRS})
set(rtmp-services_SOURCES
twitch.c
+ younow.c
rtmp-common.c
rtmp-custom.c
rtmp-services-main.c)
set(rtmp-services_HEADERS
twitch.h
+ younow.h
rtmp-format-ver.h)
set(RTMP_SERVICES_URL
${rtmp-services_SOURCES}
${rtmp-services_HEADERS}
${rtmp-services_config_HEADERS})
+
target_link_libraries(rtmp-services
libobs
file-updater
- ${OBS_JANSSON_IMPORT})
+ ${OBS_JANSSON_IMPORT}
+ ${LIBCURL_LIBRARIES})
target_include_directories(rtmp-services
PUBLIC
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
{
"url": "https://obsproject.com/obs2_update/rtmp-services",
- "version": 112,
+ "version": 114,
"files": [
{
"name": "services.json",
- "version": 112
+ "version": 114
}
]
}
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
}
},
{
+ "name": "ChathostessModels",
+ "servers": [
+ {
+ "name": "ChathostessModels - Default",
+ "url": "rtmp://wowza01.foobarweb.com/cmschatsys_video"
+ }
+ ],
+ "recommended": {
+ "keyint": 2,
+ "max video bitrate": 3000,
+ "max audio bitrate": 128
+ }
+ },
+ {
"name": "Camplace",
"servers": [
{
}
},
{
+ "name": "YouNow",
+ "common": false,
+ "servers": [
+ {
+ "name": "younow.com",
+ "url": "https://signaling-api.younow-prod.video.propsproject.com/api/v1/ingest/server/"
+ }
+ ],
+ "recommended": {
+ "keyint": 2,
+ "output": "ftl_output",
+ "max audio bitrate": 160,
+ "max video bitrate": 7000,
+ "profile": "main",
+ "bframes": 0
+ }
+ },
+ {
"name": "Steam",
"common": false,
"servers": [
"max video bitrate": 7000,
"max audio bitrate": 128
}
+ },
+ {
+ "name": "Stars.AVN.com",
+ "servers": [
+ {
+ "name": "Default",
+ "url": "rtmp://alpha.gateway.stars.avn.com/live"
+ }
+ ],
+ "recommended": {
+ "keyint": 2,
+ "profile": "main",
+ "max video bitrate": 2500,
+ "max audio bitrate": 192,
+ "bframes": 0,
+ "x264opts": "tune=zerolatency"
+ }
}
]
}
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
#include "rtmp-format-ver.h"
#include "twitch.h"
+#include "younow.h"
struct rtmp_common {
char *service;
obs_data_set_string(settings, "rate_control", "CBR");
item = json_object_get(recommended, "profile");
- if (json_is_string(item)) {
+ obs_data_item_t *enc_item = obs_data_item_byname(settings, "profile");
+ if (json_is_string(item) &&
+ obs_data_item_gettype(enc_item) == OBS_DATA_STRING) {
const char *profile = json_string_value(item);
obs_data_set_string(settings, "profile", profile);
}
}
}
+ if (service->service && strcmp(service->service, "YouNow") == 0) {
+ if (service->server && service->key) {
+ return younow_get_ingest(service->server, service->key);
+ }
+ }
+
return service->server;
}
obs-studio-24.0.5.tar.xz/plugins/rtmp-services/younow.c
Added
+#include <curl/curl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <util/dstr.h>
+#include "util/base.h"
+#include "younow.h"
+
+struct younow_mem_struct {
+ char *memory;
+ size_t size;
+};
+
+static char *current_ingest = NULL;
+
+static size_t younow_write_cb(void *contents, size_t size, size_t nmemb,
+ void *userp)
+{
+ size_t realsize = size * nmemb;
+ struct younow_mem_struct *mem = (struct younow_mem_struct *)userp;
+
+ mem->memory = realloc(mem->memory, mem->size + realsize + 1);
+ if (mem->memory == NULL) {
+ blog(LOG_WARNING, "yyounow_write_cb: realloc returned NULL");
+ return 0;
+ }
+
+ memcpy(&(mem->memory[mem->size]), contents, realsize);
+ mem->size += realsize;
+ mem->memory[mem->size] = 0;
+
+ return realsize;
+}
+
+const char *younow_get_ingest(const char *server, const char *key)
+{
+ CURL *curl_handle;
+ CURLcode res;
+ struct younow_mem_struct chunk;
+ struct dstr uri;
+ long response_code;
+
+ // find the delimiter in stream key
+ const char *delim = strchr(key, '_');
+ if (delim == NULL) {
+ blog(LOG_WARNING,
+ "younow_get_ingest: delimiter not found in stream key");
+ return server;
+ }
+
+ curl_handle = curl_easy_init();
+
+ chunk.memory = malloc(1); /* will be grown as needed by realloc */
+ chunk.size = 0; /* no data at this point */
+
+ dstr_init(&uri);
+ dstr_copy(&uri, server);
+ dstr_ncat(&uri, key, delim - key);
+
+ curl_easy_setopt(curl_handle, CURLOPT_URL, uri.array);
+ curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, true);
+ curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2L);
+ curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 3L);
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, younow_write_cb);
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
+
+#if LIBCURL_VERSION_NUM >= 0x072400
+ // A lot of servers don't yet support ALPN
+ curl_easy_setopt(curl_handle, CURLOPT_SSL_ENABLE_ALPN, 0);
+#endif
+
+ res = curl_easy_perform(curl_handle);
+ dstr_free(&uri);
+
+ if (res != CURLE_OK) {
+ blog(LOG_WARNING,
+ "younow_get_ingest: curl_easy_perform() failed: %s",
+ curl_easy_strerror(res));
+ curl_easy_cleanup(curl_handle);
+ free(chunk.memory);
+ return server;
+ }
+
+ curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &response_code);
+ if (response_code != 200) {
+ blog(LOG_WARNING,
+ "younow_get_ingest: curl_easy_perform() returned code: %ld",
+ response_code);
+ curl_easy_cleanup(curl_handle);
+ free(chunk.memory);
+ return server;
+ }
+
+ curl_easy_cleanup(curl_handle);
+
+ if (chunk.size == 0) {
+ blog(LOG_WARNING,
+ "younow_get_ingest: curl_easy_perform() returned empty response");
+ free(chunk.memory);
+ return server;
+ }
+
+ if (current_ingest) {
+ free(current_ingest);
+ current_ingest = NULL;
+ }
+
+ current_ingest = strdup(chunk.memory);
+ free(chunk.memory);
+ blog(LOG_INFO, "younow_get_ingest: returning ingest: %s",
+ current_ingest);
+ return current_ingest;
+}
obs-studio-24.0.5.tar.xz/plugins/rtmp-services/younow.h
Added
+#pragma once
+
+extern const char *younow_get_ingest(const char *server, const char *key);
\ No newline at end of file
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
/* not capturable or internal windows */
static const char *internal_microsoft_exes[] = {
+ "startmenuexperiencehost",
"applicationframehost",
+ "peopleexperiencehost",
"shellexperiencehost",
+ "microsoft.notes",
"windowsinternal",
+ "systemsettings",
+ "textinputhost",
"winstore.app",
+ "searchapp",
+ "video.ui",
"searchui",
"lockapp",
+ "cortana",
+ "gamebar",
+ "tabtip",
+ "time",
NULL,
};
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
void DShowInput::OnEncodedVideoData(enum AVCodecID id, unsigned char *data,
size_t size, long long ts)
{
+ /* If format changes, free and allow it to recreate the decoder */
+ if (ffmpeg_decode_valid(video_decoder) &&
+ video_decoder->codec->id != id) {
+ ffmpeg_decode_free(video_decoder);
+ }
+
if (!ffmpeg_decode_valid(video_decoder)) {
/* Only use MJPEG hardware decoding on resolutions higher
* than 1920x1080. The reason why is because we want to strike
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
#define WIN32_MEAN_AND_LEAN
#include <windows.h>
+#include <initguid.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#include <propsys.h>
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
obs_source_t *source;
string device_id;
string device_name;
+ string device_sample = "-";
bool isInputDevice;
bool useDeviceTiming = false;
bool isDefaultDevice = false;
client->Start();
active = true;
- blog(LOG_INFO, "WASAPI: Device '%s' initialized", device_name.c_str());
+ blog(LOG_INFO, "WASAPI: Device '%s' [%s Hz] initialized",
+ device_name.c_str(), device_sample.c_str());
}
void WASAPISource::Initialize()
device_name = GetDeviceName(device);
+ HRESULT resSample;
+ IPropertyStore *store = nullptr;
+ PWAVEFORMATEX deviceFormatProperties;
+ PROPVARIANT prop;
+ resSample = device->OpenPropertyStore(STGM_READ, &store);
+ if (!FAILED(resSample)) {
+ resSample =
+ store->GetValue(PKEY_AudioEngine_DeviceFormat, &prop);
+ if (!FAILED(resSample)) {
+ deviceFormatProperties =
+ (PWAVEFORMATEX)prop.blob.pBlobData;
+ device_sample = std::to_string(
+ deviceFormatProperties->nSamplesPerSec);
+ }
+ }
+
InitClient();
if (!isInputDevice)
InitRender();
No build results available
No rpmlint results available
Request History
boombatower created request over 5 years ago
- Update to version 24.0.5:
* libobs: Update version to 24.0.5
* CI: Don't run clang format on some submodule plugins
* Merge pull request #2010 from wanhongqing123/master
* Merge pull request #2042 from WizardCM/custom-twitch-docks
* Merge pull request #2183 from ratwithacompiler/macos-python-fix-2
* Merge pull request #2085 from ratwithacompiler/macos-python-fix
* Merge pull request #2090 from jpark37/dxgi-refresh-rate
* Merge pull request #2089 from jpark37/dxgi-driver-version
* UI: Delete cookies before connecting account
* UI: Fix bug in untested/unused function code path
* deps/media-playback: Don't use interrupt cb for local files
* deps/media-playback: Don't exit thread on AVERROR_EXIT
* deps/obs-scripting: Fix formatting
* Merge pull request #2152 from Rosuav/fix-cursor-position
* UI: Fix Twitch panels not using dark first time
* Merge pull request #1914 from YouNow/master
* Merge pull request #2140 from DevWolk/avn-obs
* Merge pull request #2045 from wolf247/master
* Merge pull request #2179 from WizardCM/remove-help-interact
* Merge pull request #2125 from DDRBoxman/appbundle
* Merge pull request #2168 from kkartaltepe/vaapi-profile-fix
* Merge pull request #2148 from eulertour/master
* Merge pull request #2146 from Fenrirthviti/recording-bitrate-fix
* libobs: Fix race condition
* Merge pull request #2147 from JohannMG/vscode-ignore
* Merge pull request #2134 from WizardCM/wasapi-samplerate
* Merge pull request #2129 from Fenrirthviti/win-blacklist-update
* Merge pull request #2131 from jpark37/input-layout-error
* Merge pull request #2128 from Xaymar/return-to-break
boombatower accepted request over 5 years ago
ok