mirror of
https://github.com/libretro/RetroArch
synced 2025-02-01 09:32:58 +00:00
430baf7c21
This can fix a lot of performance issues, like audio crackling and frame time spikes. This requires the GameMode package to be installed. See: https://github.com/FeralInteractive/gamemode This commit adds a "Game Mode" bool option to the "Power Management" and "Latency" settings sections, and it can be toggled on/off without restarting RA. The actual toggling of game mode happens in a new frontend platform interface function. Perhaps this will become useful for other platforms that provide some equivalent of Linux GameMode. Since the GameMode ABI is fixed, and the API comes as a single, header-only file with no actual deps, we simply bundle the header (deps/feralgamemode/gamemode_client.h.) That way, all Linux builds will have support for GameMode regardless of whether the GameMode development package is installed or not.
1177 lines
35 KiB
C
1177 lines
35 KiB
C
/* RetroArch - A frontend for libretro.
|
|
* Copyright (C) 2011-2017 - Daniel De Matteis
|
|
* Copyright (C) 2016-2019 - Brad Parker
|
|
* Copyright (C) 2018-2019 - Andrés Suárez
|
|
*
|
|
* RetroArch 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 Found-
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* RetroArch 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 RetroArch.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#include <retro_miscellaneous.h>
|
|
#include <windows.h>
|
|
#if defined(_WIN32) && !defined(_XBOX)
|
|
#include <process.h>
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
#include <boolean.h>
|
|
#include <compat/strl.h>
|
|
#include <dynamic/dylib.h>
|
|
#include <lists/file_list.h>
|
|
#include <file/file_path.h>
|
|
#include <string/stdstring.h>
|
|
#include <encodings/utf.h>
|
|
#include <features/features_cpu.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "../../config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_MENU
|
|
#include "../../menu/menu_driver.h"
|
|
#endif
|
|
|
|
#include "../frontend_driver.h"
|
|
#include "../../configuration.h"
|
|
#include "../../defaults.h"
|
|
#include "../../verbosity.h"
|
|
#include "../../ui/drivers/ui_win32.h"
|
|
#include "../../paths.h"
|
|
#include "../../msg_hash.h"
|
|
#include "platform_win32.h"
|
|
|
|
#include "../../verbosity.h"
|
|
|
|
/*
|
|
#ifdef HAVE_NVDA
|
|
#include "../../nvda_controller.h"
|
|
#endif
|
|
*/
|
|
|
|
#ifdef HAVE_SAPI
|
|
#define COBJMACROS
|
|
#include <sapi.h>
|
|
#include <ole2.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SAPI
|
|
static ISpVoice* pVoice = NULL;
|
|
#endif
|
|
#ifdef HAVE_NVDA
|
|
static bool USE_POWERSHELL = false;
|
|
static bool USE_NVDA = true;
|
|
#else
|
|
static bool USE_POWERSHELL = true;
|
|
static bool USE_NVDA = false;
|
|
#endif
|
|
static bool USE_NVDA_BRAILLE = false;
|
|
|
|
#ifndef SM_SERVERR2
|
|
#define SM_SERVERR2 89
|
|
#endif
|
|
|
|
/* static public global variable */
|
|
VOID (WINAPI *DragAcceptFiles_func)(HWND, BOOL);
|
|
|
|
/* TODO/FIXME - static global variables */
|
|
static bool dwm_composition_disabled = false;
|
|
static bool console_needs_free = false;
|
|
static char win32_cpu_model_name[64] = {0};
|
|
static bool pi_set = false;
|
|
#ifdef HAVE_DYNAMIC
|
|
/* We only load this library once, so we let it be
|
|
* unloaded at application shutdown, since unloading
|
|
* it early seems to cause issues on some systems.
|
|
*/
|
|
static dylib_t dwmlib;
|
|
static dylib_t shell32lib;
|
|
static dylib_t nvdalib;
|
|
#endif
|
|
|
|
/* Dynamic loading for Non-Visual Desktop Access support */
|
|
unsigned long (__stdcall *nvdaController_testIfRunning_func)(void);
|
|
unsigned long (__stdcall *nvdaController_cancelSpeech_func)(void);
|
|
unsigned long (__stdcall *nvdaController_brailleMessage_func)(wchar_t*);
|
|
unsigned long (__stdcall *nvdaController_speakText_func)(wchar_t*);
|
|
|
|
#if defined(HAVE_LANGEXTRA) && !defined(_XBOX)
|
|
#if (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500) || !defined(_MSC_VER)
|
|
struct win32_lang_pair
|
|
{
|
|
unsigned short lang_ident;
|
|
enum retro_language lang;
|
|
};
|
|
|
|
/* https://docs.microsoft.com/en-us/windows/desktop/Intl/language-identifier-constants-and-strings */
|
|
const struct win32_lang_pair win32_lang_pairs[] =
|
|
{
|
|
/* array order MUST be kept, always largest ID first */
|
|
{0x7c04, RETRO_LANGUAGE_CHINESE_TRADITIONAL}, /* neutral */
|
|
{0x1404, RETRO_LANGUAGE_CHINESE_TRADITIONAL}, /* MO */
|
|
{0x1004, RETRO_LANGUAGE_CHINESE_SIMPLIFIED}, /* SG */
|
|
{0xC04, RETRO_LANGUAGE_CHINESE_TRADITIONAL}, /* HK/PRC */
|
|
{0x816, RETRO_LANGUAGE_PORTUGUESE_PORTUGAL},
|
|
{0x416, RETRO_LANGUAGE_PORTUGUESE_BRAZIL},
|
|
{0x2a, RETRO_LANGUAGE_VIETNAMESE},
|
|
{0x19, RETRO_LANGUAGE_RUSSIAN},
|
|
{0x16, RETRO_LANGUAGE_PORTUGUESE_PORTUGAL},
|
|
{0x15, RETRO_LANGUAGE_POLISH},
|
|
{0x13, RETRO_LANGUAGE_DUTCH},
|
|
{0x12, RETRO_LANGUAGE_KOREAN},
|
|
{0x11, RETRO_LANGUAGE_JAPANESE},
|
|
{0x10, RETRO_LANGUAGE_ITALIAN},
|
|
{0xc, RETRO_LANGUAGE_FRENCH},
|
|
{0xa, RETRO_LANGUAGE_SPANISH},
|
|
{0x9, RETRO_LANGUAGE_ENGLISH},
|
|
{0x8, RETRO_LANGUAGE_GREEK},
|
|
{0x7, RETRO_LANGUAGE_GERMAN},
|
|
{0x4, RETRO_LANGUAGE_CHINESE_SIMPLIFIED}, /* neutral */
|
|
{0x1, RETRO_LANGUAGE_ARABIC},
|
|
/* MS does not support Esperanto */
|
|
/*{0x0, RETRO_LANGUAGE_ESPERANTO},*/
|
|
};
|
|
|
|
unsigned short win32_get_langid_from_retro_lang(enum retro_language lang)
|
|
{
|
|
unsigned i;
|
|
|
|
for (i = 0; i < sizeof(win32_lang_pairs) / sizeof(win32_lang_pairs[0]); i++)
|
|
{
|
|
if (win32_lang_pairs[i].lang == lang)
|
|
return win32_lang_pairs[i].lang_ident;
|
|
}
|
|
|
|
return 0x409; /* fallback to US English */
|
|
}
|
|
|
|
enum retro_language win32_get_retro_lang_from_langid(unsigned short langid)
|
|
{
|
|
unsigned i;
|
|
|
|
for (i = 0; i < sizeof(win32_lang_pairs) / sizeof(win32_lang_pairs[0]); i++)
|
|
{
|
|
if (win32_lang_pairs[i].lang_ident > 0x3ff)
|
|
{
|
|
if (langid == win32_lang_pairs[i].lang_ident)
|
|
return win32_lang_pairs[i].lang;
|
|
}
|
|
else
|
|
{
|
|
if ((langid & 0x3ff) == win32_lang_pairs[i].lang_ident)
|
|
return win32_lang_pairs[i].lang;
|
|
}
|
|
}
|
|
|
|
return RETRO_LANGUAGE_ENGLISH;
|
|
}
|
|
#endif
|
|
#else
|
|
unsigned short win32_get_langid_from_retro_lang(enum retro_language lang)
|
|
{
|
|
return 0x409; /* fallback to US English */
|
|
}
|
|
|
|
enum retro_language win32_get_retro_lang_from_langid(unsigned short langid)
|
|
{
|
|
return RETRO_LANGUAGE_ENGLISH;
|
|
}
|
|
#endif
|
|
|
|
static void gfx_dwm_shutdown(void)
|
|
{
|
|
#ifdef HAVE_DYNAMIC
|
|
if (dwmlib)
|
|
dylib_close(dwmlib);
|
|
if (shell32lib)
|
|
dylib_close(shell32lib);
|
|
dwmlib = NULL;
|
|
shell32lib = NULL;
|
|
#endif
|
|
}
|
|
|
|
static bool gfx_init_dwm(void)
|
|
{
|
|
HRESULT (WINAPI *mmcss)(BOOL);
|
|
static bool inited = false;
|
|
|
|
if (inited)
|
|
return true;
|
|
|
|
atexit(gfx_dwm_shutdown);
|
|
|
|
#ifdef HAVE_DYNAMIC
|
|
shell32lib = dylib_load("shell32.dll");
|
|
if (!shell32lib)
|
|
{
|
|
RARCH_WARN("Did not find shell32.dll.\n");
|
|
}
|
|
|
|
dwmlib = dylib_load("dwmapi.dll");
|
|
if (!dwmlib)
|
|
{
|
|
RARCH_WARN("Did not find dwmapi.dll.\n");
|
|
return false;
|
|
}
|
|
|
|
DragAcceptFiles_func =
|
|
(VOID (WINAPI*)(HWND, BOOL))dylib_proc(shell32lib, "DragAcceptFiles");
|
|
|
|
mmcss =
|
|
(HRESULT(WINAPI*)(BOOL))dylib_proc(dwmlib, "DwmEnableMMCSS");
|
|
#else
|
|
DragAcceptFiles_func = DragAcceptFiles;
|
|
#if 0
|
|
mmcss = DwmEnableMMCSS;
|
|
#endif
|
|
#endif
|
|
|
|
if (mmcss)
|
|
mmcss(TRUE);
|
|
|
|
inited = true;
|
|
return true;
|
|
}
|
|
|
|
static void gfx_set_dwm(void)
|
|
{
|
|
HRESULT ret;
|
|
HRESULT (WINAPI *composition_enable)(UINT);
|
|
settings_t *settings = config_get_ptr();
|
|
bool disable_composition = settings->bools.video_disable_composition;
|
|
|
|
if (!gfx_init_dwm())
|
|
return;
|
|
|
|
if (disable_composition == dwm_composition_disabled)
|
|
return;
|
|
|
|
#ifdef HAVE_DYNAMIC
|
|
composition_enable =
|
|
(HRESULT (WINAPI*)(UINT))dylib_proc(dwmlib, "DwmEnableComposition");
|
|
#endif
|
|
|
|
if (!composition_enable)
|
|
{
|
|
RARCH_ERR("Did not find DwmEnableComposition ...\n");
|
|
return;
|
|
}
|
|
|
|
ret = composition_enable(!disable_composition);
|
|
if (FAILED(ret))
|
|
RARCH_ERR("Failed to set composition state ...\n");
|
|
dwm_composition_disabled = disable_composition;
|
|
}
|
|
|
|
static void frontend_win32_get_os(char *s, size_t len, int *major, int *minor)
|
|
{
|
|
char buildStr[11] = {0};
|
|
bool server = false;
|
|
const char *arch = "";
|
|
|
|
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
|
|
/* Windows 2000 and later */
|
|
SYSTEM_INFO si = {{0}};
|
|
OSVERSIONINFOEX vi = {0};
|
|
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
|
|
GetSystemInfo(&si);
|
|
|
|
/* Available from NT 3.5 and Win95 */
|
|
GetVersionEx((OSVERSIONINFO*)&vi);
|
|
|
|
server = vi.wProductType != VER_NT_WORKSTATION;
|
|
|
|
switch (si.wProcessorArchitecture)
|
|
{
|
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
|
arch = "x64";
|
|
break;
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
arch = "x86";
|
|
break;
|
|
case PROCESSOR_ARCHITECTURE_ARM:
|
|
arch = "ARM";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#else
|
|
OSVERSIONINFO vi = {0};
|
|
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
/* Available from NT 3.5 and Win95 */
|
|
GetVersionEx(&vi);
|
|
#endif
|
|
|
|
if (major)
|
|
*major = vi.dwMajorVersion;
|
|
|
|
if (minor)
|
|
*minor = vi.dwMinorVersion;
|
|
|
|
if (vi.dwMajorVersion == 4 && vi.dwMinorVersion == 0)
|
|
snprintf(buildStr, sizeof(buildStr), "%lu", (DWORD)(LOWORD(vi.dwBuildNumber))); /* Windows 95 build number is in the low-order word only */
|
|
else
|
|
snprintf(buildStr, sizeof(buildStr), "%lu", vi.dwBuildNumber);
|
|
|
|
switch (vi.dwMajorVersion)
|
|
{
|
|
case 10:
|
|
if (atoi(buildStr) >= 21996)
|
|
strcpy_literal(s, "Windows 11");
|
|
else if (server)
|
|
strcpy_literal(s, "Windows Server 2016");
|
|
else
|
|
strcpy_literal(s, "Windows 10");
|
|
break;
|
|
case 6:
|
|
switch (vi.dwMinorVersion)
|
|
{
|
|
case 3:
|
|
if (server)
|
|
strcpy_literal(s, "Windows Server 2012 R2");
|
|
else
|
|
strcpy_literal(s, "Windows 8.1");
|
|
break;
|
|
case 2:
|
|
if (server)
|
|
strcpy_literal(s, "Windows Server 2012");
|
|
else
|
|
strcpy_literal(s, "Windows 8");
|
|
break;
|
|
case 1:
|
|
if (server)
|
|
strcpy_literal(s, "Windows Server 2008 R2");
|
|
else
|
|
strcpy_literal(s, "Windows 7");
|
|
break;
|
|
case 0:
|
|
if (server)
|
|
strcpy_literal(s, "Windows Server 2008");
|
|
else
|
|
strcpy_literal(s, "Windows Vista");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case 5:
|
|
switch (vi.dwMinorVersion)
|
|
{
|
|
case 2:
|
|
if (server)
|
|
{
|
|
strcpy_literal(s, "Windows Server 2003");
|
|
if (GetSystemMetrics(SM_SERVERR2))
|
|
strlcat(s, " R2", len);
|
|
}
|
|
else
|
|
{
|
|
/* Yes, XP Pro x64 is a higher version number than XP x86 */
|
|
if (string_is_equal(arch, "x64"))
|
|
strcpy_literal(s, "Windows XP");
|
|
}
|
|
break;
|
|
case 1:
|
|
strcpy_literal(s, "Windows XP");
|
|
break;
|
|
case 0:
|
|
strcpy_literal(s, "Windows 2000");
|
|
break;
|
|
}
|
|
break;
|
|
case 4:
|
|
switch (vi.dwMinorVersion)
|
|
{
|
|
case 0:
|
|
if (vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
|
strcpy_literal(s, "Windows 95");
|
|
else if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
|
strcpy_literal(s, "Windows NT 4.0");
|
|
else
|
|
strcpy_literal(s, "Unknown");
|
|
break;
|
|
case 90:
|
|
strcpy_literal(s, "Windows ME");
|
|
break;
|
|
case 10:
|
|
strcpy_literal(s, "Windows 98");
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
snprintf(s, len, "Windows %i.%i", *major, *minor);
|
|
break;
|
|
}
|
|
|
|
if (!string_is_empty(arch))
|
|
{
|
|
strlcat(s, " ", len);
|
|
strlcat(s, arch, len);
|
|
}
|
|
|
|
strlcat(s, " Build ", len);
|
|
strlcat(s, buildStr, len);
|
|
|
|
if (!string_is_empty(vi.szCSDVersion))
|
|
{
|
|
strlcat(s, " ", len);
|
|
strlcat(s, vi.szCSDVersion, len);
|
|
}
|
|
|
|
}
|
|
|
|
static void frontend_win32_init(void *data)
|
|
{
|
|
typedef BOOL (WINAPI *isProcessDPIAwareProc)();
|
|
typedef BOOL (WINAPI *setProcessDPIAwareProc)();
|
|
#ifdef HAVE_DYNAMIC
|
|
HMODULE handle =
|
|
GetModuleHandle("User32.dll");
|
|
isProcessDPIAwareProc isDPIAwareProc =
|
|
(isProcessDPIAwareProc)dylib_proc(handle, "IsProcessDPIAware");
|
|
setProcessDPIAwareProc setDPIAwareProc =
|
|
(setProcessDPIAwareProc)dylib_proc(handle, "SetProcessDPIAware");
|
|
#else
|
|
isProcessDPIAwareProc isDPIAwareProc = IsProcessDPIAware;
|
|
setProcessDPIAwareProc setDPIAwareProc = SetProcessDPIAware;
|
|
#endif
|
|
|
|
if (isDPIAwareProc)
|
|
if (!isDPIAwareProc())
|
|
if (setDPIAwareProc)
|
|
setDPIAwareProc();
|
|
}
|
|
|
|
|
|
#ifdef HAVE_NVDA
|
|
static void init_nvda(void)
|
|
{
|
|
#ifdef HAVE_DYNAMIC
|
|
if (USE_NVDA && !nvdalib)
|
|
{
|
|
nvdalib = dylib_load("nvdaControllerClient64.dll");
|
|
if (!nvdalib)
|
|
{
|
|
USE_NVDA = false;
|
|
USE_POWERSHELL = true;
|
|
}
|
|
else
|
|
{
|
|
nvdaController_testIfRunning_func = ( unsigned long (__stdcall*)(void))dylib_proc(nvdalib, "nvdaController_testIfRunning");
|
|
nvdaController_cancelSpeech_func = (unsigned long(__stdcall *)(void))dylib_proc(nvdalib, "nvdaController_cancelSpeech");
|
|
nvdaController_brailleMessage_func = (unsigned long(__stdcall *)(wchar_t*))dylib_proc(nvdalib, "nvdaController_brailleMessage");
|
|
nvdaController_speakText_func = (unsigned long(__stdcall *)(wchar_t*))dylib_proc(nvdalib, "nvdaController_speakText");
|
|
|
|
}
|
|
}
|
|
#else
|
|
USE_NVDA = false;
|
|
USE_POWERSHELL = true;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
enum frontend_powerstate frontend_win32_get_powerstate(int *seconds, int *percent)
|
|
{
|
|
SYSTEM_POWER_STATUS status;
|
|
enum frontend_powerstate ret = FRONTEND_POWERSTATE_NONE;
|
|
|
|
if (!GetSystemPowerStatus(&status))
|
|
return ret;
|
|
|
|
if (status.BatteryFlag == 0xFF)
|
|
ret = FRONTEND_POWERSTATE_NONE;
|
|
else if (status.BatteryFlag & (1 << 7))
|
|
ret = FRONTEND_POWERSTATE_NO_SOURCE;
|
|
else if (status.BatteryFlag & (1 << 3))
|
|
ret = FRONTEND_POWERSTATE_CHARGING;
|
|
else if (status.ACLineStatus == 1)
|
|
ret = FRONTEND_POWERSTATE_CHARGED;
|
|
else
|
|
ret = FRONTEND_POWERSTATE_ON_POWER_SOURCE;
|
|
|
|
*percent = (int)status.BatteryLifePercent;
|
|
*seconds = (int)status.BatteryLifeTime;
|
|
|
|
#ifdef _WIN32
|
|
if (*percent == 255)
|
|
*percent = 0;
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
enum frontend_architecture frontend_win32_get_arch(void)
|
|
{
|
|
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
|
|
/* Windows 2000 and later */
|
|
SYSTEM_INFO si = {{0}};
|
|
|
|
GetSystemInfo(&si);
|
|
|
|
switch (si.wProcessorArchitecture)
|
|
{
|
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
|
return FRONTEND_ARCH_X86_64;
|
|
break;
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
return FRONTEND_ARCH_X86;
|
|
break;
|
|
case PROCESSOR_ARCHITECTURE_ARM:
|
|
return FRONTEND_ARCH_ARM;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
return FRONTEND_ARCH_NONE;
|
|
}
|
|
|
|
static int frontend_win32_parse_drive_list(void *data, bool load_content)
|
|
{
|
|
#ifdef HAVE_MENU
|
|
file_list_t *list = (file_list_t*)data;
|
|
enum msg_hash_enums enum_idx = load_content ?
|
|
MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR :
|
|
MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY;
|
|
size_t i = 0;
|
|
unsigned drives = GetLogicalDrives();
|
|
char drive[] = " :\\";
|
|
|
|
for (i = 0; i < 32; i++)
|
|
{
|
|
drive[0] = 'A' + i;
|
|
if (drives & (1 << i))
|
|
menu_entries_append_enum(list,
|
|
drive,
|
|
msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
|
|
enum_idx,
|
|
FILE_TYPE_DIRECTORY, 0, 0);
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void frontend_win32_env_get(int *argc, char *argv[],
|
|
void *args, void *params_data)
|
|
{
|
|
const char *tmp_dir = getenv("TMP");
|
|
if (!string_is_empty(tmp_dir))
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CACHE],
|
|
tmp_dir, sizeof(g_defaults.dirs[DEFAULT_DIR_CACHE]));
|
|
|
|
gfx_set_dwm();
|
|
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_ASSETS],
|
|
":\\assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
|
|
":\\filters\\audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
|
|
":\\filters\\video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CHEATS],
|
|
":\\cheats", sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_DATABASE],
|
|
":\\database\\rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CURSOR],
|
|
":\\database\\cursors", sizeof(g_defaults.dirs[DEFAULT_DIR_CURSOR]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_PLAYLIST],
|
|
":\\playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG],
|
|
":\\config\\record", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT],
|
|
":\\recordings", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG],
|
|
":\\config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_REMAP],
|
|
":\\config\\remaps", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_WALLPAPERS],
|
|
":\\assets\\wallpapers", sizeof(g_defaults.dirs[DEFAULT_DIR_WALLPAPERS]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS],
|
|
":\\thumbnails", sizeof(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_OVERLAY],
|
|
":\\overlays", sizeof(g_defaults.dirs[DEFAULT_DIR_OVERLAY]));
|
|
#ifdef HAVE_VIDEO_LAYOUT
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_VIDEO_LAYOUT],
|
|
":\\layouts", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_LAYOUT]));
|
|
#endif
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CORE],
|
|
":\\cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CORE_INFO],
|
|
":\\info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG],
|
|
":\\autoconfig", sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SHADER],
|
|
":\\shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS],
|
|
":\\downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT],
|
|
":\\screenshots", sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SRAM],
|
|
":\\saves", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SAVESTATE],
|
|
":\\states", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SYSTEM],
|
|
":\\system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
|
|
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_LOGS],
|
|
":\\logs", sizeof(g_defaults.dirs[DEFAULT_DIR_LOGS]));
|
|
|
|
#ifndef IS_SALAMANDER
|
|
dir_check_defaults("custom.ini");
|
|
#endif
|
|
}
|
|
|
|
static uint64_t frontend_win32_get_total_mem(void)
|
|
{
|
|
/* OSes below 2000 don't have the Ex version,
|
|
* and non-Ex cannot work with >4GB RAM */
|
|
#if _WIN32_WINNT >= 0x0500
|
|
MEMORYSTATUSEX mem_info;
|
|
mem_info.dwLength = sizeof(MEMORYSTATUSEX);
|
|
GlobalMemoryStatusEx(&mem_info);
|
|
return mem_info.ullTotalPhys;
|
|
#else
|
|
MEMORYSTATUS mem_info;
|
|
mem_info.dwLength = sizeof(MEMORYSTATUS);
|
|
GlobalMemoryStatus(&mem_info);
|
|
return mem_info.dwTotalPhys;
|
|
#endif
|
|
}
|
|
|
|
static uint64_t frontend_win32_get_free_mem(void)
|
|
{
|
|
/* OSes below 2000 don't have the Ex version,
|
|
* and non-Ex cannot work with >4GB RAM */
|
|
#if _WIN32_WINNT >= 0x0500
|
|
MEMORYSTATUSEX mem_info;
|
|
mem_info.dwLength = sizeof(MEMORYSTATUSEX);
|
|
GlobalMemoryStatusEx(&mem_info);
|
|
return mem_info.ullAvailPhys;
|
|
#else
|
|
MEMORYSTATUS mem_info;
|
|
mem_info.dwLength = sizeof(MEMORYSTATUS);
|
|
GlobalMemoryStatus(&mem_info);
|
|
return mem_info.dwAvailPhys;
|
|
#endif
|
|
}
|
|
|
|
static void frontend_win32_attach_console(void)
|
|
{
|
|
#ifdef _WIN32
|
|
#ifdef _WIN32_WINNT_WINXP
|
|
/* msys will start the process with FILE_TYPE_PIPE connected.
|
|
* cmd will start the process with FILE_TYPE_UNKNOWN connected
|
|
* (since this is subsystem windows application
|
|
* ... UNLESS stdout/stderr were redirected (then FILE_TYPE_DISK
|
|
* will be connected most likely)
|
|
* explorer will start the process with NOTHING connected.
|
|
*
|
|
* Now, let's not reconnect anything that's already connected.
|
|
* If any are disconnected, open a console, and connect to them.
|
|
* In case we're launched from msys or cmd, try attaching to the
|
|
* parent process console first.
|
|
*
|
|
* Take care to leave a record of what we did, so we can
|
|
* undo it precisely.
|
|
*/
|
|
|
|
bool need_stdout = (GetFileType(GetStdHandle(STD_OUTPUT_HANDLE))
|
|
== FILE_TYPE_UNKNOWN);
|
|
bool need_stderr = (GetFileType(GetStdHandle(STD_ERROR_HANDLE))
|
|
== FILE_TYPE_UNKNOWN);
|
|
|
|
if (need_stdout || need_stderr)
|
|
{
|
|
if (!AttachConsole( ATTACH_PARENT_PROCESS))
|
|
AllocConsole();
|
|
|
|
SetConsoleTitle("Log Console");
|
|
|
|
if (need_stdout)
|
|
freopen( "CONOUT$", "w", stdout );
|
|
if (need_stderr)
|
|
freopen( "CONOUT$", "w", stderr );
|
|
|
|
console_needs_free = true;
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
static void frontend_win32_detach_console(void)
|
|
{
|
|
#if defined(_WIN32) && !defined(_XBOX)
|
|
#ifdef _WIN32_WINNT_WINXP
|
|
if (console_needs_free)
|
|
{
|
|
/* we don't reconnect stdout/stderr to anything here,
|
|
* because by definition, they weren't connected to
|
|
* anything in the first place. */
|
|
FreeConsole();
|
|
console_needs_free = false;
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
static const char* frontend_win32_get_cpu_model_name(void)
|
|
{
|
|
#ifdef ANDROID
|
|
return NULL;
|
|
#else
|
|
cpu_features_get_model_name(win32_cpu_model_name, sizeof(win32_cpu_model_name));
|
|
return win32_cpu_model_name;
|
|
#endif
|
|
}
|
|
|
|
enum retro_language frontend_win32_get_user_language(void)
|
|
{
|
|
enum retro_language lang = RETRO_LANGUAGE_ENGLISH;
|
|
#if defined(HAVE_LANGEXTRA) && !defined(_XBOX)
|
|
#if (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500) || !defined(_MSC_VER)
|
|
LANGID langid = GetUserDefaultUILanguage();
|
|
lang = win32_get_retro_lang_from_langid(langid);
|
|
#endif
|
|
#endif
|
|
return lang;
|
|
}
|
|
|
|
#if defined(_WIN32) && !defined(_XBOX)
|
|
enum frontend_fork win32_fork_mode;
|
|
|
|
static void frontend_win32_respawn(char *s, size_t len, char *args)
|
|
{
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
char executable_path[PATH_MAX_LENGTH] = {0};
|
|
|
|
if (win32_fork_mode != FRONTEND_FORK_RESTART)
|
|
return;
|
|
|
|
fill_pathname_application_path(executable_path,
|
|
sizeof(executable_path));
|
|
path_set(RARCH_PATH_CORE, executable_path);
|
|
RARCH_LOG("Restarting RetroArch with commandline: %s and %s\n",
|
|
executable_path, args);
|
|
|
|
memset(&si, 0, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
memset(&pi, 0, sizeof(pi));
|
|
|
|
if (!CreateProcess( executable_path, args,
|
|
NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
|
|
{
|
|
RARCH_LOG("Failed to restart RetroArch\n");
|
|
}
|
|
}
|
|
|
|
static bool frontend_win32_set_fork(enum frontend_fork fork_mode)
|
|
{
|
|
switch (fork_mode)
|
|
{
|
|
case FRONTEND_FORK_CORE:
|
|
break;
|
|
case FRONTEND_FORK_CORE_WITH_ARGS:
|
|
break;
|
|
case FRONTEND_FORK_RESTART:
|
|
command_event(CMD_EVENT_QUIT, NULL);
|
|
break;
|
|
case FRONTEND_FORK_NONE:
|
|
default:
|
|
break;
|
|
}
|
|
win32_fork_mode = fork_mode;
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
#if defined(_WIN32) && !defined(_XBOX)
|
|
static const char *accessibility_win_language_id(const char* language)
|
|
{
|
|
if (string_is_equal(language,"en"))
|
|
return "409";
|
|
else if (string_is_equal(language,"it"))
|
|
return "410";
|
|
else if (string_is_equal(language,"sv"))
|
|
return "041d";
|
|
else if (string_is_equal(language,"fr"))
|
|
return "040c";
|
|
else if (string_is_equal(language,"de"))
|
|
return "407";
|
|
else if (string_is_equal(language,"he"))
|
|
return "040d";
|
|
else if (string_is_equal(language,"id"))
|
|
return "421";
|
|
else if (string_is_equal(language,"es"))
|
|
return "040a";
|
|
else if (string_is_equal(language,"nl"))
|
|
return "413";
|
|
else if (string_is_equal(language,"ro"))
|
|
return "418";
|
|
else if (string_is_equal(language,"pt_pt"))
|
|
return "816";
|
|
else if (string_is_equal(language,"pt_bt") || string_is_equal(language,"pt"))
|
|
return "416";
|
|
else if (string_is_equal(language,"th"))
|
|
return "041e";
|
|
else if (string_is_equal(language,"ja"))
|
|
return "411";
|
|
else if (string_is_equal(language,"sk"))
|
|
return "041b";
|
|
else if (string_is_equal(language,"hi"))
|
|
return "439";
|
|
else if (string_is_equal(language,"ar"))
|
|
return "401";
|
|
else if (string_is_equal(language,"hu"))
|
|
return "040e";
|
|
else if (string_is_equal(language,"zh_tw") || string_is_equal(language,"zh"))
|
|
return "804";
|
|
else if (string_is_equal(language,"el"))
|
|
return "408";
|
|
else if (string_is_equal(language,"ru"))
|
|
return "419";
|
|
else if (string_is_equal(language,"nb"))
|
|
return "414";
|
|
else if (string_is_equal(language,"da"))
|
|
return "406";
|
|
else if (string_is_equal(language,"fi"))
|
|
return "040b";
|
|
else if (string_is_equal(language,"zh_hk"))
|
|
return "0c04";
|
|
else if (string_is_equal(language,"zh_cn"))
|
|
return "804";
|
|
else if (string_is_equal(language,"tr"))
|
|
return "041f";
|
|
else if (string_is_equal(language,"ko"))
|
|
return "412";
|
|
else if (string_is_equal(language,"pl"))
|
|
return "415";
|
|
else if (string_is_equal(language,"cs"))
|
|
return "405";
|
|
else
|
|
return "";
|
|
|
|
|
|
}
|
|
|
|
static const char *accessibility_win_language_code(const char* language)
|
|
{
|
|
if (string_is_equal(language,"en"))
|
|
return "Microsoft David Desktop";
|
|
else if (string_is_equal(language,"it"))
|
|
return "Microsoft Cosimo Desktop";
|
|
else if (string_is_equal(language,"sv"))
|
|
return "Microsoft Bengt Desktop";
|
|
else if (string_is_equal(language,"fr"))
|
|
return "Microsoft Paul Desktop";
|
|
else if (string_is_equal(language,"de"))
|
|
return "Microsoft Stefan Desktop";
|
|
else if (string_is_equal(language,"he"))
|
|
return "Microsoft Asaf Desktop";
|
|
else if (string_is_equal(language,"id"))
|
|
return "Microsoft Andika Desktop";
|
|
else if (string_is_equal(language,"es"))
|
|
return "Microsoft Pablo Desktop";
|
|
else if (string_is_equal(language,"nl"))
|
|
return "Microsoft Frank Desktop";
|
|
else if (string_is_equal(language,"ro"))
|
|
return "Microsoft Andrei Desktop";
|
|
else if (string_is_equal(language,"pt_pt"))
|
|
return "Microsoft Helia Desktop";
|
|
else if (string_is_equal(language,"pt_bt") || string_is_equal(language,"pt"))
|
|
return "Microsoft Daniel Desktop";
|
|
else if (string_is_equal(language,"th"))
|
|
return "Microsoft Pattara Desktop";
|
|
else if (string_is_equal(language,"ja"))
|
|
return "Microsoft Ichiro Desktop";
|
|
else if (string_is_equal(language,"sk"))
|
|
return "Microsoft Filip Desktop";
|
|
else if (string_is_equal(language,"hi"))
|
|
return "Microsoft Hemant Desktop";
|
|
else if (string_is_equal(language,"ar"))
|
|
return "Microsoft Naayf Desktop";
|
|
else if (string_is_equal(language,"hu"))
|
|
return "Microsoft Szabolcs Desktop";
|
|
else if (string_is_equal(language,"zh_tw") || string_is_equal(language,"zh"))
|
|
return "Microsoft Zhiwei Desktop";
|
|
else if (string_is_equal(language,"el"))
|
|
return "Microsoft Stefanos Desktop";
|
|
else if (string_is_equal(language,"ru"))
|
|
return "Microsoft Pavel Desktop";
|
|
else if (string_is_equal(language,"nb"))
|
|
return "Microsoft Jon Desktop";
|
|
else if (string_is_equal(language,"da"))
|
|
return "Microsoft Helle Desktop";
|
|
else if (string_is_equal(language,"fi"))
|
|
return "Microsoft Heidi Desktop";
|
|
else if (string_is_equal(language,"zh_hk"))
|
|
return "Microsoft Danny Desktop";
|
|
else if (string_is_equal(language,"zh_cn"))
|
|
return "Microsoft Kangkang Desktop";
|
|
else if (string_is_equal(language,"tr"))
|
|
return "Microsoft Tolga Desktop";
|
|
else if (string_is_equal(language,"ko"))
|
|
return "Microsoft Heami Desktop";
|
|
else if (string_is_equal(language,"pl"))
|
|
return "Microsoft Adam Desktop";
|
|
else if (string_is_equal(language,"cs"))
|
|
return "Microsoft Jakub Desktop";
|
|
else
|
|
return "";
|
|
}
|
|
|
|
static bool terminate_win32_process(PROCESS_INFORMATION pi)
|
|
{
|
|
TerminateProcess(pi.hProcess,0);
|
|
CloseHandle(pi.hProcess);
|
|
CloseHandle(pi.hThread);
|
|
return true;
|
|
}
|
|
|
|
static PROCESS_INFORMATION g_pi;
|
|
|
|
static bool create_win32_process(char* cmd, const char * input)
|
|
{
|
|
STARTUPINFO si;
|
|
HANDLE rd = NULL;
|
|
bool ret;
|
|
memset(&si, 0, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
memset(&g_pi, 0, sizeof(g_pi));
|
|
|
|
if (input)
|
|
{
|
|
DWORD dummy;
|
|
HANDLE wr;
|
|
if (!CreatePipe(&rd, &wr, NULL, strlen(input))) return false;
|
|
|
|
SetHandleInformation(rd, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
|
|
|
WriteFile(wr, input, strlen(input), &dummy, NULL);
|
|
CloseHandle(wr);
|
|
|
|
si.dwFlags |= STARTF_USESTDHANDLES;
|
|
si.hStdInput = rd;
|
|
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
|
}
|
|
|
|
ret = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NO_WINDOW,
|
|
NULL, NULL, &si, &g_pi);
|
|
if (rd) CloseHandle(rd);
|
|
return ret;
|
|
}
|
|
|
|
static bool is_narrator_running_windows(void)
|
|
{
|
|
DWORD status = 0;
|
|
#ifdef HAVE_NVDA
|
|
init_nvda();
|
|
#endif
|
|
|
|
if (USE_POWERSHELL)
|
|
{
|
|
if (pi_set == false)
|
|
return false;
|
|
if (GetExitCodeProcess(g_pi.hProcess, &status))
|
|
{
|
|
if (status == STILL_ACTIVE)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
#ifdef HAVE_NVDA
|
|
else if (USE_NVDA)
|
|
{
|
|
long res;
|
|
res = nvdaController_testIfRunning_func();
|
|
|
|
if (res != 0)
|
|
{
|
|
/* The running nvda service wasn't found, so revert
|
|
back to the powershell method
|
|
*/
|
|
RARCH_LOG("Error communicating with NVDA\n");
|
|
USE_POWERSHELL = true;
|
|
USE_NVDA = false;
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
#ifdef HAVE_SAPI
|
|
else
|
|
{
|
|
SPVOICESTATUS pStatus;
|
|
if (pVoice)
|
|
{
|
|
ISpVoice_GetStatus(pVoice, &pStatus, NULL);
|
|
if (pStatus.dwRunningState == SPRS_IS_SPEAKING)
|
|
return true;
|
|
}
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
static bool accessibility_speak_windows(int speed,
|
|
const char* speak_text, int priority)
|
|
{
|
|
char cmd[512];
|
|
const char *voice = get_user_language_iso639_1(true);
|
|
const char *language = accessibility_win_language_code(voice);
|
|
const char *langid = accessibility_win_language_id(voice);
|
|
bool res = false;
|
|
const char* speeds[10] = {"-10", "-7.5", "-5", "-2.5", "0", "2", "4", "6", "8", "10"};
|
|
size_t nbytes_cmd = 0;
|
|
if (speed < 1)
|
|
speed = 1;
|
|
else if (speed > 10)
|
|
speed = 10;
|
|
|
|
if (priority < 10)
|
|
{
|
|
if (is_narrator_running_windows())
|
|
return true;
|
|
|
|
}
|
|
#ifdef HAVE_NVDA
|
|
init_nvda();
|
|
#endif
|
|
|
|
if (USE_POWERSHELL)
|
|
{
|
|
const char * template_lang = "powershell.exe -NoProfile -WindowStyle Hidden -Command \"Add-Type -AssemblyName System.Speech; $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer; $synth.SelectVoice(\\\"%s\\\"); $synth.Rate = %s; $synth.Speak($input);\"";
|
|
const char * template_nolang = "powershell.exe -NoProfile -WindowStyle Hidden -Command \"Add-Type -AssemblyName System.Speech; $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer; $synth.Rate = %s; $synth.Speak($input);\"";
|
|
if (strlen(language) > 0)
|
|
snprintf(cmd, sizeof(cmd), template_lang, language, speeds[speed-1]);
|
|
else
|
|
snprintf(cmd, sizeof(cmd), template_nolang, speeds[speed-1]);
|
|
|
|
if (pi_set)
|
|
terminate_win32_process(g_pi);
|
|
pi_set = create_win32_process(cmd, speak_text);
|
|
}
|
|
#ifdef HAVE_NVDA
|
|
else if (USE_NVDA)
|
|
{
|
|
wchar_t *wc = utf8_to_utf16_string_alloc(speak_text);
|
|
long res = nvdaController_testIfRunning_func();
|
|
|
|
if (!wc || res != 0)
|
|
{
|
|
RARCH_LOG("Error communicating with NVDA\n");
|
|
if (wc)
|
|
free(wc);
|
|
return false;
|
|
}
|
|
|
|
nvdaController_cancelSpeech_func();
|
|
|
|
if (USE_NVDA_BRAILLE)
|
|
nvdaController_brailleMessage_func(wc);
|
|
else
|
|
nvdaController_speakText_func(wc);
|
|
free(wc);
|
|
}
|
|
#endif
|
|
#ifdef HAVE_SAPI
|
|
else
|
|
{
|
|
HRESULT hr;
|
|
/* stop the old voice if running */
|
|
if (pVoice)
|
|
{
|
|
CoUninitialize();
|
|
ISpVoice_Release(pVoice);
|
|
}
|
|
pVoice = NULL;
|
|
|
|
/* Play the new voice */
|
|
if (FAILED(CoInitialize(NULL)))
|
|
return NULL;
|
|
|
|
hr = CoCreateInstance(&CLSID_SpVoice, NULL,
|
|
CLSCTX_ALL, &IID_ISpVoice, (void **)&pVoice);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
wchar_t *wc = utf8_to_utf16_string_alloc(speak_text);
|
|
if (!wc)
|
|
return false;
|
|
hr = ISpVoice_Speak(pVoice, wc, SPF_ASYNC /*SVSFlagsAsync*/, NULL);
|
|
free(wc);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
frontend_ctx_driver_t frontend_ctx_win32 = {
|
|
frontend_win32_env_get, /* env_get */
|
|
frontend_win32_init, /* init */
|
|
NULL, /* deinit */
|
|
#if defined(_WIN32) && !defined(_XBOX)
|
|
frontend_win32_respawn, /* exitspawn */
|
|
#else
|
|
NULL, /* exitspawn */
|
|
#endif
|
|
NULL, /* process_args */
|
|
NULL, /* exec */
|
|
#if defined(_WIN32) && !defined(_XBOX)
|
|
frontend_win32_set_fork, /* set_fork */
|
|
#else
|
|
NULL, /* set_fork */
|
|
#endif
|
|
NULL, /* shutdown */
|
|
NULL, /* get_name */
|
|
frontend_win32_get_os,
|
|
NULL, /* get_rating */
|
|
NULL, /* content_loaded */
|
|
frontend_win32_get_arch, /* get_architecture */
|
|
frontend_win32_get_powerstate,
|
|
frontend_win32_parse_drive_list,
|
|
frontend_win32_get_total_mem,
|
|
frontend_win32_get_free_mem,
|
|
NULL, /* install_signal_handler */
|
|
NULL, /* get_sighandler_state */
|
|
NULL, /* set_sighandler_state */
|
|
NULL, /* destroy_sighandler_state */
|
|
frontend_win32_attach_console, /* attach_console */
|
|
frontend_win32_detach_console, /* detach_console */
|
|
NULL, /* get_lakka_version */
|
|
NULL, /* set_screen_brightness */
|
|
NULL, /* watch_path_for_changes */
|
|
NULL, /* check_for_path_changes */
|
|
NULL, /* set_sustained_performance_mode */
|
|
frontend_win32_get_cpu_model_name,
|
|
frontend_win32_get_user_language,
|
|
#if defined(_WIN32) && !defined(_XBOX)
|
|
is_narrator_running_windows, /* is_narrator_running */
|
|
accessibility_speak_windows, /* accessibility_speak */
|
|
#else
|
|
NULL, /* is_narrator_running */
|
|
NULL, /* accessibility_speak */
|
|
#endif
|
|
NULL, /* set_gamemode */
|
|
"win32", /* ident */
|
|
NULL /* get_video_driver */
|
|
};
|