2015-04-07 21:51:57 +02:00
/* RetroArch - A frontend for libretro.
2017-01-22 13:40:32 +01:00
* Copyright ( C ) 2011 - 2017 - Daniel De Matteis
2019-02-22 16:31:54 -05:00
* Copyright ( C ) 2016 - 2019 - Brad Parker
2019-06-16 13:32:27 -05:00
* Copyright ( C ) 2018 - 2019 - Andrés Suárez
2015-04-07 21:51:57 +02:00
*
* 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 .
2016-11-07 00:36:58 +01:00
*
* You should have received a copy of the GNU General Public License along with RetroArch .
2016-11-07 00:32:42 +01:00
* If not , see < http : //www.gnu.org/licenses/>.
2015-04-07 21:51:57 +02:00
*/
# include <stdint.h>
# include <stddef.h>
# include <string.h>
2016-11-29 14:26:33 -05:00
# include <retro_miscellaneous.h>
2015-06-15 22:45:02 +02:00
# include <windows.h>
2019-05-21 04:32:56 +02:00
# if defined(_WIN32) && !defined(_XBOX)
2019-05-05 17:19:12 -05:00
# include <process.h>
# include <errno.h>
2019-05-21 04:32:56 +02:00
# endif
2016-09-11 14:55:29 +02:00
2015-09-15 04:49:10 +02:00
# include <boolean.h>
2016-09-11 14:55:29 +02:00
# include <compat/strl.h>
2015-06-15 22:45:02 +02:00
# include <dynamic/dylib.h>
2016-03-20 14:53:54 +01:00
# include <lists/file_list.h>
2016-04-30 10:04:04 -05:00
# include <file/file_path.h>
2017-12-07 13:49:07 -05:00
# include <string/stdstring.h>
2020-06-27 01:10:45 +02:00
# include <encodings/utf.h>
2019-02-23 16:50:36 -05:00
# include <features/features_cpu.h>
2015-06-15 22:45:02 +02:00
2016-09-11 14:54:34 +02:00
# ifdef HAVE_CONFIG_H
# include "../../config.h"
# endif
2015-12-06 18:12:40 +01:00
# ifdef HAVE_MENU
# include "../../menu/menu_driver.h"
# endif
2015-06-15 22:45:02 +02:00
2016-09-11 14:54:34 +02:00
# include "../frontend_driver.h"
# include "../../configuration.h"
2016-08-12 01:37:12 +02:00
# include "../../defaults.h"
2016-09-11 14:54:34 +02:00
# include "../../verbosity.h"
2018-02-05 00:25:03 +01:00
# include "../../ui/drivers/ui_win32.h"
2019-05-05 17:19:12 -05:00
# include "../../paths.h"
2020-02-16 15:51:58 +01:00
# include "../../msg_hash.h"
2019-08-29 16:36:09 -04:00
# include "platform_win32.h"
2020-06-07 19:36:40 -07:00
# include "../../verbosity.h"
/*
2020-03-24 20:00:13 -07:00
# ifdef HAVE_NVDA
2020-05-10 08:51:25 +02:00
# include "../../nvda_controller.h"
2020-03-24 20:00:13 -07:00
# endif
2020-06-07 19:36:40 -07:00
*/
# ifdef HAVE_SAPI
# define COBJMACROS
# include <sapi.h>
# include <ole2.h>
# endif
# ifdef HAVE_SAPI
2020-09-21 00:52:32 +02:00
static ISpVoice * pVoice = NULL ;
2020-06-07 19:36:40 -07:00
# endif
# ifdef HAVE_NVDA
2020-09-21 00:52:32 +02:00
static bool USE_POWERSHELL = false ;
static bool USE_NVDA = true ;
2020-06-07 19:36:40 -07:00
# else
2020-09-21 00:52:32 +02:00
static bool USE_POWERSHELL = true ;
static bool USE_NVDA = false ;
2020-06-07 19:36:40 -07:00
# endif
2020-09-21 00:52:32 +02:00
static bool USE_NVDA_BRAILLE = false ;
2020-03-24 20:00:13 -07:00
2019-01-03 11:45:24 +01:00
# ifndef SM_SERVERR2
# define SM_SERVERR2 89
# endif
2020-06-04 14:41:28 +02:00
/* static public global variable */
VOID ( WINAPI * DragAcceptFiles_func ) ( HWND , BOOL ) ;
2020-08-26 19:02:48 +02:00
/* TODO/FIXME - static global variables */
2020-06-04 14:41:28 +02:00
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
2017-12-11 23:55:31 -08:00
/* We only load this library once, so we let it be
* unloaded at application shutdown , since unloading
2015-04-09 22:58:57 +02:00
* it early seems to cause issues on some systems .
*/
static dylib_t dwmlib ;
2017-08-09 16:25:23 +02:00
static dylib_t shell32lib ;
2020-06-07 19:36:40 -07:00
static dylib_t nvdalib ;
2018-01-24 01:52:44 +01:00
# endif
2017-08-09 16:25:23 +02:00
2020-06-07 19:36:40 -07:00
/* 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 * ) ;
2019-08-29 16:36:09 -04:00
# 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
2020-06-30 08:37:41 +02:00
# 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 ;
}
2019-08-29 16:36:09 -04:00
# endif
2015-04-09 22:58:57 +02:00
static void gfx_dwm_shutdown ( void )
{
2018-01-24 01:52:44 +01:00
# ifdef HAVE_DYNAMIC
2015-04-09 22:58:57 +02:00
if ( dwmlib )
dylib_close ( dwmlib ) ;
2017-08-09 16:25:23 +02:00
if ( shell32lib )
dylib_close ( shell32lib ) ;
dwmlib = NULL ;
shell32lib = NULL ;
2018-01-24 01:52:44 +01:00
# endif
2015-04-09 22:58:57 +02:00
}
static bool gfx_init_dwm ( void )
{
2017-08-12 18:15:26 +02:00
HRESULT ( WINAPI * mmcss ) ( BOOL ) ;
2015-04-09 22:58:57 +02:00
static bool inited = false ;
if ( inited )
return true ;
2017-08-09 16:25:23 +02:00
atexit ( gfx_dwm_shutdown ) ;
2018-01-24 01:52:44 +01:00
# ifdef HAVE_DYNAMIC
2017-08-09 16:25:23 +02:00
shell32lib = dylib_load ( " shell32.dll " ) ;
if ( ! shell32lib )
{
RARCH_WARN ( " Did not find shell32.dll. \n " ) ;
}
2015-04-09 22:58:57 +02:00
dwmlib = dylib_load ( " dwmapi.dll " ) ;
if ( ! dwmlib )
{
2017-08-09 16:25:23 +02:00
RARCH_WARN ( " Did not find dwmapi.dll. \n " ) ;
2015-04-09 22:58:57 +02:00
return false ;
}
2017-08-09 16:25:23 +02:00
2017-12-11 23:55:31 -08:00
DragAcceptFiles_func =
2017-08-09 16:25:23 +02:00
( VOID ( WINAPI * ) ( HWND , BOOL ) ) dylib_proc ( shell32lib , " DragAcceptFiles " ) ;
2019-02-03 15:49:35 -08:00
2017-12-11 23:55:31 -08:00
mmcss =
2019-07-04 21:08:01 +02:00
( HRESULT ( WINAPI * ) ( BOOL ) ) dylib_proc ( dwmlib , " DwmEnableMMCSS " ) ;
2018-01-24 01:52:44 +01:00
# else
DragAcceptFiles_func = DragAcceptFiles ;
#if 0
mmcss = DwmEnableMMCSS ;
# endif
# endif
2015-04-09 22:58:57 +02:00
if ( mmcss )
2019-07-04 21:08:01 +02:00
mmcss ( TRUE ) ;
2015-04-09 22:58:57 +02:00
inited = true ;
return true ;
}
static void gfx_set_dwm ( void )
{
HRESULT ret ;
2017-08-12 18:15:26 +02:00
HRESULT ( WINAPI * composition_enable ) ( UINT ) ;
2020-02-13 21:53:31 +01:00
settings_t * settings = config_get_ptr ( ) ;
bool disable_composition = settings - > bools . video_disable_composition ;
2015-04-09 22:58:57 +02:00
if ( ! gfx_init_dwm ( ) )
return ;
2020-02-13 21:53:31 +01:00
if ( disable_composition = = dwm_composition_disabled )
2015-04-09 22:58:57 +02:00
return ;
2018-01-24 01:52:44 +01:00
# ifdef HAVE_DYNAMIC
2017-12-11 23:55:31 -08:00
composition_enable =
2015-04-09 22:58:57 +02:00
( HRESULT ( WINAPI * ) ( UINT ) ) dylib_proc ( dwmlib , " DwmEnableComposition " ) ;
2018-01-24 01:52:44 +01:00
# endif
2015-04-09 22:58:57 +02:00
if ( ! composition_enable )
{
RARCH_ERR ( " Did not find DwmEnableComposition ... \n " ) ;
return ;
}
2020-02-13 21:53:31 +01:00
ret = composition_enable ( ! disable_composition ) ;
2015-04-09 22:58:57 +02:00
if ( FAILED ( ret ) )
RARCH_ERR ( " Failed to set composition state ... \n " ) ;
2020-02-13 21:53:31 +01:00
dwm_composition_disabled = disable_composition ;
2015-04-09 22:58:57 +02:00
}
2015-06-02 18:28:51 +02:00
static void frontend_win32_get_os ( char * s , size_t len , int * major , int * minor )
2015-04-07 23:28:45 +02:00
{
2018-04-09 17:35:27 +02:00
char buildStr [ 11 ] = { 0 } ;
bool server = false ;
const char * arch = " " ;
2015-04-07 23:28:45 +02:00
2017-12-07 13:49:07 -05:00
# if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
/* Windows 2000 and later */
2018-04-09 17:35:27 +02:00
SYSTEM_INFO si = { { 0 } } ;
OSVERSIONINFOEX vi = { 0 } ;
2017-12-07 13:49:07 -05:00
vi . dwOSVersionInfoSize = sizeof ( OSVERSIONINFOEX ) ;
2015-04-18 20:41:17 +02:00
2017-12-07 18:49:35 -05:00
GetSystemInfo ( & si ) ;
2017-12-07 13:49:07 -05:00
2017-12-07 18:49:35 -05:00
/* Available from NT 3.5 and Win95 */
GetVersionEx ( ( OSVERSIONINFO * ) & vi ) ;
2017-12-07 13:49:07 -05:00
2017-12-07 18:49:35 -05:00
server = vi . wProductType ! = VER_NT_WORKSTATION ;
2017-12-07 13:49:07 -05:00
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 */
2017-12-07 18:49:35 -05:00
GetVersionEx ( & vi ) ;
# endif
2017-12-07 13:49:07 -05:00
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 )
2015-04-18 20:41:17 +02:00
{
2016-05-02 03:16:46 +02:00
case 10 :
2017-12-07 13:49:07 -05:00
if ( server )
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows Server 2016 " ) ;
2017-12-07 13:49:07 -05:00
else
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows 10 " ) ;
2016-05-02 03:16:46 +02:00
break ;
2015-04-18 20:41:17 +02:00
case 6 :
2017-12-07 13:49:07 -05:00
switch ( vi . dwMinorVersion )
2015-04-18 20:41:17 +02:00
{
case 3 :
2017-12-07 13:49:07 -05:00
if ( server )
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows Server 2012 R2 " ) ;
2017-12-07 13:49:07 -05:00
else
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows 8.1 " ) ;
2015-04-18 20:41:17 +02:00
break ;
case 2 :
2017-12-07 13:49:07 -05:00
if ( server )
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows Server 2012 " ) ;
2017-12-07 13:49:07 -05:00
else
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows 8 " ) ;
2015-04-18 20:41:17 +02:00
break ;
case 1 :
2017-12-07 13:49:07 -05:00
if ( server )
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows Server 2008 R2 " ) ;
2017-12-07 13:49:07 -05:00
else
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows 7 " ) ;
2015-04-18 20:41:17 +02:00
break ;
case 0 :
2017-12-07 13:49:07 -05:00
if ( server )
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows Server 2008 " ) ;
2017-12-07 13:49:07 -05:00
else
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows Vista " ) ;
2015-04-18 20:41:17 +02:00
break ;
default :
break ;
}
break ;
case 5 :
2017-12-07 13:49:07 -05:00
switch ( vi . dwMinorVersion )
2015-04-18 20:41:17 +02:00
{
case 2 :
2017-12-07 13:49:07 -05:00
if ( server )
2019-01-02 13:30:58 +01:00
{
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows Server 2003 " ) ;
2019-01-02 13:30:58 +01:00
if ( GetSystemMetrics ( SM_SERVERR2 ) )
strlcat ( s , " R2 " , len ) ;
}
2017-12-07 13:49:07 -05:00
else
{
/* Yes, XP Pro x64 is a higher version number than XP x86 */
if ( string_is_equal ( arch , " x64 " ) )
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows XP " ) ;
2017-12-07 13:49:07 -05:00
}
2015-04-18 20:41:17 +02:00
break ;
case 1 :
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows XP " ) ;
2015-04-18 20:41:17 +02:00
break ;
case 0 :
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows 2000 " ) ;
2015-04-18 20:41:17 +02:00
break ;
}
break ;
case 4 :
2017-12-07 13:49:07 -05:00
switch ( vi . dwMinorVersion )
2015-04-18 20:41:17 +02:00
{
case 0 :
2017-12-07 13:49:07 -05:00
if ( vi . dwPlatformId = = VER_PLATFORM_WIN32_WINDOWS )
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows 95 " ) ;
2017-12-07 13:49:07 -05:00
else if ( vi . dwPlatformId = = VER_PLATFORM_WIN32_NT )
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows NT 4.0 " ) ;
2017-12-07 13:49:07 -05:00
else
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Unknown " ) ;
2015-04-18 20:41:17 +02:00
break ;
case 90 :
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows ME " ) ;
2015-04-18 20:41:17 +02:00
break ;
case 10 :
2020-09-20 00:12:54 +02:00
strcpy_literal ( s , " Windows 98 " ) ;
2015-04-18 20:41:17 +02:00
break ;
}
break ;
default :
2017-12-07 13:49:07 -05:00
snprintf ( s , len , " Windows %i.%i " , * major , * minor ) ;
2015-04-18 20:41:17 +02:00
break ;
}
2017-12-07 13:49:07 -05:00
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 ) ;
}
2018-12-28 12:41:38 +01:00
2015-04-07 23:28:45 +02:00
}
2015-04-08 02:11:23 +02:00
static void frontend_win32_init ( void * data )
2015-04-07 23:28:45 +02:00
{
2019-07-04 21:08:01 +02:00
typedef BOOL ( WINAPI * isProcessDPIAwareProc ) ( ) ;
typedef BOOL ( WINAPI * setProcessDPIAwareProc ) ( ) ;
2018-01-24 01:52:44 +01:00
# ifdef HAVE_DYNAMIC
2019-07-04 21:08:01 +02:00
HMODULE handle =
2017-05-23 19:43:58 +02:00
GetModuleHandle ( " User32.dll " ) ;
2019-07-04 21:08:01 +02:00
isProcessDPIAwareProc isDPIAwareProc =
2017-05-23 19:43:58 +02:00
( isProcessDPIAwareProc ) dylib_proc ( handle , " IsProcessDPIAware " ) ;
2019-07-04 21:08:01 +02:00
setProcessDPIAwareProc setDPIAwareProc =
2017-05-23 19:43:58 +02:00
( setProcessDPIAwareProc ) dylib_proc ( handle , " SetProcessDPIAware " ) ;
2018-01-24 01:52:44 +01:00
# else
2019-07-04 21:08:01 +02:00
isProcessDPIAwareProc isDPIAwareProc = IsProcessDPIAware ;
setProcessDPIAwareProc setDPIAwareProc = SetProcessDPIAware ;
2018-01-24 01:52:44 +01:00
# endif
2015-04-08 07:20:28 +02:00
2019-07-04 21:08:01 +02:00
if ( isDPIAwareProc )
if ( ! isDPIAwareProc ( ) )
if ( setDPIAwareProc )
setDPIAwareProc ( ) ;
2015-04-07 23:28:45 +02:00
}
2020-06-07 19:36:40 -07:00
# 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
2015-04-18 17:16:55 +02:00
enum frontend_powerstate frontend_win32_get_powerstate ( int * seconds , int * percent )
{
2016-01-13 07:05:57 +01:00
SYSTEM_POWER_STATUS status ;
2019-07-04 21:08:01 +02:00
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 ;
2015-04-18 17:16:55 +02:00
2019-07-04 21:08:01 +02:00
* percent = ( int ) status . BatteryLifePercent ;
* seconds = ( int ) status . BatteryLifeTime ;
2015-04-18 17:16:55 +02:00
2016-12-21 09:34:57 -05:00
# ifdef _WIN32
2019-07-04 21:08:01 +02:00
if ( * percent = = 255 )
* percent = 0 ;
2016-12-21 09:34:57 -05:00
# endif
2019-07-04 21:08:01 +02:00
return ret ;
2015-04-18 17:16:55 +02:00
}
2021-01-16 16:14:03 +01:00
enum frontend_architecture frontend_win32_get_arch ( void )
2015-04-18 20:03:59 +02:00
{
2017-12-07 16:32:01 -05:00
# if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
/* Windows 2000 and later */
2018-04-09 17:35:27 +02:00
SYSTEM_INFO si = { { 0 } } ;
2017-12-07 16:32:01 -05:00
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
2015-04-18 20:03:59 +02:00
return FRONTEND_ARCH_NONE ;
}
2017-05-26 15:52:38 +02:00
static int frontend_win32_parse_drive_list ( void * data , bool load_content )
2015-06-15 22:45:02 +02:00
{
2015-12-06 18:12:40 +01:00
# ifdef HAVE_MENU
2018-12-28 12:41:38 +01:00
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 :
2019-12-31 12:32:32 +00:00
MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY ;
2019-01-02 13:30:58 +01:00
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 ) ;
}
2015-12-06 18:12:40 +01:00
# endif
2015-06-15 22:45:02 +02:00
return 0 ;
}
2021-01-16 16:14:03 +01:00
static void frontend_win32_env_get ( int * argc , char * argv [ ] ,
2015-09-29 03:19:48 +02:00
void * args , void * params_data )
{
2020-10-17 20:52:27 +03:00
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 ] ) ) ;
2019-01-02 13:30:58 +01:00
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 ] ) ) ;
2019-04-16 17:41:06 +01:00
# 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
2019-01-02 13:30:58 +01:00
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 ] ) ) ;
2019-03-05 17:34:05 -05:00
fill_pathname_expand_special ( g_defaults . dirs [ DEFAULT_DIR_LOGS ] ,
" : \\ logs " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_LOGS ] ) ) ;
2020-11-19 07:10:22 +01:00
# ifndef IS_SALAMANDER
2020-11-20 03:55:55 +01:00
dir_check_defaults ( " custom.ini " ) ;
2020-11-19 07:10:22 +01:00
# endif
2016-06-12 20:38:48 +02:00
}
2016-04-30 10:04:04 -05:00
2020-07-18 19:25:57 +01:00
static uint64_t frontend_win32_get_total_mem ( void )
2016-06-12 20:38:48 +02:00
{
2017-05-23 19:43:58 +02:00
/* OSes below 2000 don't have the Ex version,
* and non - Ex cannot work with > 4 GB RAM */
2017-11-29 19:33:39 -05:00
# if _WIN32_WINNT >= 0x0500
2019-07-04 21:08:01 +02:00
MEMORYSTATUSEX mem_info ;
mem_info . dwLength = sizeof ( MEMORYSTATUSEX ) ;
GlobalMemoryStatusEx ( & mem_info ) ;
return mem_info . ullTotalPhys ;
2017-01-18 02:02:32 -05:00
# else
2019-07-04 21:08:01 +02:00
MEMORYSTATUS mem_info ;
mem_info . dwLength = sizeof ( MEMORYSTATUS ) ;
GlobalMemoryStatus ( & mem_info ) ;
return mem_info . dwTotalPhys ;
2017-01-18 02:02:32 -05:00
# endif
2016-06-12 20:38:48 +02:00
}
2020-07-18 19:25:57 +01:00
static uint64_t frontend_win32_get_free_mem ( void )
2016-06-12 20:38:48 +02:00
{
2017-12-11 23:55:31 -08:00
/* OSes below 2000 don't have the Ex version,
2017-05-23 19:43:58 +02:00
* and non - Ex cannot work with > 4 GB RAM */
2017-11-29 19:33:39 -05:00
# if _WIN32_WINNT >= 0x0500
2019-07-04 21:08:01 +02:00
MEMORYSTATUSEX mem_info ;
mem_info . dwLength = sizeof ( MEMORYSTATUSEX ) ;
GlobalMemoryStatusEx ( & mem_info ) ;
2020-07-18 19:25:57 +01:00
return mem_info . ullAvailPhys ;
2017-01-18 02:02:32 -05:00
# else
2019-07-04 21:08:01 +02:00
MEMORYSTATUS mem_info ;
mem_info . dwLength = sizeof ( MEMORYSTATUS ) ;
GlobalMemoryStatus ( & mem_info ) ;
2020-07-18 19:25:57 +01:00
return mem_info . dwAvailPhys ;
2017-01-18 02:02:32 -05:00
# endif
2015-09-29 03:19:48 +02:00
}
2016-10-09 17:15:50 +02:00
static void frontend_win32_attach_console ( void )
{
# ifdef _WIN32
2017-01-14 04:06:56 -05:00
# ifdef _WIN32_WINNT_WINXP
2017-02-24 18:37:36 -06:00
/* msys will start the process with FILE_TYPE_PIPE connected.
2017-12-11 23:55:31 -08:00
* cmd will start the process with FILE_TYPE_UNKNOWN connected
2017-05-23 19:43:58 +02:00
* ( since this is subsystem windows application
2017-12-11 23:55:31 -08:00
* . . . UNLESS stdout / stderr were redirected ( then FILE_TYPE_DISK
2017-05-23 19:43:58 +02:00
* will be connected most likely )
2017-02-24 18:37:36 -06:00
* 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 .
2017-12-11 23:55:31 -08:00
* In case we ' re launched from msys or cmd , try attaching to the
2017-05-23 19:43:58 +02:00
* parent process console first .
*
2017-12-11 23:55:31 -08:00
* Take care to leave a record of what we did , so we can
2017-05-23 19:43:58 +02:00
* undo it precisely .
2017-02-24 18:37:36 -06:00
*/
2017-12-11 23:55:31 -08:00
bool need_stdout = ( GetFileType ( GetStdHandle ( STD_OUTPUT_HANDLE ) )
2017-05-23 19:43:58 +02:00
= = FILE_TYPE_UNKNOWN ) ;
2017-12-11 23:55:31 -08:00
bool need_stderr = ( GetFileType ( GetStdHandle ( STD_ERROR_HANDLE ) )
2017-05-23 19:43:58 +02:00
= = FILE_TYPE_UNKNOWN ) ;
2017-02-24 18:37:36 -06:00
2020-05-12 17:16:36 +02:00
if ( need_stdout | | need_stderr )
2017-02-24 18:37:36 -06:00
{
2020-05-12 17:16:36 +02:00
if ( ! AttachConsole ( ATTACH_PARENT_PROCESS ) )
2017-02-24 18:37:36 -06:00
AllocConsole ( ) ;
2019-09-19 06:23:31 +02:00
SetConsoleTitle ( " Log Console " ) ;
2020-05-12 17:16:36 +02:00
if ( need_stdout )
freopen ( " CONOUT$ " , " w " , stdout ) ;
if ( need_stderr )
freopen ( " CONOUT$ " , " w " , stderr ) ;
2017-02-24 18:37:36 -06:00
console_needs_free = true ;
}
2017-02-15 22:25:17 -05:00
2016-10-09 17:15:50 +02:00
# endif
2006-05-14 14:33:10 +02:00
# endif
2016-10-09 17:15:50 +02:00
}
static void frontend_win32_detach_console ( void )
{
# if defined(_WIN32) && !defined(_XBOX)
2017-01-14 04:06:56 -05:00
# ifdef _WIN32_WINNT_WINXP
2020-05-12 17:16:36 +02:00
if ( console_needs_free )
2016-11-17 20:16:50 +01:00
{
2017-12-11 23:55:31 -08:00
/* we don't reconnect stdout/stderr to anything here,
* because by definition , they weren ' t connected to
2017-05-23 19:43:58 +02:00
* anything in the first place . */
2016-11-17 20:16:50 +01:00
FreeConsole ( ) ;
2017-02-24 18:37:36 -06:00
console_needs_free = false ;
2016-11-17 20:16:50 +01:00
}
2016-10-09 17:15:50 +02:00
# endif
2006-05-14 14:33:10 +02:00
# endif
2016-10-09 17:15:50 +02:00
}
2019-02-23 16:50:36 -05:00
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
}
2019-04-16 00:42:29 -04:00
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 ( ) ;
2019-08-29 16:36:09 -04:00
lang = win32_get_retro_lang_from_langid ( langid ) ;
2019-04-16 00:42:29 -04:00
# endif
# endif
return lang ;
}
2019-05-21 04:32:56 +02:00
# if defined(_WIN32) && !defined(_XBOX)
2019-05-05 17:19:12 -05:00
enum frontend_fork win32_fork_mode ;
2020-02-01 17:42:18 +01:00
static void frontend_win32_respawn ( char * s , size_t len , char * args )
2019-05-05 17:19:12 -05:00
{
STARTUPINFO si ;
PROCESS_INFORMATION pi ;
2019-05-21 06:08:33 +02:00
char executable_path [ PATH_MAX_LENGTH ] = { 0 } ;
2019-05-05 17:19:12 -05:00
2019-05-21 06:08:33 +02:00
if ( win32_fork_mode ! = FRONTEND_FORK_RESTART )
return ;
2019-05-05 17:19:12 -05:00
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 " ,
2020-02-01 17:42:18 +01:00
executable_path , args ) ;
memset ( & si , 0 , sizeof ( si ) ) ;
si . cb = sizeof ( si ) ;
memset ( & pi , 0 , sizeof ( pi ) ) ;
2019-05-05 17:19:12 -05:00
2020-05-12 17:16:36 +02:00
if ( ! CreateProcess ( executable_path , args ,
2019-05-05 17:19:12 -05:00
NULL , NULL , FALSE , 0 , NULL , NULL , & si , & pi ) )
{
RARCH_LOG ( " Failed to restart RetroArch \n " ) ;
}
}
2019-05-21 04:32:56 +02:00
static bool frontend_win32_set_fork ( enum frontend_fork fork_mode )
2019-05-05 17:19:12 -05:00
{
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 ;
}
2019-05-21 04:32:56 +02:00
# endif
2019-05-05 17:19:12 -05:00
2020-02-14 00:17:55 +01:00
# if defined(_WIN32) && !defined(_XBOX)
2020-03-24 20:00:13 -07:00
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 " " ;
}
2020-02-14 00:17:55 +01:00
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 " ;
2020-03-24 20:00:13 -07:00
else if ( string_is_equal ( language , " id " ) )
return " Microsoft Andika Desktop " ;
2020-02-14 00:17:55 +01:00
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 )
{
STARTUPINFO si ;
memset ( & si , 0 , sizeof ( si ) ) ;
si . cb = sizeof ( si ) ;
memset ( & g_pi , 0 , sizeof ( g_pi ) ) ;
if ( ! CreateProcess ( NULL , cmd , NULL , NULL , FALSE , CREATE_NO_WINDOW ,
NULL , NULL , & si , & g_pi ) )
return false ;
return true ;
}
static bool is_narrator_running_windows ( void )
{
DWORD status = 0 ;
2020-06-09 03:22:10 +02:00
# ifdef HAVE_NVDA
2020-06-07 19:36:40 -07:00
init_nvda ( ) ;
2020-06-09 03:22:10 +02:00
# endif
2020-03-24 20:00:13 -07:00
if ( USE_POWERSHELL )
{
if ( pi_set = = false )
return false ;
if ( GetExitCodeProcess ( g_pi . hProcess , & status ) )
{
if ( status = = STILL_ACTIVE )
return true ;
}
2020-02-14 00:17:55 +01:00
return false ;
2020-03-24 20:00:13 -07:00
}
# ifdef HAVE_NVDA
else if ( USE_NVDA )
{
2020-06-07 19:36:40 -07:00
long res ;
res = nvdaController_testIfRunning_func ( ) ;
2020-04-17 16:40:39 +02:00
if ( res ! = 0 )
2020-03-24 20:00:13 -07:00
{
/* The running nvda service wasn't found, so revert
back to the powershell method
*/
RARCH_LOG ( " Error communicating with NVDA \n " ) ;
USE_POWERSHELL = true ;
2020-04-17 16:40:39 +02:00
USE_NVDA = false ;
2020-06-07 19:36:40 -07:00
return false ;
2020-03-24 20:00:13 -07:00
}
return false ;
}
# endif
2020-04-16 11:57:39 -07:00
# ifdef HAVE_SAPI
2020-03-24 20:00:13 -07:00
else
{
SPVOICESTATUS pStatus ;
2020-04-17 16:40:39 +02:00
if ( pVoice )
2020-03-24 20:00:13 -07:00
{
ISpVoice_GetStatus ( pVoice , & pStatus , NULL ) ;
if ( pStatus . dwRunningState = = SPRS_IS_SPEAKING )
return true ;
}
}
2020-04-16 11:57:39 -07:00
# endif
2020-02-14 00:17:55 +01:00
return false ;
}
static bool accessibility_speak_windows ( int speed ,
const char * speak_text , int priority )
{
2021-05-16 17:55:14 +10:00
char * cmd = NULL ;
2020-02-14 00:17:55 +01:00
const char * voice = get_user_language_iso639_1 ( true ) ;
const char * language = accessibility_win_language_code ( voice ) ;
2020-03-24 20:00:13 -07:00
const char * langid = accessibility_win_language_id ( voice ) ;
2020-02-14 00:17:55 +01:00
bool res = false ;
const char * speeds [ 10 ] = { " -10 " , " -7.5 " , " -5 " , " -2.5 " , " 0 " , " 2 " , " 4 " , " 6 " , " 8 " , " 10 " } ;
2021-05-16 17:55:14 +10:00
size_t nbytes_cmd = 0 ;
2020-02-14 00:17:55 +01:00
if ( speed < 1 )
speed = 1 ;
else if ( speed > 10 )
speed = 10 ;
if ( priority < 10 )
{
if ( is_narrator_running_windows ( ) )
return true ;
2020-06-07 19:36:40 -07:00
2020-02-14 00:17:55 +01:00
}
2020-06-09 03:22:10 +02:00
# ifdef HAVE_NVDA
2020-06-07 19:36:40 -07:00
init_nvda ( ) ;
2020-06-09 03:22:10 +02:00
# endif
2020-06-07 19:36:40 -07:00
2021-06-17 05:44:17 +02:00
if ( USE_POWERSHELL & & ! strchr ( speak_text , ' " ' ) & & ! strchr ( speak_text , ' \\ ' ) & & ! strstr ( speak_text , " $( " ) ) // TODO: escape these things properly instead of rejecting the entire string
2020-03-24 20:00:13 -07:00
{
2021-06-17 05:44:17 +02:00
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( \\ \" %s \\ \" ); \" " ;
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( \\ \" %s \\ \" ); \" " ;
2020-03-24 20:00:13 -07:00
if ( strlen ( language ) > 0 )
2021-05-16 17:55:14 +10:00
{
2021-06-17 05:44:17 +02:00
nbytes_cmd = snprintf ( NULL , 0 , template_lang , language , speeds [ speed - 1 ] , speak_text ) + 1 ;
2021-05-17 15:58:04 +02:00
if ( ! ( cmd = malloc ( nbytes_cmd ) ) )
return false ;
2021-06-17 05:44:17 +02:00
snprintf ( cmd , nbytes_cmd , template_lang , language , speeds [ speed - 1 ] , speak_text ) ;
2021-05-16 17:55:14 +10:00
}
2020-03-24 20:00:13 -07:00
else
2021-05-16 17:55:14 +10:00
{
2021-06-17 05:44:17 +02:00
nbytes_cmd = snprintf ( NULL , 0 , template_nolang , speeds [ speed - 1 ] , speak_text ) + 1 ;
2021-05-17 15:58:04 +02:00
if ( ! ( cmd = malloc ( nbytes_cmd ) ) )
return false ;
2021-06-17 05:44:17 +02:00
snprintf ( cmd , nbytes_cmd , template_nolang , speeds [ speed - 1 ] , speak_text ) ;
2021-05-16 17:55:14 +10:00
}
2021-05-17 15:58:04 +02:00
2020-03-24 20:00:13 -07:00
if ( pi_set )
terminate_win32_process ( g_pi ) ;
res = create_win32_process ( cmd ) ;
2021-05-16 17:55:14 +10:00
free ( cmd ) ;
cmd = NULL ;
2020-03-24 20:00:13 -07:00
if ( ! res )
{
pi_set = false ;
return true ;
}
pi_set = true ;
}
# ifdef HAVE_NVDA
else if ( USE_NVDA )
2020-02-14 00:17:55 +01:00
{
2020-06-27 01:10:45 +02:00
wchar_t * wc = utf8_to_utf16_string_alloc ( speak_text ) ;
long res = nvdaController_testIfRunning_func ( ) ;
2020-03-24 20:00:13 -07:00
2020-06-27 01:10:45 +02:00
if ( ! wc | | res ! = 0 )
2020-03-24 20:00:13 -07:00
{
RARCH_LOG ( " Error communicating with NVDA \n " ) ;
2020-06-27 01:10:45 +02:00
if ( wc )
free ( wc ) ;
2020-03-24 20:00:13 -07:00
return false ;
}
2020-05-20 16:26:39 +02:00
2020-06-07 19:36:40 -07:00
nvdaController_cancelSpeech_func ( ) ;
2020-03-24 20:00:13 -07:00
if ( USE_NVDA_BRAILLE )
2020-06-07 19:36:40 -07:00
nvdaController_brailleMessage_func ( wc ) ;
2020-03-24 20:00:13 -07:00
else
2020-06-07 19:36:40 -07:00
nvdaController_speakText_func ( wc ) ;
2020-06-27 01:10:45 +02:00
free ( wc ) ;
2020-03-24 20:00:13 -07:00
}
# endif
2020-04-16 11:57:39 -07:00
# ifdef HAVE_SAPI
2020-03-24 20:00:13 -07:00
else
{
2020-05-20 16:26:39 +02:00
HRESULT hr ;
2020-03-24 20:00:13 -07:00
/* stop the old voice if running */
2020-04-17 16:40:39 +02:00
if ( pVoice )
2020-03-24 20:00:13 -07:00
{
CoUninitialize ( ) ;
ISpVoice_Release ( pVoice ) ;
}
pVoice = NULL ;
/* Play the new voice */
if ( FAILED ( CoInitialize ( NULL ) ) )
return NULL ;
2020-04-17 16:40:39 +02:00
hr = CoCreateInstance ( & CLSID_SpVoice , NULL ,
CLSCTX_ALL , & IID_ISpVoice , ( void * * ) & pVoice ) ;
2020-03-24 20:00:13 -07:00
if ( SUCCEEDED ( hr ) )
{
2020-06-27 01:10:45 +02:00
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 ) ;
2020-03-24 20:00:13 -07:00
}
2020-02-14 00:17:55 +01:00
}
2020-04-16 11:57:39 -07:00
# endif
2020-05-20 16:26:39 +02:00
2020-04-17 14:07:28 -07:00
return true ;
2020-02-14 00:17:55 +01:00
}
# endif
2015-07-27 03:44:28 +02:00
frontend_ctx_driver_t frontend_ctx_win32 = {
2021-01-16 16:14:03 +01:00
frontend_win32_env_get , /* env_get */
frontend_win32_init , /* init */
NULL , /* deinit */
2019-05-21 04:32:56 +02:00
# if defined(_WIN32) && !defined(_XBOX)
2019-05-05 17:19:12 -05:00
frontend_win32_respawn , /* exitspawn */
2019-05-21 04:32:56 +02:00
# else
NULL , /* exitspawn */
# endif
2015-04-07 23:28:45 +02:00
NULL , /* process_args */
NULL , /* exec */
2019-05-21 04:32:56 +02:00
# if defined(_WIN32) && !defined(_XBOX)
frontend_win32_set_fork , /* set_fork */
# else
NULL , /* set_fork */
# endif
2021-01-16 16:14:03 +01:00
NULL , /* shutdown */
NULL , /* get_name */
2015-04-18 17:16:55 +02:00
frontend_win32_get_os ,
2021-01-16 16:14:03 +01:00
NULL , /* get_rating */
NULL , /* content_loaded */
frontend_win32_get_arch , /* get_architecture */
2015-04-18 17:16:55 +02:00
frontend_win32_get_powerstate ,
2015-06-15 22:45:02 +02:00
frontend_win32_parse_drive_list ,
2020-07-18 19:25:57 +01:00
frontend_win32_get_total_mem ,
frontend_win32_get_free_mem ,
2021-01-16 16:14:03 +01:00
NULL , /* install_signal_handler */
NULL , /* get_sighandler_state */
NULL , /* set_sighandler_state */
2016-07-08 02:24:56 +02:00
NULL , /* destroy_sighandler_state */
2021-01-16 16:14:03 +01:00
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 */
2018-06-19 02:50:33 -04:00
NULL , /* set_sustained_performance_mode */
2019-02-23 16:50:36 -05:00
frontend_win32_get_cpu_model_name ,
2019-04-16 00:42:29 -04:00
frontend_win32_get_user_language ,
2020-02-14 00:17:55 +01:00
# if defined(_WIN32) && !defined(_XBOX)
2021-01-16 16:14:03 +01:00
is_narrator_running_windows , /* is_narrator_running */
accessibility_speak_windows , /* accessibility_speak */
2020-02-14 00:17:55 +01:00
# else
2021-01-16 16:14:03 +01:00
NULL , /* is_narrator_running */
NULL , /* accessibility_speak */
2020-02-14 00:17:55 +01:00
# endif
2021-01-16 16:14:03 +01:00
" win32 " , /* ident */
NULL /* get_video_driver */
2015-04-07 21:51:57 +02:00
} ;