Merge pull request #9822 from driver1998/uwp-fixes

Multiple UWP Fixes
This commit is contained in:
Twinaphex 2019-12-05 23:38:47 +01:00 committed by GitHub
commit e61fc4e427
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 301 additions and 110 deletions

View File

@ -97,7 +97,7 @@
#define DEFAULT_MOUSE_SCALE 1
#endif
#if defined(RARCH_MOBILE) || defined(HAVE_LIBNX)
#if defined(RARCH_MOBILE) || defined(HAVE_LIBNX) || defined(__WINRT__)
#define DEFAULT_POINTER_ENABLE true
#else
#define DEFAULT_POINTER_ENABLE false

View File

@ -75,6 +75,9 @@ static void frontend_uwp_get_os(char *s, size_t len, int *major, int *minor)
case PROCESSOR_ARCHITECTURE_ARM:
arch = "ARM";
break;
case PROCESSOR_ARCHITECTURE_ARM64:
arch = "ARM64";
break;
default:
break;
}
@ -257,6 +260,9 @@ enum frontend_architecture frontend_uwp_get_architecture(void)
case PROCESSOR_ARCHITECTURE_ARM:
return FRONTEND_ARCH_ARM;
break;
case PROCESSOR_ARCHITECTURE_ARM64:
return FRONTEND_ARCH_ARMV8;
break;
default:
break;
}
@ -327,65 +333,73 @@ static void frontend_uwp_environment_get(int *argc, char *argv[],
/* On UWP, we have to use the writable directory
* instead of the install directory. */
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_ASSETS],
"~\\assets", sizeof(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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\layouts\\", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_LAYOUT]));
#endif
/* This one is an exception: cores have to be loaded from
* the install directory,
* since this is the only place UWP apps can take .dlls from */
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CORE],
":\\cores", sizeof(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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\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]));
"~\\logs\\", sizeof(g_defaults.dirs[DEFAULT_DIR_LOGS]));
#ifdef HAVE_MENU
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) || defined(HAVE_OPENGL_CORE)
snprintf(g_defaults.settings.menu,
if (string_is_equal(uwp_device_family, "Windows.Mobile"))
{
snprintf(g_defaults.settings.menu,
sizeof(g_defaults.settings.menu), "glui");
}
else
{
snprintf(g_defaults.settings.menu,
sizeof(g_defaults.settings.menu), "xmb");
}
#endif
#endif
}
@ -424,6 +438,16 @@ static uint64_t frontend_uwp_get_mem_used(void)
#endif
}
enum retro_language frontend_uwp_get_user_language(void)
{
return uwp_get_language();
}
static const char* frontend_uwp_get_cpu_model_name(void)
{
return uwp_get_cpu_model_name();
}
frontend_ctx_driver_t frontend_ctx_uwp = {
frontend_uwp_environment_get,
frontend_uwp_init,
@ -451,7 +475,7 @@ frontend_ctx_driver_t frontend_ctx_uwp = {
NULL, /* watch_path_for_changes */
NULL, /* check_for_path_changes */
NULL, /* set_sustained_performance_mode */
NULL, /* get_cpu_model_name */
NULL, /* get_user_language */
frontend_uwp_get_cpu_model_name,
frontend_uwp_get_user_language,
"uwp"
};

View File

@ -55,62 +55,10 @@ using namespace Windows::Storage::FileProperties;
#include <string/stdstring.h>
#include <retro_environment.h>
#include <uwp/uwp_func.h>
#include <uwp/uwp_async.h>
namespace
{
/* Dear Microsoft
* I really appreciate all the effort you took to not provide any
* synchronous file APIs and block all attempts to synchronously
* wait for the results of async tasks for "smooth user experience",
* but I'm not going to run and rewrite all RetroArch cores for
* async I/O. I hope you like this hack I made instead.
*/
template<typename T>
T RunAsync(std::function<concurrency::task<T>()> func)
{
volatile bool finished = false;
Platform::Exception^ exception = nullptr;
T result;
func().then([&finished, &exception, &result](concurrency::task<T> t) {
try
{
result = t.get();
}
catch (Platform::Exception^ exception_)
{
exception = exception_;
}
finished = true;
});
/* Don't stall the UI thread - prevents a deadlock */
Windows::UI::Core::CoreWindow^ corewindow = Windows::UI::Core::CoreWindow::GetForCurrentThread();
while (!finished)
{
if (corewindow) {
corewindow->Dispatcher->ProcessEvents(Windows::UI::Core::CoreProcessEventsOption::ProcessAllIfPresent);
}
}
if (exception != nullptr)
throw exception;
return result;
}
template<typename T>
T RunAsyncAndCatchErrors(std::function<concurrency::task<T>()> func, T valueOnError)
{
try
{
return RunAsync<T>(func);
}
catch (Platform::Exception^ e)
{
return valueOnError;
}
}
void windowsize_path(wchar_t* path)
{
/* UWP deals with paths containing / instead of \ way worse than normal Windows */

View File

@ -293,6 +293,7 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\uwp\uwp_async.h" />
<ClInclude Include="..\..\..\uwp\uwp_func.h" />
<ClInclude Include="..\..\..\uwp\uwp_main.h" />
</ItemGroup>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="uwp">
@ -29,6 +29,9 @@
<ClInclude Include="..\..\..\uwp\uwp_main.h">
<Filter>uwp</Filter>
</ClInclude>
<ClInclude Include="..\..\..\uwp\uwp_async.h">
<Filter>uwp</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\griffin\griffin.c">

View File

@ -2259,6 +2259,10 @@ void dir_check_defaults(void)
*/
#if defined(ORBIS) || defined(ANDROID)
if (path_is_valid("host0:app/custom.ini"))
#elif defined(__WINRT__)
char path[MAX_PATH];
fill_pathname_expand_special(path, "~\\custom.ini", MAX_PATH);
if (path_is_valid(path))
#else
if (path_is_valid("custom.ini"))
#endif

86
uwp/uwp_async.h Normal file
View File

@ -0,0 +1,86 @@
/* Copyright (C) 2018-2019 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (uwp_async.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <ppl.h>
#include <ppltasks.h>
#include "uwp_main.h"
#include "uwp_func.h"
#ifdef __cplusplus
#ifdef __cplusplus_winrt
namespace
{
/* Dear Microsoft
* I really appreciate all the effort you took to not provide any
* synchronous file APIs and block all attempts to synchronously
* wait for the results of async tasks for "smooth user experience",
* but I'm not going to run and rewrite all RetroArch cores for
* async I/O. I hope you like this hack I made instead.
*/
template<typename T>
T RunAsync(std::function<concurrency::task<T>()> func)
{
volatile bool finished = false;
Platform::Exception^ exception = nullptr;
T result;
func().then([&finished, &exception, &result](concurrency::task<T> t) {
try
{
result = t.get();
}
catch (Platform::Exception ^ exception_)
{
exception = exception_;
}
finished = true;
});
/* Don't stall the UI thread - prevents a deadlock */
Windows::UI::Core::CoreWindow^ corewindow = Windows::UI::Core::CoreWindow::GetForCurrentThread();
while (!finished)
{
if (corewindow) {
corewindow->Dispatcher->ProcessEvents(Windows::UI::Core::CoreProcessEventsOption::ProcessAllIfPresent);
}
}
if (exception != nullptr)
throw exception;
return result;
}
template<typename T>
T RunAsyncAndCatchErrors(std::function<concurrency::task<T>()> func, T valueOnError)
{
try
{
return RunAsync<T>(func);
}
catch (Platform::Exception ^ e)
{
return valueOnError;
}
}
}
#endif
#endif

View File

@ -36,6 +36,8 @@ void uwp_input_next_frame(void);
bool uwp_keyboard_pressed(unsigned key);
int16_t uwp_mouse_state(unsigned port, unsigned id, bool screen);
int16_t uwp_pointer_state(unsigned idx, unsigned id, bool screen);
const char* uwp_get_cpu_model_name();
enum retro_language uwp_get_language();
void uwp_fill_installed_core_packages(struct string_list *list);

View File

@ -23,9 +23,11 @@
#include "../libretro-common/include/encodings/utf.h"
#include "../libretro-common/include/lists/string_list.h"
#include "uwp_func.h"
#include "uwp_async.h"
#include <ppltasks.h>
#include <collection.h>
#include <windows.devices.enumeration.h>
using namespace RetroArchUWP;
@ -42,10 +44,12 @@ using namespace Windows::System::Profile;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Graphics::Display;
using namespace Windows::Devices::Enumeration;
char uwp_dir_install[PATH_MAX_LENGTH];
char uwp_dir_data[PATH_MAX_LENGTH];
char uwp_device_family[128];
char win32_cpu_model_name[128] = { 0 };
// Some keys are unavailable in the VirtualKey enum (wtf) but the old-style constants work
const struct rarch_key_map rarch_key_map_uwp[] = {
@ -162,6 +166,14 @@ const struct rarch_key_map rarch_key_map_uwp[] = {
{ 0, RETROK_UNKNOWN }
};
#define MAX_TOUCH 16
struct input_pointer {
int id;
bool isInContact;
short x, y;
short full_x, full_y;
};
struct uwp_input_state_t {
short mouse_screen_x;
short mouse_screen_y;
@ -174,15 +186,20 @@ struct uwp_input_state_t {
bool mouse_button5;
short mouse_wheel_left;
short mouse_wheel_up;
short touch_screen_x;
short touch_screen_y;
short touch_rel_x;
short touch_rel_y;
bool touch_touched;
unsigned touch_count;
struct input_pointer touch[MAX_TOUCH];
};
struct uwp_input_state_t uwp_current_input, uwp_next_input;
// Taken from DirectX UWP samples - on Xbox, everything is scaled 200% so getting the DPI calculation correct is crucial
static inline float ConvertDipsToPixels(float dips, float dpi)
{
static const float dipsPerInch = 96.0f;
return floorf(dips * dpi / dipsPerInch + 0.5f);
}
// The main function is only used to initialize our IFrameworkView class.
[Platform::MTAThread]
int main(Platform::Array<Platform::String^>^)
@ -417,6 +434,9 @@ void App::OnKey(CoreWindow^ sender, KeyEventArgs^ args)
void App::OnPointer(CoreWindow^ sender, PointerEventArgs^ args)
{
float dpi = DisplayInformation::GetForCurrentView()->LogicalDpi;
if (args->CurrentPoint->PointerDevice->PointerDeviceType == PointerDeviceType::Mouse)
{
uwp_next_input.mouse_left = args->CurrentPoint->Properties->IsLeftButtonPressed;
@ -424,8 +444,8 @@ void App::OnPointer(CoreWindow^ sender, PointerEventArgs^ args)
uwp_next_input.mouse_right = args->CurrentPoint->Properties->IsRightButtonPressed;
uwp_next_input.mouse_button4 = args->CurrentPoint->Properties->IsXButton1Pressed;
uwp_next_input.mouse_button5 = args->CurrentPoint->Properties->IsXButton2Pressed;
uwp_next_input.mouse_screen_x = args->CurrentPoint->Position.X;
uwp_next_input.mouse_screen_y = args->CurrentPoint->Position.Y;
uwp_next_input.mouse_screen_x = ConvertDipsToPixels(args->CurrentPoint->Position.X, dpi);
uwp_next_input.mouse_screen_y = ConvertDipsToPixels(args->CurrentPoint->Position.Y, dpi);
uwp_next_input.mouse_rel_x = uwp_next_input.mouse_screen_x - uwp_current_input.mouse_screen_x;
uwp_next_input.mouse_rel_y = uwp_next_input.mouse_screen_y - uwp_current_input.mouse_screen_y;
if (args->CurrentPoint->Properties->IsHorizontalMouseWheel)
@ -435,11 +455,53 @@ void App::OnPointer(CoreWindow^ sender, PointerEventArgs^ args)
}
else
{
uwp_next_input.touch_touched = args->CurrentPoint->IsInContact;
uwp_next_input.touch_screen_x = args->CurrentPoint->Position.X;
uwp_next_input.touch_screen_y = args->CurrentPoint->Position.Y;
uwp_next_input.touch_rel_x = uwp_next_input.touch_screen_x - uwp_current_input.touch_screen_x;
uwp_next_input.touch_rel_y = uwp_next_input.touch_screen_y - uwp_current_input.touch_screen_y;
unsigned i, free_index = MAX_TOUCH; bool found = false;
int id = args->CurrentPoint->PointerId;
for (i = 0; i < uwp_next_input.touch_count; i++)
{
if (!uwp_next_input.touch[i].isInContact && free_index == MAX_TOUCH)
free_index = i;
if (uwp_next_input.touch[i].id == id)
{
found = true;
break;
}
}
if (!found)
{
if (free_index >= 0 && free_index < uwp_next_input.touch_count)
i = free_index;
else if (uwp_next_input.touch_count + 1 < MAX_TOUCH)
i = ++uwp_next_input.touch_count;
else
return;
}
uwp_next_input.touch[i].id = id;
struct video_viewport vp;
/* convert from event coordinates to core and screen coordinates */
vp.x = 0;
vp.y = 0;
vp.width = 0;
vp.height = 0;
vp.full_width = 0;
vp.full_height = 0;
video_driver_translate_coord_viewport_wrap(
&vp,
ConvertDipsToPixels(args->CurrentPoint->Position.X, dpi),
ConvertDipsToPixels(args->CurrentPoint->Position.Y, dpi),
&uwp_next_input.touch[i].x,
&uwp_next_input.touch[i].y,
&uwp_next_input.touch[i].full_x,
&uwp_next_input.touch[i].full_y);
uwp_next_input.touch[i].isInContact = args->CurrentPoint->IsInContact;
}
}
@ -476,13 +538,6 @@ void App::OnPackageInstalling(PackageCatalog^ sender, PackageInstallingEventArgs
}
}
// Taken from DirectX UWP samples - on Xbox, everything is scaled 200% so getting the DPI calculation correct is crucial
static inline float ConvertDipsToPixels(float dips, float dpi)
{
static const float dipsPerInch = 96.0f;
return floorf(dips * dpi / dipsPerInch + 0.5f);
}
// Implement UWP equivalents of various win32_* functions
extern "C" {
@ -562,13 +617,12 @@ extern "C" {
uwp_next_input.mouse_rel_y = 0;
uwp_next_input.mouse_wheel_up %= WHEEL_DELTA;
uwp_next_input.mouse_wheel_left %= WHEEL_DELTA;
uwp_next_input.touch_rel_x = 0;
uwp_next_input.touch_rel_y = 0;
}
bool uwp_keyboard_pressed(unsigned key)
{
unsigned sym = rarch_keysym_lut[(enum retro_key)key];
VirtualKey sym = (VirtualKey)rarch_keysym_lut[(enum retro_key)key];
if (sym == VirtualKey::None) return false;
CoreWindow^ window = CoreWindow::GetForCurrentThread();
if (!window)
{
@ -576,7 +630,7 @@ extern "C" {
// Dolphin core runs on its own CPU thread separate from the UI-thread and so we must do a check for this.
return false;
}
return (window->GetKeyState((VirtualKey)sym) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down;
return (window->GetKeyState(sym) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down;
}
int16_t uwp_mouse_state(unsigned port, unsigned id, bool screen)
@ -612,17 +666,18 @@ extern "C" {
return 0;
}
// TODO: I don't have any touch-enabled Windows devices to test if this actually works
int16_t uwp_pointer_state(unsigned idx, unsigned id, bool screen)
{
switch (id)
{
case RETRO_DEVICE_ID_POINTER_X:
return screen ? uwp_current_input.touch_screen_x : uwp_current_input.touch_rel_x;
return screen ? uwp_current_input.touch[idx].full_x : uwp_current_input.touch[idx].x;
case RETRO_DEVICE_ID_POINTER_Y:
return screen ? uwp_current_input.touch_screen_y : uwp_current_input.touch_rel_y;
return screen ? uwp_current_input.touch[idx].full_y : uwp_current_input.touch[idx].y;
case RETRO_DEVICE_ID_POINTER_PRESSED:
return uwp_current_input.touch_touched;
return uwp_current_input.touch[idx].isInContact;
case RETRO_DEVICE_ID_POINTER_COUNT:
return uwp_current_input.touch_count;
default:
break;
}
@ -634,4 +689,72 @@ extern "C" {
{
Windows::System::Launcher::LaunchUriAsync(ref new Uri("ms-settings:privacy-broadfilesystemaccess"));
}
enum retro_language uwp_get_language()
{
auto lang = Windows::System::UserProfile::GlobalizationPreferences::Languages->GetAt(0);
char lang_bcp[16] = { 0 };
char lang_iso[16] = { 0 };
wcstombs(lang_bcp, lang->Data(), 16);
/* Trying to convert BCP 47 language codes to ISO 639 ones */
string_list* split;
split = string_split(lang_bcp, "-");
strcat(lang_iso, split->elems[0].data);
if (split->size >= 2)
{
strcat(lang_iso, "_");
strcat(lang_iso, split->elems[split->size >= 3 ? 2 : 1].data);
}
free(split);
return rarch_get_language_from_iso(lang_iso);
}
const char *uwp_get_cpu_model_name()
{
Platform::String^ cpu_id = nullptr;
Platform::String^ cpu_name = nullptr;
/* GUID_DEVICE_PROCESSOR: {97FADB10-4E33-40AE-359C-8BEF029DBDD0} */
Platform::String^ if_filter = L"System.Devices.InterfaceClassGuid:=\"{97FADB10-4E33-40AE-359C-8BEF029DBDD0}\"";
/* Enumerate all CPU DeviceInterfaces, and get DeviceInstanceID of the first one. */
cpu_id = RunAsyncAndCatchErrors<Platform::String^>([&]() {
return create_task(DeviceInformation::FindAllAsync(if_filter)).then(
[&](DeviceInformationCollection^ collection)
{
return dynamic_cast<Platform::String^>(
collection->GetAt(0)->Properties->Lookup(L"System.Devices.DeviceInstanceID"));
});
}, nullptr);
if (cpu_id)
{
Platform::String^ dev_filter = L"System.Devices.DeviceInstanceID:=\"" + cpu_id + L"\"";
/* Get the Device with the same ID as the DeviceInterface
* Then get the name (description) of that Device
* We have to do this because the DeviceInterface we get doesn't have a proper description. */
cpu_name = RunAsyncAndCatchErrors<Platform::String^>([&]() {
return create_task(
DeviceInformation::FindAllAsync(dev_filter, {}, DeviceInformationKind::Device)).then(
[&](DeviceInformationCollection^ collection)
{
return cpu_name = collection->GetAt(0)->Name;
});
}, nullptr);
}
if (cpu_name)
{
wcstombs(win32_cpu_model_name, cpu_name->Data(), 128);
return win32_cpu_model_name;
}
else
return "Unknown";
}
}