Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/UWP/PPSSPP_UWPMain.cpp
5731 views
1
#include "pch.h"
2
#include "PPSSPP_UWPMain.h"
3
4
#include <mutex>
5
#include <list>
6
#include <memory>
7
#include <thread>
8
9
#include "Common/File/FileUtil.h"
10
#include "Common/Net/HTTPClient.h"
11
#include "Common/Net/Resolve.h"
12
#include "Common/GPU/thin3d_create.h"
13
14
#include "Common/Common.h"
15
#include "Common/Audio/AudioBackend.h"
16
#include "Common/Input/InputState.h"
17
#include "Common/File/VFS/VFS.h"
18
#include "Common/Thread/ThreadUtil.h"
19
#include "Common/Data/Encoding/Utf8.h"
20
#include "Common/DirectXHelper.h"
21
#include "Common/Log.h"
22
#include "Common/Log/LogManager.h"
23
#include "Common/TimeUtil.h"
24
#include "Common/StringUtils.h"
25
#include "Common/System/Display.h"
26
#include "Common/System/NativeApp.h"
27
#include "Common/System/Request.h"
28
29
#include "Core/System.h"
30
#include "Core/Loaders.h"
31
#include "Core/Config.h"
32
33
#include "Windows/InputDevice.h"
34
#include "Windows/XinputDevice.h"
35
#include "NKCodeFromWindowsSystem.h"
36
#include "XAudioSoundStream.h"
37
#include "UWPUtil.h"
38
#include "App.h"
39
40
// UWP Helpers includes
41
#include "UWPHelpers/StorageManager.h"
42
#include "UWPHelpers/StorageAsync.h"
43
#include "UWPHelpers/LaunchItem.h"
44
#include "UWPHelpers/InputHelpers.h"
45
#include "Windows/InputDevice.h"
46
47
using namespace UWP;
48
using namespace winrt;
49
using namespace winrt::Windows::Foundation;
50
using namespace winrt::Windows::Storage;
51
using namespace winrt::Windows::Storage::Streams;
52
using namespace winrt::Windows::System::Threading;
53
using namespace winrt::Windows::ApplicationModel::DataTransfer;
54
using namespace winrt::Windows::Devices::Enumeration;
55
56
// TODO: Use Microsoft::WRL::ComPtr<> for D3D11 objects?
57
// TODO: See https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/WindowsAudioSession for WASAPI with UWP
58
// TODO: Low latency input: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/LowLatencyInput/cpp
59
60
// Loads and initializes application assets when the application is loaded.
61
PPSSPP_UWPMain::PPSSPP_UWPMain(App *app, const std::shared_ptr<DX::DeviceResources>& deviceResources) :
62
app_(app),
63
m_deviceResources(deviceResources)
64
{
65
TimeInit();
66
67
// Register to be notified if the Device is lost or recreated
68
m_deviceResources->RegisterDeviceNotify(this);
69
70
ctx_.reset(new UWPGraphicsContext(deviceResources));
71
72
#if _DEBUG
73
g_logManager.SetAllLogLevels(LogLevel::LDEBUG);
74
75
if (g_Config.bEnableLogging) {
76
g_logManager.SetFileLogPath(Path(GetLogFile()));
77
}
78
#endif
79
80
// At this point we have main requirements initialized (Log, Config, NativeInit, Device)
81
NativeInitGraphics(ctx_.get());
82
NativeResized();
83
84
int width = m_deviceResources->GetScreenViewport().Width;
85
int height = m_deviceResources->GetScreenViewport().Height;
86
87
ctx_->GetDrawContext()->HandleEvent(Draw::Event::GOT_BACKBUFFER, width, height, m_deviceResources->GetBackBufferRenderTargetView());
88
89
// add first XInput device to respond
90
g_InputManager.AddDevice(new XinputDevice());
91
g_InputManager.BeginPolling();
92
93
// Prepare input pane (for Xbox & touch devices)
94
PrepareInputPane();
95
}
96
97
PPSSPP_UWPMain::~PPSSPP_UWPMain() {
98
g_InputManager.StopPolling();
99
g_InputManager.Shutdown();
100
101
ctx_->GetDrawContext()->HandleEvent(Draw::Event::LOST_BACKBUFFER, 0, 0, nullptr);
102
NativeShutdownGraphics();
103
NativeShutdown();
104
g_VFS.Clear();
105
106
// Deregister device notification
107
m_deviceResources->RegisterDeviceNotify(nullptr);
108
net::Shutdown();
109
}
110
111
// Updates application state when the window size changes (e.g. device orientation change)
112
void PPSSPP_UWPMain::CreateWindowSizeDependentResources() {
113
ctx_->GetDrawContext()->HandleEvent(Draw::Event::LOST_BACKBUFFER, 0, 0, nullptr);
114
115
NativeResized();
116
117
int width = m_deviceResources->GetScreenViewport().Width;
118
int height = m_deviceResources->GetScreenViewport().Height;
119
ctx_->GetDrawContext()->HandleEvent(Draw::Event::GOT_BACKBUFFER, width, height, m_deviceResources->GetBackBufferRenderTargetView());
120
}
121
122
void PPSSPP_UWPMain::UpdateScreenState() {
123
// This code was included into the render loop directly
124
// based on my test I don't understand why it should be called each loop
125
// is it better to call it on demand only, like when screen state changed?
126
auto context = m_deviceResources->GetD3DDeviceContext();
127
128
switch (m_deviceResources->ComputeDisplayRotation()) {
129
case DXGI_MODE_ROTATION_IDENTITY: g_display.rotation = DisplayRotation::ROTATE_0; break;
130
case DXGI_MODE_ROTATION_ROTATE90: g_display.rotation = DisplayRotation::ROTATE_90; break;
131
case DXGI_MODE_ROTATION_ROTATE180: g_display.rotation = DisplayRotation::ROTATE_180; break;
132
case DXGI_MODE_ROTATION_ROTATE270: g_display.rotation = DisplayRotation::ROTATE_270; break;
133
}
134
// Not super elegant but hey.
135
auto orientMatrix = m_deviceResources->GetOrientationTransform3D();
136
memcpy(&g_display.rot_matrix, &orientMatrix, sizeof(float) * 16);
137
138
// Reset the viewport to target the whole screen.
139
auto viewport = m_deviceResources->GetScreenViewport();
140
141
g_display.pixel_xres = viewport.Width;
142
g_display.pixel_yres = viewport.Height;
143
144
if (g_display.rotation == DisplayRotation::ROTATE_90 || g_display.rotation == DisplayRotation::ROTATE_270) {
145
// We need to swap our width/height.
146
// TODO: This is most likely dead code, since we no longer support Windows Phone.
147
std::swap(g_display.pixel_xres, g_display.pixel_yres);
148
}
149
150
// TODO: The below stuff is probably completely redundant since the UWP app elsewhere calls Native_UpdateScreenScale.
151
152
float dpi = m_deviceResources->GetActualDpi();
153
if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_MOBILE) {
154
// Boost DPI a bit to look better.
155
dpi *= 96.0f / 136.0f;
156
}
157
158
g_display.dpi_scale_real_x = 96.0f / dpi;
159
g_display.dpi_scale_real_y = 96.0f / dpi;
160
161
g_display.dpi_scale_x = g_display.dpi_scale_real_x;
162
g_display.dpi_scale_y = g_display.dpi_scale_real_y;
163
g_display.pixel_in_dps_x = 1.0f / g_display.dpi_scale_x;
164
g_display.pixel_in_dps_y = 1.0f / g_display.dpi_scale_y;
165
166
g_display.dp_xres = g_display.pixel_xres * g_display.dpi_scale_x;
167
g_display.dp_yres = g_display.pixel_yres * g_display.dpi_scale_y;
168
169
context->RSSetViewports(1, &viewport);
170
}
171
172
// Renders the current frame according to the current application state.
173
// Returns true if the frame was rendered and is ready to be displayed.
174
bool PPSSPP_UWPMain::Render() {
175
static bool hasSetThreadName = false;
176
if (!hasSetThreadName) {
177
SetCurrentThreadName("EmuThread");
178
hasSetThreadName = true;
179
}
180
181
UpdateScreenState();
182
183
NativeFrame(ctx_.get());
184
return true;
185
}
186
187
// Notifies renderers that device resources need to be released.
188
void PPSSPP_UWPMain::OnDeviceLost() {
189
ctx_->GetDrawContext()->HandleEvent(Draw::Event::LOST_DEVICE, 0, 0, nullptr);
190
}
191
192
// Notifies renderers that device resources may now be recreated.
193
void PPSSPP_UWPMain::OnDeviceRestored() {
194
CreateWindowSizeDependentResources();
195
196
ctx_->GetDrawContext()->HandleEvent(Draw::Event::GOT_DEVICE, 0, 0, nullptr);
197
}
198
199
void PPSSPP_UWPMain::OnKeyDown(int scanCode, winrt::Windows::System::VirtualKey virtualKey, int repeatCount) {
200
// TODO: Look like (Ctrl, Alt, Shift) don't trigger this event
201
bool isDPad = (int)virtualKey >= 195 && (int)virtualKey <= 218; // DPad buttons range
202
DPadInputState(isDPad);
203
204
auto iter = virtualKeyCodeToNKCode.find(virtualKey);
205
if (iter != virtualKeyCodeToNKCode.end()) {
206
KeyInput key{};
207
key.deviceId = DEVICE_ID_KEYBOARD;
208
key.keyCode = iter->second;
209
key.flags = KeyInputFlags::DOWN;
210
if (repeatCount > 1)
211
key.flags |= KeyInputFlags::IS_REPEAT;
212
NativeKey(key);
213
}
214
}
215
216
void PPSSPP_UWPMain::OnKeyUp(int scanCode, winrt::Windows::System::VirtualKey virtualKey) {
217
auto iter = virtualKeyCodeToNKCode.find(virtualKey);
218
if (iter != virtualKeyCodeToNKCode.end()) {
219
KeyInput key{};
220
key.deviceId = DEVICE_ID_KEYBOARD;
221
key.keyCode = iter->second;
222
key.flags = KeyInputFlags::UP;
223
NativeKey(key);
224
}
225
}
226
227
void PPSSPP_UWPMain::OnCharacterReceived(int scanCode, unsigned int keyCode) {
228
// This event triggered only in chars case, (Arrows, Delete..etc don't call it)
229
// TODO: Add ` && !IsCtrlOnHold()` once it's ready and implemented
230
if (isTextEditActive()) {
231
KeyInput key{};
232
key.deviceId = DEVICE_ID_KEYBOARD;
233
key.keyCode = (InputKeyCode)keyCode;
234
// After many tests turns out for char just add `KeyInputFlags::CHAR` for the flags
235
// any other flag like `KeyInputFlags::DOWN` will cause conflict and trigger something else
236
key.flags = KeyInputFlags::CHAR;
237
NativeKey(key);
238
}
239
}
240
241
void PPSSPP_UWPMain::OnMouseWheel(float delta) {
242
InputKeyCode key = NKCODE_EXT_MOUSEWHEEL_UP;
243
if (delta < 0) {
244
key = NKCODE_EXT_MOUSEWHEEL_DOWN;
245
} else if (delta == 0) {
246
return;
247
}
248
249
KeyInput keyInput{};
250
keyInput.keyCode = key;
251
keyInput.deviceId = DEVICE_ID_MOUSE;
252
keyInput.flags = KeyInputFlags::DOWN;
253
NativeKey(keyInput);
254
255
// KeyInputFlags::UP is now sent automatically afterwards for mouse wheel events, see NativeKey.
256
}
257
258
bool PPSSPP_UWPMain::OnHardwareButton(HardwareButton button) {
259
KeyInput keyInput{};
260
keyInput.deviceId = DEVICE_ID_KEYBOARD;
261
keyInput.flags = KeyInputFlags::DOWN | KeyInputFlags::UP;
262
switch (button) {
263
case HardwareButton::BACK:
264
keyInput.keyCode = NKCODE_BACK;
265
return NativeKey(keyInput);
266
default:
267
return false;
268
}
269
}
270
271
void PPSSPP_UWPMain::OnTouchEvent(TouchInputFlags flags, int touchId, float x, float y, double timestamp) {
272
// We get the coordinate in Windows' device independent pixels already. So let's undo that,
273
// and then apply our own "dpi".
274
float dpiFactor_x = m_deviceResources->GetActualDpi() / 96.0f;
275
float dpiFactor_y = dpiFactor_x;
276
dpiFactor_x /= g_display.pixel_in_dps_x;
277
dpiFactor_y /= g_display.pixel_in_dps_y;
278
279
TouchInput input{};
280
input.id = touchId;
281
input.x = x * dpiFactor_x;
282
input.y = y * dpiFactor_y;
283
input.flags = flags;
284
input.timestamp = timestamp;
285
NativeTouch(input);
286
287
KeyInput key{};
288
key.deviceId = DEVICE_ID_MOUSE;
289
if (flags & TouchInputFlags::DOWN) {
290
key.keyCode = NKCODE_EXT_MOUSEBUTTON_1;
291
key.flags = KeyInputFlags::DOWN;
292
NativeKey(key);
293
}
294
if (flags & TouchInputFlags::UP) {
295
key.keyCode = NKCODE_EXT_MOUSEBUTTON_1;
296
key.flags = KeyInputFlags::UP;
297
NativeKey(key);
298
}
299
}
300
301
void PPSSPP_UWPMain::OnSuspend() {
302
// TODO
303
}
304
305
306
UWPGraphicsContext::UWPGraphicsContext(std::shared_ptr<DX::DeviceResources> resources) {
307
std::vector<std::string> adapterNames = resources->GetAdapters();
308
309
draw_ = Draw::T3DCreateD3D11Context(
310
resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetSwapChain(), resources->GetDeviceFeatureLevel(), 0, adapterNames, g_Config.iInflightFrames);
311
bool success = draw_->CreatePresets();
312
_assert_(success);
313
}
314
315
void UWPGraphicsContext::Shutdown() {
316
delete draw_;
317
}
318
319
std::string System_GetProperty(SystemProperty prop) {
320
static bool hasCheckedGPUDriverVersion = false;
321
switch (prop) {
322
case SYSPROP_NAME:
323
return GetSystemName();
324
case SYSPROP_SYSTEMBUILD:
325
return GetWindowsBuild();
326
case SYSPROP_LANGREGION:
327
return GetLangRegion();
328
case SYSPROP_CLIPBOARD_TEXT:
329
/* TODO: Need to either change this API or do this on a thread in an ugly fashion.
330
auto view = winrt::Windows::ApplicationModel::DataTransfer::Clipboard::GetContent();
331
if (view) {
332
winrt::hstring text = co_await view.GetTextAsync();
333
}
334
*/
335
return "";
336
case SYSPROP_GPUDRIVER_VERSION:
337
return "";
338
case SYSPROP_BUILD_VERSION:
339
return PPSSPP_GIT_VERSION;
340
default:
341
return "";
342
}
343
}
344
345
std::vector<std::string> System_GetPropertyStringVec(SystemProperty prop) {
346
std::vector<std::string> result;
347
switch (prop) {
348
case SYSPROP_TEMP_DIRS:
349
{
350
std::wstring tempPath(MAX_PATH, '\0');
351
size_t sz = GetTempPath((DWORD)tempPath.size(), &tempPath[0]);
352
if (sz >= tempPath.size()) {
353
tempPath.resize(sz);
354
sz = GetTempPath((DWORD)tempPath.size(), &tempPath[0]);
355
}
356
// Need to resize off the null terminator either way.
357
tempPath.resize(sz);
358
result.push_back(ConvertWStringToUTF8(tempPath));
359
return result;
360
}
361
362
default:
363
return result;
364
}
365
}
366
367
extern AudioBackend *g_audioBackend;
368
369
int64_t System_GetPropertyInt(SystemProperty prop) {
370
switch (prop) {
371
case SYSPROP_AUDIO_SAMPLE_RATE:
372
return g_audioBackend ? g_audioBackend->SampleRate() : -1;
373
374
case SYSPROP_DEVICE_TYPE:
375
{
376
if (IsMobile()) {
377
return DEVICE_TYPE_MOBILE;
378
} else if (IsXBox()) {
379
return DEVICE_TYPE_TV;
380
} else {
381
return DEVICE_TYPE_DESKTOP;
382
}
383
}
384
case SYSPROP_DISPLAY_XRES:
385
{
386
winrt::Windows::UI::Core::CoreWindow corewindow = winrt::Windows::UI::Core::CoreWindow::GetForCurrentThread();
387
if (corewindow) {
388
return (int)corewindow.Bounds().Width;
389
}
390
}
391
case SYSPROP_DISPLAY_YRES:
392
{
393
winrt::Windows::UI::Core::CoreWindow corewindow = winrt::Windows::UI::Core::CoreWindow::GetForCurrentThread();
394
if (corewindow) {
395
return (int)corewindow.Bounds().Height;
396
}
397
}
398
default:
399
return -1;
400
}
401
}
402
403
float System_GetPropertyFloat(SystemProperty prop) {
404
switch (prop) {
405
case SYSPROP_DISPLAY_REFRESH_RATE:
406
return 60.f;
407
case SYSPROP_DISPLAY_SAFE_INSET_LEFT:
408
case SYSPROP_DISPLAY_SAFE_INSET_RIGHT:
409
case SYSPROP_DISPLAY_SAFE_INSET_TOP:
410
case SYSPROP_DISPLAY_SAFE_INSET_BOTTOM:
411
return 0.0f;
412
default:
413
return -1;
414
}
415
}
416
417
void System_Toast(std::string_view str) {}
418
419
bool System_GetPropertyBool(SystemProperty prop) {
420
switch (prop) {
421
case SYSPROP_HAS_TEXT_CLIPBOARD:
422
case SYSPROP_HAS_OPEN_DIRECTORY:
423
{
424
return !IsXBox();
425
}
426
case SYSPROP_HAS_FILE_BROWSER:
427
return true;
428
case SYSPROP_HAS_FOLDER_BROWSER:
429
return true;
430
case SYSPROP_HAS_IMAGE_BROWSER:
431
return true; // we just use the file browser
432
case SYSPROP_HAS_BACK_BUTTON:
433
return true;
434
case SYSPROP_HAS_ACCELEROMETER:
435
return IsMobile();
436
case SYSPROP_APP_GOLD:
437
#ifdef GOLD
438
return true;
439
#else
440
return false;
441
#endif
442
case SYSPROP_CAN_JIT:
443
return true;
444
case SYSPROP_HAS_KEYBOARD:
445
{
446
// Do actual check
447
// touch devices has input pane, we need to depend on it
448
// I don't know any possible way to display input dialog in non-xaml apps
449
return isKeyboardAvailable() || isTouchAvailable();
450
}
451
case SYSPROP_DEBUGGER_PRESENT:
452
return IsDebuggerPresent();
453
case SYSPROP_OK_BUTTON_LEFT:
454
return true;
455
default:
456
return false;
457
}
458
}
459
460
void System_Notify(SystemNotification notification) {}
461
462
bool System_MakeRequest(SystemRequestType type, int requestId, const std::string &param1, const std::string &param2, int64_t param3, int64_t param4) {
463
switch (type) {
464
465
case SystemRequestType::EXIT_APP:
466
{
467
bool state = false;
468
ExecuteTask(state, winrt::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView().TryConsolidateAsync());
469
if (!state) {
470
// Notify the user?
471
}
472
return true;
473
}
474
case SystemRequestType::RESTART_APP:
475
{
476
winrt::Windows::ApplicationModel::Core::AppRestartFailureReason error;
477
ExecuteTask(error, winrt::Windows::ApplicationModel::Core::CoreApplication::RequestRestartAsync(L""));
478
if (error != winrt::Windows::ApplicationModel::Core::AppRestartFailureReason::RestartPending) {
479
// Shutdown
480
System_MakeRequest(SystemRequestType::EXIT_APP, requestId, param1, param2, param3, param4);
481
}
482
return true;
483
}
484
case SystemRequestType::BROWSE_FOR_IMAGE:
485
{
486
std::vector<std::string> supportedExtensions = { ".jpg", ".png" };
487
488
//Call file picker
489
std::string filePath = ChooseFile(supportedExtensions);
490
if (filePath.size() > 1) {
491
g_requestManager.PostSystemSuccess(requestId, filePath.c_str());
492
}
493
else {
494
g_requestManager.PostSystemFailure(requestId);
495
}
496
return true;
497
}
498
case SystemRequestType::BROWSE_FOR_FILE:
499
{
500
std::vector<std::string> supportedExtensions = {};
501
switch ((BrowseFileType)param3) {
502
case BrowseFileType::BOOTABLE:
503
supportedExtensions = { ".cso", ".iso", ".chd", ".elf", ".pbp", ".zip", ".prx", ".bin" }; // should .bin even be here?
504
break;
505
case BrowseFileType::INI:
506
supportedExtensions = { ".ini" };
507
break;
508
case BrowseFileType::ZIP:
509
supportedExtensions = { ".zip" };
510
break;
511
case BrowseFileType::SYMBOL_MAP:
512
supportedExtensions = { ".ppmap" };
513
break;
514
case BrowseFileType::SYMBOL_MAP_NOCASH:
515
supportedExtensions = { ".sym" };
516
break;
517
case BrowseFileType::DB:
518
supportedExtensions = { ".db" };
519
break;
520
case BrowseFileType::SOUND_EFFECT:
521
supportedExtensions = { ".wav", ".mp3" };
522
break;
523
case BrowseFileType::ATRAC3:
524
supportedExtensions = { ".at3" };
525
break;
526
case BrowseFileType::ANY:
527
// 'ChooseFile' will added '*' by default when there are no extensions assigned
528
break;
529
default:
530
ERROR_LOG(Log::FileSystem, "Unexpected BrowseFileType: %d", param3);
531
return false;
532
}
533
534
//Call file picker
535
std::string filePath = ChooseFile(supportedExtensions);
536
if (filePath.size() > 1) {
537
g_requestManager.PostSystemSuccess(requestId, filePath.c_str());
538
}
539
else {
540
g_requestManager.PostSystemFailure(requestId);
541
}
542
543
return true;
544
}
545
case SystemRequestType::BROWSE_FOR_FOLDER:
546
{
547
std::string folderPath = ChooseFolder();
548
if (folderPath.size() > 1) {
549
g_requestManager.PostSystemSuccess(requestId, folderPath.c_str());
550
}
551
else {
552
g_requestManager.PostSystemFailure(requestId);
553
}
554
return true;
555
}
556
case SystemRequestType::NOTIFY_UI_EVENT:
557
{
558
switch ((UIEventNotification)param3) {
559
case UIEventNotification::MENU_RETURN:
560
CloseLaunchItem();
561
break;
562
case UIEventNotification::POPUP_CLOSED:
563
DeactivateTextEditInput();
564
break;
565
case UIEventNotification::TEXT_GOTFOCUS:
566
ActivateTextEditInput(true);
567
break;
568
case UIEventNotification::TEXT_LOSTFOCUS:
569
DeactivateTextEditInput(true);
570
break;
571
default:
572
break;
573
}
574
return true;
575
}
576
case SystemRequestType::COPY_TO_CLIPBOARD:
577
{
578
winrt::Windows::ApplicationModel::DataTransfer::DataPackage dataPackage;
579
dataPackage.RequestedOperation(winrt::Windows::ApplicationModel::DataTransfer::DataPackageOperation::Copy);
580
dataPackage.SetText(ToHString(param1));
581
winrt::Windows::ApplicationModel::DataTransfer::Clipboard::SetContent(dataPackage);
582
return true;
583
}
584
case SystemRequestType::APPLY_FULLSCREEN_STATE:
585
{
586
auto view = winrt::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView();
587
bool flag = !view.IsFullScreenMode();
588
if (param1 == "0") {
589
flag = false;
590
} else if (param1 == "1"){
591
flag = true;
592
}
593
if (flag && g_Config.bFullScreen) {
594
view.TryEnterFullScreenMode();
595
} else if (!g_Config.bFullScreen){
596
view.ExitFullScreenMode();
597
}
598
return true;
599
}
600
case SystemRequestType::SHOW_FILE_IN_FOLDER:
601
OpenFolder(param1);
602
return true;
603
default:
604
return false;
605
}
606
}
607
608
void System_LaunchUrl(LaunchUrlType urlType, std::string_view url) {
609
auto uri = winrt::Windows::Foundation::Uri(ToHString(url));
610
winrt::Windows::System::Launcher::LaunchUriAsync(uri);
611
}
612
613
void System_Vibrate(int length_ms) {
614
#if _M_ARM
615
if (length_ms == -1 || length_ms == -3)
616
length_ms = 50;
617
else if (length_ms == -2)
618
length_ms = 25;
619
else
620
return;
621
622
winrt::Windows::Foundation::TimeSpan timeSpan;
623
timeSpan.count = length_ms * 10000;
624
// TODO: Can't use this?
625
// winrt::Windows::Phone::Devices::Notification::VibrationDevice::GetDefault().Vibrate(timeSpan);
626
#endif
627
}
628
629
void System_AskForPermission(SystemPermission permission) {
630
}
631
632
PermissionStatus System_GetPermissionStatus(SystemPermission permission) {
633
return PERMISSION_STATUS_GRANTED;
634
}
635
636
std::string GetCPUBrandString() {
637
winrt::hstring cpu_id;
638
winrt::hstring cpu_name;
639
640
// GUID_DEVICE_PROCESSOR: {97FADB10-4E33-40AE-359C-8BEF029DBDD0}
641
winrt::hstring if_filter = L"System.Devices.InterfaceClassGuid:=\"{97FADB10-4E33-40AE-359C-8BEF029DBDD0}\"";
642
643
// Enumerate all CPU DeviceInterfaces, and get DeviceInstanceID of the first one.
644
try {
645
auto collection = winrt::Windows::Devices::Enumeration::DeviceInformation::FindAllAsync(if_filter).get();
646
if (collection.Size() > 0) {
647
auto cpu = collection.GetAt(0);
648
auto id = cpu.Properties().Lookup(L"System.Devices.DeviceInstanceID");
649
cpu_id = winrt::unbox_value<winrt::hstring>(id);
650
}
651
}
652
catch (const winrt::hresult_error& e) {
653
INFO_LOG(Log::System, "%s", winrt::to_string(e.message()).c_str());
654
}
655
656
if (!cpu_id.empty()) {
657
// Get the Device with the same ID as the DeviceInterface
658
// Then get the name (description) of that Device
659
// We have to do this because the DeviceInterface we get doesn't have a proper description.
660
winrt::hstring dev_filter = L"System.Devices.DeviceInstanceID:=\"" + cpu_id + L"\"";
661
662
try {
663
auto collection = winrt::Windows::Devices::Enumeration::DeviceInformation::FindAllAsync(dev_filter, {},
664
winrt::Windows::Devices::Enumeration::DeviceInformationKind::Device).get();
665
if (collection.Size() > 0) {
666
cpu_name = collection.GetAt(0).Name();
667
}
668
}
669
catch (const winrt::hresult_error& e) {
670
INFO_LOG(Log::System, "%s", winrt::to_string(e.message()).c_str());
671
}
672
}
673
674
if (!cpu_name.empty()) {
675
return FromHString(cpu_name);
676
} else {
677
return "Unknown";
678
}
679
}
680
681