CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/UWP/UWPHelpers/InputHelpers.cpp
Views: 1401
// Copyright (c) 2023- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include <list>1819#include "InputHelpers.h"20#include "UWPUtil.h"21#include "NKCodeFromWindowsSystem.h"22#include "Common/Log.h"23#include "Common/OSVersion.h"2425#include <ppl.h>26#include <ppltasks.h>2728using namespace Windows::System;29using namespace Windows::Foundation;30using namespace Windows::UI::Core;31using namespace Windows::UI::ViewManagement;32using namespace Windows::ApplicationModel::Core;33using namespace Windows::Data::Xml::Dom;34using namespace Windows::UI::Notifications;35using namespace Windows::UI::ViewManagement;3637#pragma region Extenstions38template<typename T>39bool findInList(std::list<T>& inputList, T& str) {40return (std::find(inputList.begin(), inputList.end(), str) != inputList.end());41};42#pragma endregion4344#pragma region Input Devices45bool isKeyboardAvailable() {46Windows::Devices::Input::KeyboardCapabilities^ keyboardCapabilities = ref new Windows::Devices::Input::KeyboardCapabilities();47bool hasKeyboard = keyboardCapabilities->KeyboardPresent != 0;48return hasKeyboard;49}5051bool isTouchAvailable() {52Windows::Devices::Input::TouchCapabilities^ touchCapabilities = ref new Windows::Devices::Input::TouchCapabilities();53bool hasTouch = touchCapabilities->TouchPresent != 0;54return hasTouch;55}56#pragma endregion5758#pragma region Input Keyboard5960bool dPadInputActive = false;61bool textEditActive = false;62bool inputPaneVisible = false;63Platform::Agile<Windows::UI::ViewManagement::InputPane> inputPane = nullptr;6465void OnShowing(InputPane^ pane, InputPaneVisibilityEventArgs^ args) {66inputPaneVisible = true;67}68void OnHiding(InputPane^ pane, InputPaneVisibilityEventArgs^ args) {69inputPaneVisible = false;70}7172void PrepareInputPane() {73inputPane = InputPane::GetForCurrentView();74inputPane->Showing += ref new Windows::Foundation::TypedEventHandler<InputPane^, InputPaneVisibilityEventArgs^>(&OnShowing);75inputPane->Hiding += ref new Windows::Foundation::TypedEventHandler<InputPane^, InputPaneVisibilityEventArgs^>(&OnHiding);76}7778// Show input pane (OSK)79bool ShowInputPane() {80return !isInputPaneVisible() ? inputPane->TryShow() : true;81}82// Hide input pane (OSK)83bool HideInputPane() {84return isInputPaneVisible() ? inputPane->TryHide() : true;85}8687// Check if input pane (OSK) visible88bool isInputPaneVisible() {89return inputPaneVisible;90}9192// Check if text edit active (got focus)93bool isTextEditActive() {94return textEditActive;95}9697// Set if the current input is DPad98void DPadInputState(bool inputState) {99dPadInputActive = inputState;100}101102// Check if the current input is DPad103bool isDPadActive() {104return dPadInputActive;105}106107void ActivateTextEditInput(bool byFocus) {108// Must be performed from UI thread109Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(110CoreDispatcherPriority::Normal,111ref new Windows::UI::Core::DispatchedHandler([=]()112{113if (byFocus) {114// Why we should delay? (Mostly happen on XBox)115// once the popup appear, UI is reporting 3 focus events for text edit (got, lost, got)116// it might be caused by the input pane it self but anyway..117// because this has to on UI thread and async, we will end with input pane hidden118// the small delay will ensure that last recieved event is (got focus)119std::this_thread::sleep_for(std::chrono::milliseconds(100));120}121122if (!isInputPaneVisible() && (isDPadActive() || !IsXBox())) {123if (ShowInputPane()) {124DEBUG_LOG(Log::Common, "Input pane: TryShow accepted");125}126else {127DEBUG_LOG(Log::Common, "Input pane: (TryShow is not accepted or not supported)");128}129}130DEBUG_LOG(Log::Common, "Text edit active");131textEditActive = true;132}));133}134135void DeactivateTextEditInput(bool byFocus) {136// Must be performed from UI thread137Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(138CoreDispatcherPriority::Normal,139ref new Windows::UI::Core::DispatchedHandler([=]()140{141if (isInputPaneVisible()) {142if (HideInputPane()) {143DEBUG_LOG(Log::Common, "Input pane: TryHide accepted");144}145else {146DEBUG_LOG(Log::Common, "Input pane: TryHide is not accepted, or not supported");147}148}149if (isTextEditActive()) {150DEBUG_LOG(Log::Common, "Text edit inactive");151textEditActive = false;152}153}));154}155156bool IgnoreInput(int keyCode) {157// When text edit active and char is passed this function return 'true'158// it will help to prevent KeyDown from sending the same code again159bool ignoreInput = false;160// TODO: Add ` && !IsCtrlOnHold()` once it's ready and implemented161if (isTextEditActive()) {162// To avoid bothering KeyDown to check this case always163// we don't get here unless text edit is active164std::list<int> nonCharList = {165NKCODE_CTRL_LEFT,166NKCODE_CTRL_RIGHT,167NKCODE_MOVE_HOME,168NKCODE_PAGE_UP,169NKCODE_MOVE_END,170NKCODE_PAGE_DOWN,171NKCODE_FORWARD_DEL,172NKCODE_DEL,173NKCODE_ENTER,174NKCODE_NUMPAD_ENTER,175NKCODE_EXT_MOUSEBUTTON_1,176NKCODE_EXT_MOUSEBUTTON_2,177NKCODE_EXT_MOUSEBUTTON_3,178NKCODE_EXT_MOUSEBUTTON_4,179NKCODE_EXT_MOUSEBUTTON_5,180};181if (!isInputPaneVisible()) {182// Keyboard active but no on-screen keyboard183// allow arrow keys for navigation184nonCharList.push_back(NKCODE_DPAD_UP);185nonCharList.push_back(NKCODE_DPAD_DOWN);186nonCharList.push_back(NKCODE_DPAD_LEFT);187nonCharList.push_back(NKCODE_DPAD_RIGHT);188nonCharList.push_back(NKCODE_BACK);189nonCharList.push_back(NKCODE_ESCAPE);190}191192ignoreInput = !findInList(nonCharList, keyCode);193}194195return ignoreInput;196}197#pragma endregion198199#pragma region Keys Status200bool IsCapsLockOn() {201// TODO: Perform this on UI thread, delayed as currently `KeyDown` don't detect those anyway202auto capsLockState = CoreApplication::MainView->CoreWindow->GetKeyState(VirtualKey::CapitalLock);203return (capsLockState == CoreVirtualKeyStates::Locked);204}205bool IsShiftOnHold() {206// TODO: Perform this on UI thread, delayed as currently `KeyDown` don't detect those anyway207auto shiftState = CoreApplication::MainView->CoreWindow->GetKeyState(VirtualKey::Shift);208return (shiftState == CoreVirtualKeyStates::Down);209}210bool IsCtrlOnHold() {211// TODO: Perform this on UI thread, delayed as currently `KeyDown` don't detect those anyway212auto ctrlState = CoreApplication::MainView->CoreWindow->GetKeyState(VirtualKey::Control);213return (ctrlState == CoreVirtualKeyStates::Down);214}215#pragma endregion216217#pragma region Misc218std::string GetLangRegion() {219std::string langRegion = "en_US";220wchar_t lcCountry[256];221222if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, lcCountry, 256) != FALSE) {223langRegion = ConvertWStringToUTF8(lcCountry);224for (size_t i = 0; i < langRegion.size(); i++) {225if (langRegion[i] == '-')226langRegion[i] = '_';227}228}229return langRegion;230}231232bool IsXBox() {233auto deviceInfo = Windows::System::Profile::AnalyticsInfo::VersionInfo;234return deviceInfo->DeviceFamily == "Windows.Xbox";235}236237bool IsMobile() {238auto deviceInfo = Windows::System::Profile::AnalyticsInfo::VersionInfo;239return deviceInfo->DeviceFamily == "Windows.Mobile";240}241242void GetVersionInfo(uint32_t& major, uint32_t& minor, uint32_t& build, uint32_t& revision) {243Platform::String^ deviceFamilyVersion = Windows::System::Profile::AnalyticsInfo::VersionInfo->DeviceFamilyVersion;244uint64_t version = std::stoull(deviceFamilyVersion->Data());245246major = static_cast<uint32_t>((version & 0xFFFF000000000000L) >> 48);247minor = static_cast<uint32_t>((version & 0x0000FFFF00000000L) >> 32);248build = static_cast<uint32_t>((version & 0x00000000FFFF0000L) >> 16);249revision = static_cast<uint32_t>(version & 0x000000000000FFFFL);250}251252std::string GetSystemName() {253std::string osName = "Microsoft Windows 10";254255if (IsXBox()) {256osName = "Xbox OS";257}258else {259uint32_t major = 0, minor = 0, build = 0, revision = 0;260GetVersionInfo(major, minor, build, revision);261262if (build >= 22000) {263osName = "Microsoft Windows 11";264}265}266return osName + " " + GetWindowsSystemArchitecture();267}268269std::string GetWindowsBuild() {270uint32_t major = 0, minor = 0, build = 0, revision = 0;271GetVersionInfo(major, minor, build, revision);272273char buffer[50];274sprintf_s(buffer, sizeof(buffer), "%u.%u.%u (rev. %u)", major, minor, build, revision);275return std::string(buffer);276}277#pragma endregion278279280