#include "pch.h"
#include <list>
#include <thread>
#include "InputHelpers.h"
#include "UWPUtil.h"
#include "NKCodeFromWindowsSystem.h"
#include "Common/Log.h"
#include "Common/OSVersion.h"
#include <ppl.h>
#include <ppltasks.h>
using namespace winrt;
using namespace winrt::Windows::System;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::ViewManagement;
using namespace winrt::Windows::ApplicationModel::Core;
using namespace winrt::Windows::Data::Xml::Dom;
using namespace winrt::Windows::UI::Notifications;
#pragma region Extenstions
template<typename T>
bool findInList(std::list<T>& inputList, T& str) {
return (std::find(inputList.begin(), inputList.end(), str) != inputList.end());
};
#pragma endregion
#pragma region Input Devices
bool isKeyboardAvailable() {
winrt::Windows::Devices::Input::KeyboardCapabilities keyboardCapabilities;
bool hasKeyboard = keyboardCapabilities.KeyboardPresent() != 0;
return hasKeyboard;
}
bool isTouchAvailable() {
winrt::Windows::Devices::Input::TouchCapabilities touchCapabilities;
bool hasTouch = touchCapabilities.TouchPresent() != 0;
return hasTouch;
}
#pragma endregion
#pragma region Input Keyboard
bool dPadInputActive = false;
bool textEditActive = false;
bool inputPaneVisible = false;
winrt::agile_ref<InputPane> inputPane = nullptr;
void OnShowing(const InputPane& pane, const InputPaneVisibilityEventArgs& args) {
inputPaneVisible = true;
}
void OnHiding(const InputPane& pane, const InputPaneVisibilityEventArgs& args) {
inputPaneVisible = false;
}
void PrepareInputPane() {
auto pane = InputPane::GetForCurrentView();
pane.Showing(OnShowing);
pane.Hiding(OnHiding);
inputPane = pane;
}
bool ShowInputPane() {
if (inputPane) {
return !isInputPaneVisible() ? inputPane.get().TryShow() : true;
}
return false;
}
bool HideInputPane() {
if (inputPane) {
return isInputPaneVisible() ? inputPane.get().TryHide() : true;
}
return false;
}
bool isInputPaneVisible() {
return inputPaneVisible;
}
bool isTextEditActive() {
return textEditActive;
}
void DPadInputState(bool inputState) {
dPadInputActive = inputState;
}
bool isDPadActive() {
return dPadInputActive;
}
void ActivateTextEditInput(bool byFocus) {
CoreApplication::MainView().CoreWindow().Dispatcher().RunAsync(
CoreDispatcherPriority::Normal,
[byFocus]()
{
if (byFocus) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
if (!isInputPaneVisible() && (isDPadActive() || !IsXBox())) {
if (ShowInputPane()) {
DEBUG_LOG(Log::Common, "Input pane: TryShow accepted");
}
else {
DEBUG_LOG(Log::Common, "Input pane: (TryShow is not accepted or not supported)");
}
}
DEBUG_LOG(Log::Common, "Text edit active");
textEditActive = true;
});
}
void DeactivateTextEditInput(bool byFocus) {
CoreApplication::MainView().CoreWindow().Dispatcher().RunAsync(
CoreDispatcherPriority::Normal,
[byFocus]()
{
if (isInputPaneVisible()) {
if (HideInputPane()) {
DEBUG_LOG(Log::Common, "Input pane: TryHide accepted");
}
else {
DEBUG_LOG(Log::Common, "Input pane: TryHide is not accepted, or not supported");
}
}
if (isTextEditActive()) {
DEBUG_LOG(Log::Common, "Text edit inactive");
textEditActive = false;
}
});
}
bool IgnoreInput(int keyCode) {
bool ignoreInput = false;
if (isTextEditActive()) {
std::list<int> nonCharList = {
NKCODE_CTRL_LEFT,
NKCODE_CTRL_RIGHT,
NKCODE_MOVE_HOME,
NKCODE_PAGE_UP,
NKCODE_MOVE_END,
NKCODE_PAGE_DOWN,
NKCODE_FORWARD_DEL,
NKCODE_DEL,
NKCODE_ENTER,
NKCODE_NUMPAD_ENTER,
NKCODE_EXT_MOUSEBUTTON_1,
NKCODE_EXT_MOUSEBUTTON_2,
NKCODE_EXT_MOUSEBUTTON_3,
NKCODE_EXT_MOUSEBUTTON_4,
NKCODE_EXT_MOUSEBUTTON_5,
};
if (!isInputPaneVisible()) {
nonCharList.push_back(NKCODE_DPAD_UP);
nonCharList.push_back(NKCODE_DPAD_DOWN);
nonCharList.push_back(NKCODE_DPAD_LEFT);
nonCharList.push_back(NKCODE_DPAD_RIGHT);
nonCharList.push_back(NKCODE_BACK);
nonCharList.push_back(NKCODE_ESCAPE);
}
ignoreInput = !findInList(nonCharList, keyCode);
}
return ignoreInput;
}
#pragma endregion
#pragma region Keys Status
bool IsCapsLockOn() {
auto capsLockState = CoreApplication::MainView().CoreWindow().GetKeyState(VirtualKey::CapitalLock);
return (capsLockState == CoreVirtualKeyStates::Locked);
}
bool IsShiftOnHold() {
auto shiftState = CoreApplication::MainView().CoreWindow().GetKeyState(VirtualKey::Shift);
return (shiftState == CoreVirtualKeyStates::Down);
}
bool IsCtrlOnHold() {
auto ctrlState = CoreApplication::MainView().CoreWindow().GetKeyState(VirtualKey::Control);
return (ctrlState == CoreVirtualKeyStates::Down);
}
#pragma endregion
#pragma region Misc
std::string GetLangRegion() {
std::string langRegion = "en_US";
wchar_t lcCountry[256];
if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, lcCountry, 256) != FALSE) {
langRegion = ConvertWStringToUTF8(lcCountry);
for (size_t i = 0; i < langRegion.size(); i++) {
if (langRegion[i] == '-')
langRegion[i] = '_';
}
}
return langRegion;
}
bool IsXBox() {
auto deviceInfo = winrt::Windows::System::Profile::AnalyticsInfo::VersionInfo();
return deviceInfo.DeviceFamily() == L"Windows.Xbox";
}
bool IsMobile() {
auto deviceInfo = winrt::Windows::System::Profile::AnalyticsInfo::VersionInfo();
return deviceInfo.DeviceFamily() == L"Windows.Mobile";
}
void GetVersionInfo(uint32_t& major, uint32_t& minor, uint32_t& build, uint32_t& revision) {
winrt::hstring deviceFamilyVersion = winrt::Windows::System::Profile::AnalyticsInfo::VersionInfo().DeviceFamilyVersion();
uint64_t version = std::stoull(std::wstring(deviceFamilyVersion));
major = static_cast<uint32_t>((version & 0xFFFF000000000000L) >> 48);
minor = static_cast<uint32_t>((version & 0x0000FFFF00000000L) >> 32);
build = static_cast<uint32_t>((version & 0x00000000FFFF0000L) >> 16);
revision = static_cast<uint32_t>(version & 0x000000000000FFFFL);
}
std::string GetSystemName() {
std::string osName = "Microsoft Windows 10";
if (IsXBox()) {
osName = "Xbox OS";
}
else {
uint32_t major = 0, minor = 0, build = 0, revision = 0;
GetVersionInfo(major, minor, build, revision);
if (build >= 22000) {
osName = "Microsoft Windows 11";
}
}
return osName + " " + GetWindowsSystemArchitecture();
}
std::string GetWindowsBuild() {
uint32_t major = 0, minor = 0, build = 0, revision = 0;
GetVersionInfo(major, minor, build, revision);
char buffer[50];
sprintf_s(buffer, sizeof(buffer), "%u.%u.%u (rev. %u)", major, minor, build, revision);
return std::string(buffer);
}
#pragma endregion