Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/UWP/UWPHelpers/InputHelpers.cpp
5676 views
1
// Copyright (c) 2023- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include "pch.h"
19
#include <list>
20
#include <thread>
21
22
#include "InputHelpers.h"
23
#include "UWPUtil.h"
24
#include "NKCodeFromWindowsSystem.h"
25
#include "Common/Log.h"
26
#include "Common/OSVersion.h"
27
28
#include <ppl.h>
29
#include <ppltasks.h>
30
31
using namespace winrt;
32
using namespace winrt::Windows::System;
33
using namespace winrt::Windows::Foundation;
34
using namespace winrt::Windows::UI::Core;
35
using namespace winrt::Windows::UI::ViewManagement;
36
using namespace winrt::Windows::ApplicationModel::Core;
37
using namespace winrt::Windows::Data::Xml::Dom;
38
using namespace winrt::Windows::UI::Notifications;
39
40
#pragma region Extenstions
41
template<typename T>
42
bool findInList(std::list<T>& inputList, T& str) {
43
return (std::find(inputList.begin(), inputList.end(), str) != inputList.end());
44
};
45
#pragma endregion
46
47
#pragma region Input Devices
48
bool isKeyboardAvailable() {
49
winrt::Windows::Devices::Input::KeyboardCapabilities keyboardCapabilities;
50
bool hasKeyboard = keyboardCapabilities.KeyboardPresent() != 0;
51
return hasKeyboard;
52
}
53
54
bool isTouchAvailable() {
55
winrt::Windows::Devices::Input::TouchCapabilities touchCapabilities;
56
bool hasTouch = touchCapabilities.TouchPresent() != 0;
57
return hasTouch;
58
}
59
#pragma endregion
60
61
#pragma region Input Keyboard
62
63
bool dPadInputActive = false;
64
bool textEditActive = false;
65
bool inputPaneVisible = false;
66
winrt::agile_ref<InputPane> inputPane = nullptr;
67
68
void OnShowing(const InputPane& pane, const InputPaneVisibilityEventArgs& args) {
69
inputPaneVisible = true;
70
}
71
void OnHiding(const InputPane& pane, const InputPaneVisibilityEventArgs& args) {
72
inputPaneVisible = false;
73
}
74
75
void PrepareInputPane() {
76
auto pane = InputPane::GetForCurrentView();
77
pane.Showing(OnShowing);
78
pane.Hiding(OnHiding);
79
inputPane = pane;
80
}
81
82
// Show input pane (OSK)
83
bool ShowInputPane() {
84
if (inputPane) {
85
return !isInputPaneVisible() ? inputPane.get().TryShow() : true;
86
}
87
return false;
88
}
89
// Hide input pane (OSK)
90
bool HideInputPane() {
91
if (inputPane) {
92
return isInputPaneVisible() ? inputPane.get().TryHide() : true;
93
}
94
return false;
95
}
96
97
// Check if input pane (OSK) visible
98
bool isInputPaneVisible() {
99
return inputPaneVisible;
100
}
101
102
// Check if text edit active (got focus)
103
bool isTextEditActive() {
104
return textEditActive;
105
}
106
107
// Set if the current input is DPad
108
void DPadInputState(bool inputState) {
109
dPadInputActive = inputState;
110
}
111
112
// Check if the current input is DPad
113
bool isDPadActive() {
114
return dPadInputActive;
115
}
116
117
void ActivateTextEditInput(bool byFocus) {
118
// Must be performed from UI thread
119
CoreApplication::MainView().CoreWindow().Dispatcher().RunAsync(
120
CoreDispatcherPriority::Normal,
121
[byFocus]()
122
{
123
if (byFocus) {
124
// Why we should delay? (Mostly happen on XBox)
125
// once the popup appear, UI is reporting 3 focus events for text edit (got, lost, got)
126
// it might be caused by the input pane it self but anyway..
127
// because this has to on UI thread and async, we will end with input pane hidden
128
// the small delay will ensure that last recieved event is (got focus)
129
std::this_thread::sleep_for(std::chrono::milliseconds(100));
130
}
131
132
if (!isInputPaneVisible() && (isDPadActive() || !IsXBox())) {
133
if (ShowInputPane()) {
134
DEBUG_LOG(Log::Common, "Input pane: TryShow accepted");
135
}
136
else {
137
DEBUG_LOG(Log::Common, "Input pane: (TryShow is not accepted or not supported)");
138
}
139
}
140
DEBUG_LOG(Log::Common, "Text edit active");
141
textEditActive = true;
142
});
143
}
144
145
void DeactivateTextEditInput(bool byFocus) {
146
// Must be performed from UI thread
147
CoreApplication::MainView().CoreWindow().Dispatcher().RunAsync(
148
CoreDispatcherPriority::Normal,
149
[byFocus]()
150
{
151
if (isInputPaneVisible()) {
152
if (HideInputPane()) {
153
DEBUG_LOG(Log::Common, "Input pane: TryHide accepted");
154
}
155
else {
156
DEBUG_LOG(Log::Common, "Input pane: TryHide is not accepted, or not supported");
157
}
158
}
159
if (isTextEditActive()) {
160
DEBUG_LOG(Log::Common, "Text edit inactive");
161
textEditActive = false;
162
}
163
});
164
}
165
166
bool IgnoreInput(int keyCode) {
167
// When text edit active and char is passed this function return 'true'
168
// it will help to prevent KeyDown from sending the same code again
169
bool ignoreInput = false;
170
// TODO: Add ` && !IsCtrlOnHold()` once it's ready and implemented
171
if (isTextEditActive()) {
172
// To avoid bothering KeyDown to check this case always
173
// we don't get here unless text edit is active
174
std::list<int> nonCharList = {
175
NKCODE_CTRL_LEFT,
176
NKCODE_CTRL_RIGHT,
177
NKCODE_MOVE_HOME,
178
NKCODE_PAGE_UP,
179
NKCODE_MOVE_END,
180
NKCODE_PAGE_DOWN,
181
NKCODE_FORWARD_DEL,
182
NKCODE_DEL,
183
NKCODE_ENTER,
184
NKCODE_NUMPAD_ENTER,
185
NKCODE_EXT_MOUSEBUTTON_1,
186
NKCODE_EXT_MOUSEBUTTON_2,
187
NKCODE_EXT_MOUSEBUTTON_3,
188
NKCODE_EXT_MOUSEBUTTON_4,
189
NKCODE_EXT_MOUSEBUTTON_5,
190
};
191
if (!isInputPaneVisible()) {
192
// Keyboard active but no on-screen keyboard
193
// allow arrow keys for navigation
194
nonCharList.push_back(NKCODE_DPAD_UP);
195
nonCharList.push_back(NKCODE_DPAD_DOWN);
196
nonCharList.push_back(NKCODE_DPAD_LEFT);
197
nonCharList.push_back(NKCODE_DPAD_RIGHT);
198
nonCharList.push_back(NKCODE_BACK);
199
nonCharList.push_back(NKCODE_ESCAPE);
200
}
201
202
ignoreInput = !findInList(nonCharList, keyCode);
203
}
204
205
return ignoreInput;
206
}
207
#pragma endregion
208
209
#pragma region Keys Status
210
bool IsCapsLockOn() {
211
// TODO: Perform this on UI thread, delayed as currently `KeyDown` don't detect those anyway
212
auto capsLockState = CoreApplication::MainView().CoreWindow().GetKeyState(VirtualKey::CapitalLock);
213
return (capsLockState == CoreVirtualKeyStates::Locked);
214
}
215
bool IsShiftOnHold() {
216
// TODO: Perform this on UI thread, delayed as currently `KeyDown` don't detect those anyway
217
auto shiftState = CoreApplication::MainView().CoreWindow().GetKeyState(VirtualKey::Shift);
218
return (shiftState == CoreVirtualKeyStates::Down);
219
}
220
bool IsCtrlOnHold() {
221
// TODO: Perform this on UI thread, delayed as currently `KeyDown` don't detect those anyway
222
auto ctrlState = CoreApplication::MainView().CoreWindow().GetKeyState(VirtualKey::Control);
223
return (ctrlState == CoreVirtualKeyStates::Down);
224
}
225
#pragma endregion
226
227
#pragma region Misc
228
std::string GetLangRegion() {
229
std::string langRegion = "en_US";
230
wchar_t lcCountry[256];
231
232
if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, lcCountry, 256) != FALSE) {
233
langRegion = ConvertWStringToUTF8(lcCountry);
234
for (size_t i = 0; i < langRegion.size(); i++) {
235
if (langRegion[i] == '-')
236
langRegion[i] = '_';
237
}
238
}
239
return langRegion;
240
}
241
242
bool IsXBox() {
243
auto deviceInfo = winrt::Windows::System::Profile::AnalyticsInfo::VersionInfo();
244
return deviceInfo.DeviceFamily() == L"Windows.Xbox";
245
}
246
247
bool IsMobile() {
248
auto deviceInfo = winrt::Windows::System::Profile::AnalyticsInfo::VersionInfo();
249
return deviceInfo.DeviceFamily() == L"Windows.Mobile";
250
}
251
252
void GetVersionInfo(uint32_t& major, uint32_t& minor, uint32_t& build, uint32_t& revision) {
253
winrt::hstring deviceFamilyVersion = winrt::Windows::System::Profile::AnalyticsInfo::VersionInfo().DeviceFamilyVersion();
254
uint64_t version = std::stoull(std::wstring(deviceFamilyVersion));
255
256
major = static_cast<uint32_t>((version & 0xFFFF000000000000L) >> 48);
257
minor = static_cast<uint32_t>((version & 0x0000FFFF00000000L) >> 32);
258
build = static_cast<uint32_t>((version & 0x00000000FFFF0000L) >> 16);
259
revision = static_cast<uint32_t>(version & 0x000000000000FFFFL);
260
}
261
262
std::string GetSystemName() {
263
std::string osName = "Microsoft Windows 10";
264
265
if (IsXBox()) {
266
osName = "Xbox OS";
267
}
268
else {
269
uint32_t major = 0, minor = 0, build = 0, revision = 0;
270
GetVersionInfo(major, minor, build, revision);
271
272
if (build >= 22000) {
273
osName = "Microsoft Windows 11";
274
}
275
}
276
return osName + " " + GetWindowsSystemArchitecture();
277
}
278
279
std::string GetWindowsBuild() {
280
uint32_t major = 0, minor = 0, build = 0, revision = 0;
281
GetVersionInfo(major, minor, build, revision);
282
283
char buffer[50];
284
sprintf_s(buffer, sizeof(buffer), "%u.%u.%u (rev. %u)", major, minor, build, revision);
285
return std::string(buffer);
286
}
287
#pragma endregion
288
289