obs-windows.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269
  1. /******************************************************************************
  2. Copyright (C) 2013 by Hugh Bailey <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include "util/windows/win-registry.h"
  15. #include "util/windows/win-version.h"
  16. #include "util/platform.h"
  17. #include "util/dstr.h"
  18. #include "obs.h"
  19. #include "obs-internal.h"
  20. #include <windows.h>
  21. #include <wscapi.h>
  22. #include <iwscapi.h>
  23. static uint32_t win_ver = 0;
  24. static uint32_t win_build = 0;
  25. const char *get_module_extension(void)
  26. {
  27. return ".dll";
  28. }
  29. #ifdef _WIN64
  30. #define BIT_STRING "64bit"
  31. #else
  32. #define BIT_STRING "32bit"
  33. #endif
  34. static const char *module_bin[] = {
  35. "../../obs-plugins/" BIT_STRING,
  36. };
  37. static const char *module_data[] = {"../../data/obs-plugins/%module%"};
  38. static const int module_patterns_size =
  39. sizeof(module_bin) / sizeof(module_bin[0]);
  40. void add_default_module_paths(void)
  41. {
  42. for (int i = 0; i < module_patterns_size; i++)
  43. obs_add_module_path(module_bin[i], module_data[i]);
  44. }
  45. /* on windows, points to [base directory]/data/libobs */
  46. char *find_libobs_data_file(const char *file)
  47. {
  48. struct dstr path;
  49. dstr_init(&path);
  50. if (check_path(file, "../../data/libobs/", &path))
  51. return path.array;
  52. dstr_free(&path);
  53. return NULL;
  54. }
  55. static void log_processor_info(void)
  56. {
  57. HKEY key;
  58. wchar_t data[1024];
  59. char *str = NULL;
  60. DWORD size, speed;
  61. LSTATUS status;
  62. memset(data, 0, sizeof(data));
  63. status = RegOpenKeyW(
  64. HKEY_LOCAL_MACHINE,
  65. L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &key);
  66. if (status != ERROR_SUCCESS)
  67. return;
  68. size = sizeof(data);
  69. status = RegQueryValueExW(key, L"ProcessorNameString", NULL, NULL,
  70. (LPBYTE)data, &size);
  71. if (status == ERROR_SUCCESS) {
  72. os_wcs_to_utf8_ptr(data, 0, &str);
  73. blog(LOG_INFO, "CPU Name: %s", str);
  74. bfree(str);
  75. }
  76. size = sizeof(speed);
  77. status = RegQueryValueExW(key, L"~MHz", NULL, NULL, (LPBYTE)&speed,
  78. &size);
  79. if (status == ERROR_SUCCESS)
  80. blog(LOG_INFO, "CPU Speed: %ldMHz", speed);
  81. RegCloseKey(key);
  82. }
  83. static void log_processor_cores(void)
  84. {
  85. blog(LOG_INFO, "Physical Cores: %d, Logical Cores: %d",
  86. os_get_physical_cores(), os_get_logical_cores());
  87. }
  88. static void log_emulation_status(void)
  89. {
  90. if (os_get_emulation_status()) {
  91. blog(LOG_WARNING, "Windows ARM64: Running with x64 emulation");
  92. }
  93. }
  94. static void log_available_memory(void)
  95. {
  96. MEMORYSTATUSEX ms;
  97. ms.dwLength = sizeof(ms);
  98. GlobalMemoryStatusEx(&ms);
  99. #ifdef _WIN64
  100. const char *note = "";
  101. #else
  102. const char *note = " (NOTE: 32bit programs cannot use more than 3gb)";
  103. #endif
  104. blog(LOG_INFO, "Physical Memory: %luMB Total, %luMB Free%s",
  105. (DWORD)(ms.ullTotalPhys / 1048576),
  106. (DWORD)(ms.ullAvailPhys / 1048576), note);
  107. }
  108. extern const char *get_win_release_id();
  109. static void log_windows_version(void)
  110. {
  111. struct win_version_info ver;
  112. get_win_ver(&ver);
  113. const char *release_id = get_win_release_id();
  114. bool b64 = is_64_bit_windows();
  115. const char *windows_bitness = b64 ? "64" : "32";
  116. bool arm64 = is_arm64_windows();
  117. const char *arm64_windows = arm64 ? "ARM " : "";
  118. blog(LOG_INFO,
  119. "Windows Version: %d.%d Build %d (release: %s; revision: %d; %s%s-bit)",
  120. ver.major, ver.minor, ver.build, release_id, ver.revis,
  121. arm64_windows, windows_bitness);
  122. }
  123. static void log_admin_status(void)
  124. {
  125. SID_IDENTIFIER_AUTHORITY auth = SECURITY_NT_AUTHORITY;
  126. PSID admin_group;
  127. BOOL success;
  128. success = AllocateAndInitializeSid(&auth, 2,
  129. SECURITY_BUILTIN_DOMAIN_RID,
  130. DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0,
  131. 0, 0, &admin_group);
  132. if (success) {
  133. if (!CheckTokenMembership(NULL, admin_group, &success))
  134. success = false;
  135. FreeSid(admin_group);
  136. }
  137. blog(LOG_INFO, "Running as administrator: %s",
  138. success ? "true" : "false");
  139. }
  140. #define WIN10_GAME_BAR_REG_KEY \
  141. L"Software\\Microsoft\\Windows\\CurrentVersion\\GameDVR"
  142. #define WIN10_GAME_DVR_POLICY_REG_KEY \
  143. L"SOFTWARE\\Policies\\Microsoft\\Windows\\GameDVR"
  144. #define WIN10_GAME_DVR_REG_KEY L"System\\GameConfigStore"
  145. #define WIN10_GAME_MODE_REG_KEY L"Software\\Microsoft\\GameBar"
  146. static void log_gaming_features(void)
  147. {
  148. if (win_ver < 0xA00)
  149. return;
  150. struct reg_dword game_bar_enabled;
  151. struct reg_dword game_dvr_allowed;
  152. struct reg_dword game_dvr_enabled;
  153. struct reg_dword game_dvr_bg_recording;
  154. struct reg_dword game_mode_enabled;
  155. get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_BAR_REG_KEY,
  156. L"AppCaptureEnabled", &game_bar_enabled);
  157. get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_DVR_POLICY_REG_KEY,
  158. L"AllowGameDVR", &game_dvr_allowed);
  159. get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_DVR_REG_KEY,
  160. L"GameDVR_Enabled", &game_dvr_enabled);
  161. get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_BAR_REG_KEY,
  162. L"HistoricalCaptureEnabled", &game_dvr_bg_recording);
  163. get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_MODE_REG_KEY,
  164. L"AutoGameModeEnabled", &game_mode_enabled);
  165. if (game_mode_enabled.status != ERROR_SUCCESS) {
  166. get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_MODE_REG_KEY,
  167. L"AllowAutoGameMode", &game_mode_enabled);
  168. }
  169. blog(LOG_INFO, "Windows 10/11 Gaming Features:");
  170. if (game_bar_enabled.status == ERROR_SUCCESS) {
  171. blog(LOG_INFO, "\tGame Bar: %s",
  172. (bool)game_bar_enabled.return_value ? "On" : "Off");
  173. }
  174. if (game_dvr_allowed.status == ERROR_SUCCESS) {
  175. blog(LOG_INFO, "\tGame DVR Allowed: %s",
  176. (bool)game_dvr_allowed.return_value ? "Yes" : "No");
  177. }
  178. if (game_dvr_enabled.status == ERROR_SUCCESS) {
  179. blog(LOG_INFO, "\tGame DVR: %s",
  180. (bool)game_dvr_enabled.return_value ? "On" : "Off");
  181. }
  182. if (game_dvr_bg_recording.status == ERROR_SUCCESS) {
  183. blog(LOG_INFO, "\tGame DVR Background Recording: %s",
  184. (bool)game_dvr_bg_recording.return_value ? "On" : "Off");
  185. }
  186. if (game_mode_enabled.status == ERROR_SUCCESS) {
  187. blog(LOG_INFO, "\tGame Mode: %s",
  188. (bool)game_mode_enabled.return_value ? "On" : "Off");
  189. } else if (win_build >= 19042) {
  190. // On by default in newer Windows 10 builds (no registry key set)
  191. blog(LOG_INFO, "\tGame Mode: Probably On (no reg key set)");
  192. }
  193. }
  194. static const char *get_str_for_state(int state)
  195. {
  196. switch (state) {
  197. case WSC_SECURITY_PRODUCT_STATE_ON:
  198. return "enabled";
  199. case WSC_SECURITY_PRODUCT_STATE_OFF:
  200. return "disabled";
  201. case WSC_SECURITY_PRODUCT_STATE_SNOOZED:
  202. return "temporarily disabled";
  203. case WSC_SECURITY_PRODUCT_STATE_EXPIRED:
  204. return "expired";
  205. default:
  206. return "unknown";
  207. }
  208. }
  209. static const char *get_str_for_type(int type)
  210. {
  211. switch (type) {
  212. case WSC_SECURITY_PROVIDER_ANTIVIRUS:
  213. return "AV";
  214. case WSC_SECURITY_PROVIDER_FIREWALL:
  215. return "FW";
  216. case WSC_SECURITY_PROVIDER_ANTISPYWARE:
  217. return "ASW";
  218. default:
  219. return "unknown";
  220. }
  221. }
  222. static void log_security_products_by_type(IWSCProductList *prod_list, int type)
  223. {
  224. HRESULT hr;
  225. LONG count = 0;
  226. IWscProduct *prod;
  227. BSTR name;
  228. WSC_SECURITY_PRODUCT_STATE prod_state;
  229. hr = prod_list->lpVtbl->Initialize(prod_list, type);
  230. if (FAILED(hr))
  231. return;
  232. hr = prod_list->lpVtbl->get_Count(prod_list, &count);
  233. if (FAILED(hr)) {
  234. prod_list->lpVtbl->Release(prod_list);
  235. return;
  236. }
  237. for (int i = 0; i < count; i++) {
  238. hr = prod_list->lpVtbl->get_Item(prod_list, i, &prod);
  239. if (FAILED(hr))
  240. continue;
  241. hr = prod->lpVtbl->get_ProductName(prod, &name);
  242. if (FAILED(hr))
  243. continue;
  244. hr = prod->lpVtbl->get_ProductState(prod, &prod_state);
  245. if (FAILED(hr)) {
  246. SysFreeString(name);
  247. continue;
  248. }
  249. char *product_name;
  250. os_wcs_to_utf8_ptr(name, 0, &product_name);
  251. blog(LOG_INFO, "\t%s: %s (%s)", product_name,
  252. get_str_for_state(prod_state), get_str_for_type(type));
  253. bfree(product_name);
  254. SysFreeString(name);
  255. prod->lpVtbl->Release(prod);
  256. }
  257. prod_list->lpVtbl->Release(prod_list);
  258. }
  259. static void log_security_products(void)
  260. {
  261. IWSCProductList *prod_list = NULL;
  262. HMODULE h_wsc;
  263. HRESULT hr;
  264. /* We load the DLL rather than import wcsapi.lib because the clsid /
  265. * iid only exists on Windows 8 or higher. */
  266. h_wsc = LoadLibraryW(L"wscapi.dll");
  267. if (!h_wsc)
  268. return;
  269. const CLSID *prod_list_clsid =
  270. (const CLSID *)GetProcAddress(h_wsc, "CLSID_WSCProductList");
  271. const IID *prod_list_iid =
  272. (const IID *)GetProcAddress(h_wsc, "IID_IWSCProductList");
  273. if (prod_list_clsid && prod_list_iid) {
  274. blog(LOG_INFO, "Sec. Software Status:");
  275. hr = CoCreateInstance(prod_list_clsid, NULL,
  276. CLSCTX_INPROC_SERVER, prod_list_iid,
  277. &prod_list);
  278. if (!FAILED(hr)) {
  279. log_security_products_by_type(
  280. prod_list, WSC_SECURITY_PROVIDER_ANTIVIRUS);
  281. }
  282. hr = CoCreateInstance(prod_list_clsid, NULL,
  283. CLSCTX_INPROC_SERVER, prod_list_iid,
  284. &prod_list);
  285. if (!FAILED(hr)) {
  286. log_security_products_by_type(
  287. prod_list, WSC_SECURITY_PROVIDER_FIREWALL);
  288. }
  289. hr = CoCreateInstance(prod_list_clsid, NULL,
  290. CLSCTX_INPROC_SERVER, prod_list_iid,
  291. &prod_list);
  292. if (!FAILED(hr)) {
  293. log_security_products_by_type(
  294. prod_list, WSC_SECURITY_PROVIDER_ANTISPYWARE);
  295. }
  296. }
  297. FreeLibrary(h_wsc);
  298. }
  299. void log_system_info(void)
  300. {
  301. struct win_version_info ver;
  302. get_win_ver(&ver);
  303. win_ver = (ver.major << 8) | ver.minor;
  304. win_build = ver.build;
  305. log_processor_info();
  306. log_processor_cores();
  307. log_available_memory();
  308. log_windows_version();
  309. log_emulation_status();
  310. log_admin_status();
  311. log_gaming_features();
  312. log_security_products();
  313. }
  314. struct obs_hotkeys_platform {
  315. int vk_codes[OBS_KEY_LAST_VALUE];
  316. };
  317. static int get_virtual_key(obs_key_t key)
  318. {
  319. switch (key) {
  320. case OBS_KEY_RETURN:
  321. return VK_RETURN;
  322. case OBS_KEY_ESCAPE:
  323. return VK_ESCAPE;
  324. case OBS_KEY_TAB:
  325. return VK_TAB;
  326. case OBS_KEY_BACKTAB:
  327. return VK_OEM_BACKTAB;
  328. case OBS_KEY_BACKSPACE:
  329. return VK_BACK;
  330. case OBS_KEY_INSERT:
  331. return VK_INSERT;
  332. case OBS_KEY_DELETE:
  333. return VK_DELETE;
  334. case OBS_KEY_PAUSE:
  335. return VK_PAUSE;
  336. case OBS_KEY_PRINT:
  337. return VK_SNAPSHOT;
  338. case OBS_KEY_CLEAR:
  339. return VK_CLEAR;
  340. case OBS_KEY_HOME:
  341. return VK_HOME;
  342. case OBS_KEY_END:
  343. return VK_END;
  344. case OBS_KEY_LEFT:
  345. return VK_LEFT;
  346. case OBS_KEY_UP:
  347. return VK_UP;
  348. case OBS_KEY_RIGHT:
  349. return VK_RIGHT;
  350. case OBS_KEY_DOWN:
  351. return VK_DOWN;
  352. case OBS_KEY_PAGEUP:
  353. return VK_PRIOR;
  354. case OBS_KEY_PAGEDOWN:
  355. return VK_NEXT;
  356. case OBS_KEY_SHIFT:
  357. return VK_SHIFT;
  358. case OBS_KEY_CONTROL:
  359. return VK_CONTROL;
  360. case OBS_KEY_ALT:
  361. return VK_MENU;
  362. case OBS_KEY_CAPSLOCK:
  363. return VK_CAPITAL;
  364. case OBS_KEY_NUMLOCK:
  365. return VK_NUMLOCK;
  366. case OBS_KEY_SCROLLLOCK:
  367. return VK_SCROLL;
  368. case OBS_KEY_F1:
  369. return VK_F1;
  370. case OBS_KEY_F2:
  371. return VK_F2;
  372. case OBS_KEY_F3:
  373. return VK_F3;
  374. case OBS_KEY_F4:
  375. return VK_F4;
  376. case OBS_KEY_F5:
  377. return VK_F5;
  378. case OBS_KEY_F6:
  379. return VK_F6;
  380. case OBS_KEY_F7:
  381. return VK_F7;
  382. case OBS_KEY_F8:
  383. return VK_F8;
  384. case OBS_KEY_F9:
  385. return VK_F9;
  386. case OBS_KEY_F10:
  387. return VK_F10;
  388. case OBS_KEY_F11:
  389. return VK_F11;
  390. case OBS_KEY_F12:
  391. return VK_F12;
  392. case OBS_KEY_F13:
  393. return VK_F13;
  394. case OBS_KEY_F14:
  395. return VK_F14;
  396. case OBS_KEY_F15:
  397. return VK_F15;
  398. case OBS_KEY_F16:
  399. return VK_F16;
  400. case OBS_KEY_F17:
  401. return VK_F17;
  402. case OBS_KEY_F18:
  403. return VK_F18;
  404. case OBS_KEY_F19:
  405. return VK_F19;
  406. case OBS_KEY_F20:
  407. return VK_F20;
  408. case OBS_KEY_F21:
  409. return VK_F21;
  410. case OBS_KEY_F22:
  411. return VK_F22;
  412. case OBS_KEY_F23:
  413. return VK_F23;
  414. case OBS_KEY_F24:
  415. return VK_F24;
  416. case OBS_KEY_SPACE:
  417. return VK_SPACE;
  418. case OBS_KEY_APOSTROPHE:
  419. return VK_OEM_7;
  420. case OBS_KEY_PLUS:
  421. return VK_OEM_PLUS;
  422. case OBS_KEY_COMMA:
  423. return VK_OEM_COMMA;
  424. case OBS_KEY_MINUS:
  425. return VK_OEM_MINUS;
  426. case OBS_KEY_PERIOD:
  427. return VK_OEM_PERIOD;
  428. case OBS_KEY_SLASH:
  429. return VK_OEM_2;
  430. case OBS_KEY_0:
  431. return '0';
  432. case OBS_KEY_1:
  433. return '1';
  434. case OBS_KEY_2:
  435. return '2';
  436. case OBS_KEY_3:
  437. return '3';
  438. case OBS_KEY_4:
  439. return '4';
  440. case OBS_KEY_5:
  441. return '5';
  442. case OBS_KEY_6:
  443. return '6';
  444. case OBS_KEY_7:
  445. return '7';
  446. case OBS_KEY_8:
  447. return '8';
  448. case OBS_KEY_9:
  449. return '9';
  450. case OBS_KEY_NUMASTERISK:
  451. return VK_MULTIPLY;
  452. case OBS_KEY_NUMPLUS:
  453. return VK_ADD;
  454. case OBS_KEY_NUMMINUS:
  455. return VK_SUBTRACT;
  456. case OBS_KEY_NUMPERIOD:
  457. return VK_DECIMAL;
  458. case OBS_KEY_NUMSLASH:
  459. return VK_DIVIDE;
  460. case OBS_KEY_NUM0:
  461. return VK_NUMPAD0;
  462. case OBS_KEY_NUM1:
  463. return VK_NUMPAD1;
  464. case OBS_KEY_NUM2:
  465. return VK_NUMPAD2;
  466. case OBS_KEY_NUM3:
  467. return VK_NUMPAD3;
  468. case OBS_KEY_NUM4:
  469. return VK_NUMPAD4;
  470. case OBS_KEY_NUM5:
  471. return VK_NUMPAD5;
  472. case OBS_KEY_NUM6:
  473. return VK_NUMPAD6;
  474. case OBS_KEY_NUM7:
  475. return VK_NUMPAD7;
  476. case OBS_KEY_NUM8:
  477. return VK_NUMPAD8;
  478. case OBS_KEY_NUM9:
  479. return VK_NUMPAD9;
  480. case OBS_KEY_SEMICOLON:
  481. return VK_OEM_1;
  482. case OBS_KEY_A:
  483. return 'A';
  484. case OBS_KEY_B:
  485. return 'B';
  486. case OBS_KEY_C:
  487. return 'C';
  488. case OBS_KEY_D:
  489. return 'D';
  490. case OBS_KEY_E:
  491. return 'E';
  492. case OBS_KEY_F:
  493. return 'F';
  494. case OBS_KEY_G:
  495. return 'G';
  496. case OBS_KEY_H:
  497. return 'H';
  498. case OBS_KEY_I:
  499. return 'I';
  500. case OBS_KEY_J:
  501. return 'J';
  502. case OBS_KEY_K:
  503. return 'K';
  504. case OBS_KEY_L:
  505. return 'L';
  506. case OBS_KEY_M:
  507. return 'M';
  508. case OBS_KEY_N:
  509. return 'N';
  510. case OBS_KEY_O:
  511. return 'O';
  512. case OBS_KEY_P:
  513. return 'P';
  514. case OBS_KEY_Q:
  515. return 'Q';
  516. case OBS_KEY_R:
  517. return 'R';
  518. case OBS_KEY_S:
  519. return 'S';
  520. case OBS_KEY_T:
  521. return 'T';
  522. case OBS_KEY_U:
  523. return 'U';
  524. case OBS_KEY_V:
  525. return 'V';
  526. case OBS_KEY_W:
  527. return 'W';
  528. case OBS_KEY_X:
  529. return 'X';
  530. case OBS_KEY_Y:
  531. return 'Y';
  532. case OBS_KEY_Z:
  533. return 'Z';
  534. case OBS_KEY_BRACKETLEFT:
  535. return VK_OEM_4;
  536. case OBS_KEY_BACKSLASH:
  537. return VK_OEM_5;
  538. case OBS_KEY_BRACKETRIGHT:
  539. return VK_OEM_6;
  540. case OBS_KEY_ASCIITILDE:
  541. return VK_OEM_3;
  542. case OBS_KEY_HENKAN:
  543. return VK_CONVERT;
  544. case OBS_KEY_MUHENKAN:
  545. return VK_NONCONVERT;
  546. case OBS_KEY_KANJI:
  547. return VK_KANJI;
  548. case OBS_KEY_TOUROKU:
  549. return VK_OEM_FJ_TOUROKU;
  550. case OBS_KEY_MASSYO:
  551. return VK_OEM_FJ_MASSHOU;
  552. case OBS_KEY_HANGUL:
  553. return VK_HANGUL;
  554. case OBS_KEY_BACKSLASH_RT102:
  555. return VK_OEM_102;
  556. case OBS_KEY_MOUSE1:
  557. return VK_LBUTTON;
  558. case OBS_KEY_MOUSE2:
  559. return VK_RBUTTON;
  560. case OBS_KEY_MOUSE3:
  561. return VK_MBUTTON;
  562. case OBS_KEY_MOUSE4:
  563. return VK_XBUTTON1;
  564. case OBS_KEY_MOUSE5:
  565. return VK_XBUTTON2;
  566. case OBS_KEY_VK_CANCEL:
  567. return VK_CANCEL;
  568. case OBS_KEY_0x07:
  569. return 0x07;
  570. case OBS_KEY_0x0A:
  571. return 0x0A;
  572. case OBS_KEY_0x0B:
  573. return 0x0B;
  574. case OBS_KEY_0x0E:
  575. return 0x0E;
  576. case OBS_KEY_0x0F:
  577. return 0x0F;
  578. case OBS_KEY_0x16:
  579. return 0x16;
  580. case OBS_KEY_VK_JUNJA:
  581. return VK_JUNJA;
  582. case OBS_KEY_VK_FINAL:
  583. return VK_FINAL;
  584. case OBS_KEY_0x1A:
  585. return 0x1A;
  586. case OBS_KEY_VK_ACCEPT:
  587. return VK_ACCEPT;
  588. case OBS_KEY_VK_MODECHANGE:
  589. return VK_MODECHANGE;
  590. case OBS_KEY_VK_SELECT:
  591. return VK_SELECT;
  592. case OBS_KEY_VK_PRINT:
  593. return VK_PRINT;
  594. case OBS_KEY_VK_EXECUTE:
  595. return VK_EXECUTE;
  596. case OBS_KEY_VK_HELP:
  597. return VK_HELP;
  598. case OBS_KEY_0x30:
  599. return 0x30;
  600. case OBS_KEY_0x31:
  601. return 0x31;
  602. case OBS_KEY_0x32:
  603. return 0x32;
  604. case OBS_KEY_0x33:
  605. return 0x33;
  606. case OBS_KEY_0x34:
  607. return 0x34;
  608. case OBS_KEY_0x35:
  609. return 0x35;
  610. case OBS_KEY_0x36:
  611. return 0x36;
  612. case OBS_KEY_0x37:
  613. return 0x37;
  614. case OBS_KEY_0x38:
  615. return 0x38;
  616. case OBS_KEY_0x39:
  617. return 0x39;
  618. case OBS_KEY_0x3A:
  619. return 0x3A;
  620. case OBS_KEY_0x3B:
  621. return 0x3B;
  622. case OBS_KEY_0x3C:
  623. return 0x3C;
  624. case OBS_KEY_0x3D:
  625. return 0x3D;
  626. case OBS_KEY_0x3E:
  627. return 0x3E;
  628. case OBS_KEY_0x3F:
  629. return 0x3F;
  630. case OBS_KEY_0x40:
  631. return 0x40;
  632. case OBS_KEY_0x41:
  633. return 0x41;
  634. case OBS_KEY_0x42:
  635. return 0x42;
  636. case OBS_KEY_0x43:
  637. return 0x43;
  638. case OBS_KEY_0x44:
  639. return 0x44;
  640. case OBS_KEY_0x45:
  641. return 0x45;
  642. case OBS_KEY_0x46:
  643. return 0x46;
  644. case OBS_KEY_0x47:
  645. return 0x47;
  646. case OBS_KEY_0x48:
  647. return 0x48;
  648. case OBS_KEY_0x49:
  649. return 0x49;
  650. case OBS_KEY_0x4A:
  651. return 0x4A;
  652. case OBS_KEY_0x4B:
  653. return 0x4B;
  654. case OBS_KEY_0x4C:
  655. return 0x4C;
  656. case OBS_KEY_0x4D:
  657. return 0x4D;
  658. case OBS_KEY_0x4E:
  659. return 0x4E;
  660. case OBS_KEY_0x4F:
  661. return 0x4F;
  662. case OBS_KEY_0x50:
  663. return 0x50;
  664. case OBS_KEY_0x51:
  665. return 0x51;
  666. case OBS_KEY_0x52:
  667. return 0x52;
  668. case OBS_KEY_0x53:
  669. return 0x53;
  670. case OBS_KEY_0x54:
  671. return 0x54;
  672. case OBS_KEY_0x55:
  673. return 0x55;
  674. case OBS_KEY_0x56:
  675. return 0x56;
  676. case OBS_KEY_0x57:
  677. return 0x57;
  678. case OBS_KEY_0x58:
  679. return 0x58;
  680. case OBS_KEY_0x59:
  681. return 0x59;
  682. case OBS_KEY_0x5A:
  683. return 0x5A;
  684. case OBS_KEY_VK_LWIN:
  685. return VK_LWIN;
  686. case OBS_KEY_VK_RWIN:
  687. return VK_RWIN;
  688. case OBS_KEY_VK_APPS:
  689. return VK_APPS;
  690. case OBS_KEY_0x5E:
  691. return 0x5E;
  692. case OBS_KEY_VK_SLEEP:
  693. return VK_SLEEP;
  694. case OBS_KEY_VK_SEPARATOR:
  695. return VK_SEPARATOR;
  696. case OBS_KEY_0x88:
  697. return 0x88;
  698. case OBS_KEY_0x89:
  699. return 0x89;
  700. case OBS_KEY_0x8A:
  701. return 0x8A;
  702. case OBS_KEY_0x8B:
  703. return 0x8B;
  704. case OBS_KEY_0x8C:
  705. return 0x8C;
  706. case OBS_KEY_0x8D:
  707. return 0x8D;
  708. case OBS_KEY_0x8E:
  709. return 0x8E;
  710. case OBS_KEY_0x8F:
  711. return 0x8F;
  712. case OBS_KEY_VK_OEM_FJ_JISHO:
  713. return VK_OEM_FJ_JISHO;
  714. case OBS_KEY_VK_OEM_FJ_LOYA:
  715. return VK_OEM_FJ_LOYA;
  716. case OBS_KEY_VK_OEM_FJ_ROYA:
  717. return VK_OEM_FJ_ROYA;
  718. case OBS_KEY_0x97:
  719. return 0x97;
  720. case OBS_KEY_0x98:
  721. return 0x98;
  722. case OBS_KEY_0x99:
  723. return 0x99;
  724. case OBS_KEY_0x9A:
  725. return 0x9A;
  726. case OBS_KEY_0x9B:
  727. return 0x9B;
  728. case OBS_KEY_0x9C:
  729. return 0x9C;
  730. case OBS_KEY_0x9D:
  731. return 0x9D;
  732. case OBS_KEY_0x9E:
  733. return 0x9E;
  734. case OBS_KEY_0x9F:
  735. return 0x9F;
  736. case OBS_KEY_VK_LSHIFT:
  737. return VK_LSHIFT;
  738. case OBS_KEY_VK_RSHIFT:
  739. return VK_RSHIFT;
  740. case OBS_KEY_VK_LCONTROL:
  741. return VK_LCONTROL;
  742. case OBS_KEY_VK_RCONTROL:
  743. return VK_RCONTROL;
  744. case OBS_KEY_VK_LMENU:
  745. return VK_LMENU;
  746. case OBS_KEY_VK_RMENU:
  747. return VK_RMENU;
  748. case OBS_KEY_VK_BROWSER_BACK:
  749. return VK_BROWSER_BACK;
  750. case OBS_KEY_VK_BROWSER_FORWARD:
  751. return VK_BROWSER_FORWARD;
  752. case OBS_KEY_VK_BROWSER_REFRESH:
  753. return VK_BROWSER_REFRESH;
  754. case OBS_KEY_VK_BROWSER_STOP:
  755. return VK_BROWSER_STOP;
  756. case OBS_KEY_VK_BROWSER_SEARCH:
  757. return VK_BROWSER_SEARCH;
  758. case OBS_KEY_VK_BROWSER_FAVORITES:
  759. return VK_BROWSER_FAVORITES;
  760. case OBS_KEY_VK_BROWSER_HOME:
  761. return VK_BROWSER_HOME;
  762. case OBS_KEY_VK_VOLUME_MUTE:
  763. return VK_VOLUME_MUTE;
  764. case OBS_KEY_VK_VOLUME_DOWN:
  765. return VK_VOLUME_DOWN;
  766. case OBS_KEY_VK_VOLUME_UP:
  767. return VK_VOLUME_UP;
  768. case OBS_KEY_VK_MEDIA_NEXT_TRACK:
  769. return VK_MEDIA_NEXT_TRACK;
  770. case OBS_KEY_VK_MEDIA_PREV_TRACK:
  771. return VK_MEDIA_PREV_TRACK;
  772. case OBS_KEY_VK_MEDIA_STOP:
  773. return VK_MEDIA_STOP;
  774. case OBS_KEY_VK_MEDIA_PLAY_PAUSE:
  775. return VK_MEDIA_PLAY_PAUSE;
  776. case OBS_KEY_VK_LAUNCH_MAIL:
  777. return VK_LAUNCH_MAIL;
  778. case OBS_KEY_VK_LAUNCH_MEDIA_SELECT:
  779. return VK_LAUNCH_MEDIA_SELECT;
  780. case OBS_KEY_VK_LAUNCH_APP1:
  781. return VK_LAUNCH_APP1;
  782. case OBS_KEY_VK_LAUNCH_APP2:
  783. return VK_LAUNCH_APP2;
  784. case OBS_KEY_0xB8:
  785. return 0xB8;
  786. case OBS_KEY_0xB9:
  787. return 0xB9;
  788. case OBS_KEY_0xC1:
  789. return 0xC1;
  790. case OBS_KEY_0xC2:
  791. return 0xC2;
  792. case OBS_KEY_0xC3:
  793. return 0xC3;
  794. case OBS_KEY_0xC4:
  795. return 0xC4;
  796. case OBS_KEY_0xC5:
  797. return 0xC5;
  798. case OBS_KEY_0xC6:
  799. return 0xC6;
  800. case OBS_KEY_0xC7:
  801. return 0xC7;
  802. case OBS_KEY_0xC8:
  803. return 0xC8;
  804. case OBS_KEY_0xC9:
  805. return 0xC9;
  806. case OBS_KEY_0xCA:
  807. return 0xCA;
  808. case OBS_KEY_0xCB:
  809. return 0xCB;
  810. case OBS_KEY_0xCC:
  811. return 0xCC;
  812. case OBS_KEY_0xCD:
  813. return 0xCD;
  814. case OBS_KEY_0xCE:
  815. return 0xCE;
  816. case OBS_KEY_0xCF:
  817. return 0xCF;
  818. case OBS_KEY_0xD0:
  819. return 0xD0;
  820. case OBS_KEY_0xD1:
  821. return 0xD1;
  822. case OBS_KEY_0xD2:
  823. return 0xD2;
  824. case OBS_KEY_0xD3:
  825. return 0xD3;
  826. case OBS_KEY_0xD4:
  827. return 0xD4;
  828. case OBS_KEY_0xD5:
  829. return 0xD5;
  830. case OBS_KEY_0xD6:
  831. return 0xD6;
  832. case OBS_KEY_0xD7:
  833. return 0xD7;
  834. case OBS_KEY_0xD8:
  835. return 0xD8;
  836. case OBS_KEY_0xD9:
  837. return 0xD9;
  838. case OBS_KEY_0xDA:
  839. return 0xDA;
  840. case OBS_KEY_VK_OEM_8:
  841. return VK_OEM_8;
  842. case OBS_KEY_0xE0:
  843. return 0xE0;
  844. case OBS_KEY_VK_OEM_AX:
  845. return VK_OEM_AX;
  846. case OBS_KEY_VK_ICO_HELP:
  847. return VK_ICO_HELP;
  848. case OBS_KEY_VK_ICO_00:
  849. return VK_ICO_00;
  850. case OBS_KEY_VK_PROCESSKEY:
  851. return VK_PROCESSKEY;
  852. case OBS_KEY_VK_ICO_CLEAR:
  853. return VK_ICO_CLEAR;
  854. case OBS_KEY_VK_PACKET:
  855. return VK_PACKET;
  856. case OBS_KEY_0xE8:
  857. return 0xE8;
  858. case OBS_KEY_VK_OEM_RESET:
  859. return VK_OEM_RESET;
  860. case OBS_KEY_VK_OEM_JUMP:
  861. return VK_OEM_JUMP;
  862. case OBS_KEY_VK_OEM_PA1:
  863. return VK_OEM_PA1;
  864. case OBS_KEY_VK_OEM_PA2:
  865. return VK_OEM_PA2;
  866. case OBS_KEY_VK_OEM_PA3:
  867. return VK_OEM_PA3;
  868. case OBS_KEY_VK_OEM_WSCTRL:
  869. return VK_OEM_WSCTRL;
  870. case OBS_KEY_VK_OEM_CUSEL:
  871. return VK_OEM_CUSEL;
  872. case OBS_KEY_VK_OEM_ATTN:
  873. return VK_OEM_ATTN;
  874. case OBS_KEY_VK_OEM_FINISH:
  875. return VK_OEM_FINISH;
  876. case OBS_KEY_VK_OEM_COPY:
  877. return VK_OEM_COPY;
  878. case OBS_KEY_VK_OEM_AUTO:
  879. return VK_OEM_AUTO;
  880. case OBS_KEY_VK_OEM_ENLW:
  881. return VK_OEM_ENLW;
  882. case OBS_KEY_VK_ATTN:
  883. return VK_ATTN;
  884. case OBS_KEY_VK_CRSEL:
  885. return VK_CRSEL;
  886. case OBS_KEY_VK_EXSEL:
  887. return VK_EXSEL;
  888. case OBS_KEY_VK_EREOF:
  889. return VK_EREOF;
  890. case OBS_KEY_VK_PLAY:
  891. return VK_PLAY;
  892. case OBS_KEY_VK_ZOOM:
  893. return VK_ZOOM;
  894. case OBS_KEY_VK_NONAME:
  895. return VK_NONAME;
  896. case OBS_KEY_VK_PA1:
  897. return VK_PA1;
  898. case OBS_KEY_VK_OEM_CLEAR:
  899. return VK_OEM_CLEAR;
  900. /* TODO: Implement keys for non-US keyboards */
  901. default:;
  902. }
  903. return 0;
  904. }
  905. bool obs_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys)
  906. {
  907. hotkeys->platform_context = bzalloc(sizeof(obs_hotkeys_platform_t));
  908. for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++)
  909. hotkeys->platform_context->vk_codes[i] = get_virtual_key(i);
  910. return true;
  911. }
  912. void obs_hotkeys_platform_free(struct obs_core_hotkeys *hotkeys)
  913. {
  914. bfree(hotkeys->platform_context);
  915. hotkeys->platform_context = NULL;
  916. }
  917. static bool vk_down(DWORD vk)
  918. {
  919. short state = GetAsyncKeyState(vk);
  920. bool down = (state & 0x8000) != 0;
  921. return down;
  922. }
  923. bool obs_hotkeys_platform_is_pressed(obs_hotkeys_platform_t *context,
  924. obs_key_t key)
  925. {
  926. if (key == OBS_KEY_META) {
  927. return vk_down(VK_LWIN) || vk_down(VK_RWIN);
  928. }
  929. UNUSED_PARAMETER(context);
  930. return vk_down(obs_key_to_virtual_key(key));
  931. }
  932. void obs_key_to_str(obs_key_t key, struct dstr *str)
  933. {
  934. wchar_t name[128] = L"";
  935. UINT scan_code;
  936. int vk;
  937. if (key == OBS_KEY_NONE) {
  938. return;
  939. } else if (key >= OBS_KEY_F13 && key <= OBS_KEY_F24) {
  940. dstr_printf(str, "F%d", (int)(key - OBS_KEY_F13 + 13));
  941. return;
  942. } else if (key >= OBS_KEY_MOUSE1 && key <= OBS_KEY_MOUSE29) {
  943. if (obs->hotkeys.translations[key]) {
  944. dstr_copy(str, obs->hotkeys.translations[key]);
  945. } else {
  946. dstr_printf(str, "Mouse %d",
  947. (int)(key - OBS_KEY_MOUSE1 + 1));
  948. }
  949. return;
  950. }
  951. if (key == OBS_KEY_PAUSE) {
  952. dstr_copy(str, obs_get_hotkey_translation(key, "Pause"));
  953. return;
  954. } else if (key == OBS_KEY_META) {
  955. dstr_copy(str, obs_get_hotkey_translation(key, "Windows"));
  956. return;
  957. }
  958. vk = obs_key_to_virtual_key(key);
  959. scan_code = MapVirtualKey(vk, 0) << 16;
  960. switch (vk) {
  961. case VK_HOME:
  962. case VK_END:
  963. case VK_LEFT:
  964. case VK_UP:
  965. case VK_RIGHT:
  966. case VK_DOWN:
  967. case VK_PRIOR:
  968. case VK_NEXT:
  969. case VK_INSERT:
  970. case VK_DELETE:
  971. case VK_NUMLOCK:
  972. scan_code |= 0x01000000;
  973. }
  974. if ((key < OBS_KEY_VK_CANCEL || key > OBS_KEY_VK_OEM_CLEAR) &&
  975. scan_code != 0 && GetKeyNameTextW(scan_code, name, 128) != 0) {
  976. dstr_from_wcs(str, name);
  977. } else if (key != OBS_KEY_NONE) {
  978. dstr_copy(str, obs_key_to_name(key));
  979. }
  980. }
  981. obs_key_t obs_key_from_virtual_key(int code)
  982. {
  983. obs_hotkeys_platform_t *platform = obs->hotkeys.platform_context;
  984. for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++) {
  985. if (platform->vk_codes[i] == code) {
  986. return (obs_key_t)i;
  987. }
  988. }
  989. return OBS_KEY_NONE;
  990. }
  991. int obs_key_to_virtual_key(obs_key_t key)
  992. {
  993. if (key == OBS_KEY_META)
  994. return VK_LWIN;
  995. return obs->hotkeys.platform_context->vk_codes[(int)key];
  996. }
  997. static inline void add_combo_key(obs_key_t key, struct dstr *str)
  998. {
  999. struct dstr key_str = {0};
  1000. obs_key_to_str(key, &key_str);
  1001. if (!dstr_is_empty(&key_str)) {
  1002. if (!dstr_is_empty(str)) {
  1003. dstr_cat(str, " + ");
  1004. }
  1005. dstr_cat_dstr(str, &key_str);
  1006. }
  1007. dstr_free(&key_str);
  1008. }
  1009. void obs_key_combination_to_str(obs_key_combination_t combination,
  1010. struct dstr *str)
  1011. {
  1012. if ((combination.modifiers & INTERACT_CONTROL_KEY) != 0) {
  1013. add_combo_key(OBS_KEY_CONTROL, str);
  1014. }
  1015. if ((combination.modifiers & INTERACT_COMMAND_KEY) != 0) {
  1016. add_combo_key(OBS_KEY_META, str);
  1017. }
  1018. if ((combination.modifiers & INTERACT_ALT_KEY) != 0) {
  1019. add_combo_key(OBS_KEY_ALT, str);
  1020. }
  1021. if ((combination.modifiers & INTERACT_SHIFT_KEY) != 0) {
  1022. add_combo_key(OBS_KEY_SHIFT, str);
  1023. }
  1024. if (combination.key != OBS_KEY_NONE) {
  1025. add_combo_key(combination.key, str);
  1026. }
  1027. }
  1028. bool sym_initialize_called = false;
  1029. void reset_win32_symbol_paths(void)
  1030. {
  1031. static BOOL(WINAPI * sym_initialize_w)(HANDLE, const wchar_t *, BOOL);
  1032. static BOOL(WINAPI * sym_set_search_path_w)(HANDLE, const wchar_t *);
  1033. static bool funcs_initialized = false;
  1034. static bool initialize_success = false;
  1035. struct obs_module *module = obs->first_module;
  1036. struct dstr path_str = {0};
  1037. DARRAY(char *) paths;
  1038. wchar_t *path_str_w = NULL;
  1039. char *abspath;
  1040. da_init(paths);
  1041. if (!funcs_initialized) {
  1042. HMODULE mod;
  1043. funcs_initialized = true;
  1044. mod = LoadLibraryW(L"DbgHelp");
  1045. if (!mod)
  1046. return;
  1047. sym_initialize_w =
  1048. (void *)GetProcAddress(mod, "SymInitializeW");
  1049. sym_set_search_path_w =
  1050. (void *)GetProcAddress(mod, "SymSetSearchPathW");
  1051. if (!sym_initialize_w || !sym_set_search_path_w) {
  1052. FreeLibrary(mod);
  1053. return;
  1054. }
  1055. initialize_success = true;
  1056. // Leaks 'mod' once.
  1057. }
  1058. if (!initialize_success)
  1059. return;
  1060. abspath = os_get_abs_path_ptr(".");
  1061. if (abspath)
  1062. da_push_back(paths, &abspath);
  1063. while (module) {
  1064. bool found = false;
  1065. struct dstr path = {0};
  1066. char *path_end;
  1067. dstr_copy(&path, module->bin_path);
  1068. dstr_replace(&path, "/", "\\");
  1069. path_end = strrchr(path.array, '\\');
  1070. if (!path_end) {
  1071. module = module->next;
  1072. dstr_free(&path);
  1073. continue;
  1074. }
  1075. *path_end = 0;
  1076. for (size_t i = 0; i < paths.num; i++) {
  1077. const char *existing_path = paths.array[i];
  1078. if (astrcmpi(path.array, existing_path) == 0) {
  1079. found = true;
  1080. break;
  1081. }
  1082. }
  1083. if (!found) {
  1084. abspath = os_get_abs_path_ptr(path.array);
  1085. if (abspath)
  1086. da_push_back(paths, &abspath);
  1087. }
  1088. dstr_free(&path);
  1089. module = module->next;
  1090. }
  1091. for (size_t i = 0; i < paths.num; i++) {
  1092. const char *path = paths.array[i];
  1093. if (path && *path) {
  1094. if (i != 0)
  1095. dstr_cat(&path_str, ";");
  1096. dstr_cat(&path_str, paths.array[i]);
  1097. }
  1098. }
  1099. if (path_str.array) {
  1100. os_utf8_to_wcs_ptr(path_str.array, path_str.len, &path_str_w);
  1101. if (path_str_w) {
  1102. if (!sym_initialize_called) {
  1103. sym_initialize_w(GetCurrentProcess(),
  1104. path_str_w, false);
  1105. sym_initialize_called = true;
  1106. } else {
  1107. sym_set_search_path_w(GetCurrentProcess(),
  1108. path_str_w);
  1109. }
  1110. bfree(path_str_w);
  1111. }
  1112. }
  1113. for (size_t i = 0; i < paths.num; i++)
  1114. bfree(paths.array[i]);
  1115. dstr_free(&path_str);
  1116. da_free(paths);
  1117. }
  1118. extern void initialize_crash_handler(void);
  1119. void obs_init_win32_crash_handler(void)
  1120. {
  1121. initialize_crash_handler();
  1122. }
  1123. bool initialize_com(void)
  1124. {
  1125. const HRESULT hr = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
  1126. const bool success = SUCCEEDED(hr);
  1127. if (!success)
  1128. blog(LOG_ERROR, "CoInitializeEx failed: 0x%08X", hr);
  1129. return success;
  1130. }
  1131. void uninitialize_com(void)
  1132. {
  1133. CoUninitialize();
  1134. }