mirror of
https://github.com/libretro/RetroArch
synced 2025-02-08 06:40:14 +00:00
commit
e61fc4e427
@ -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
|
||||
|
@ -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"
|
||||
};
|
||||
|
@ -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 */
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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
86
uwp/uwp_async.h
Normal 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
|
@ -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);
|
||||
|
||||
|
177
uwp/uwp_main.cpp
177
uwp/uwp_main.cpp
@ -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";
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user