CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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