Files
OpenVR-AdvancedSettings-frame/src/tabcontrollers/UtilitiesTabController.cpp
T

440 lines
15 KiB
C++

#include "UtilitiesTabController.h"
#include <QQuickWindow>
#include "../overlaycontroller.h"
#include <Windows.h>
#include <thread>
// application namespace
namespace advsettings {
const char* steamDesktopOverlaykey = "valve.steam.desktop";
void UtilitiesTabController::initStage1() {
auto settings = OverlayController::appSettings();
settings->beginGroup("utilitiesSettings");
auto qAlarmEnabled = settings->value("alarmEnabled", m_alarmEnabled);
auto qAlarmIsModal = settings->value("alarmIsModal", m_alarmIsModal);
auto qAlarmHour = settings->value("alarmHour", 0);
auto qAlarmMinute = settings->value("alarmMinute", 0);
settings->endGroup();
m_alarmEnabled = qAlarmEnabled.toBool();
m_alarmIsModal = qAlarmIsModal.toBool();
m_alarmTime = QTime(qAlarmHour.toInt(), qAlarmMinute.toInt());
vr::VROverlayHandle_t pOverlayHandle;
auto error = vr::VROverlay()->FindOverlay(steamDesktopOverlaykey, &pOverlayHandle);
if (error != vr::VROverlayError_None) {
m_steamDesktopOverlayAvailable = false;
LOG(INFO) << "Could not find overlay \"" << steamDesktopOverlaykey << "\": " << vr::VROverlay()->GetOverlayErrorNameFromEnum(error);
} else {
m_steamDesktopOverlayAvailable = true;
float width;
error = vr::VROverlay()->GetOverlayWidthInMeters(pOverlayHandle, &width);
if (error != vr::VROverlayError_None) {
LOG(ERROR) << "Could not read overlay width of \"" << steamDesktopOverlaykey << "\": " << vr::VROverlay()->GetOverlayErrorNameFromEnum(error);
} else {
m_steamDesktopOverlayWidth = width;
}
}
}
void UtilitiesTabController::initStage2(OverlayController * parent, QQuickWindow * widget) {
this->parent = parent;
this->widget = widget;
}
void fillKiStruct(INPUT& ip, WORD scanCode, bool keyup) {
ip.type = INPUT_KEYBOARD;
ip.ki.wVk = scanCode;
if (keyup) {
ip.ki.dwFlags = KEYEVENTF_KEYUP;
} else {
ip.ki.dwFlags = 0;
}
ip.ki.wScan = 0;
ip.ki.dwExtraInfo = 0;
ip.ki.time = 0;
};
void UtilitiesTabController::sendKeyboardInput(QString input) {
int len = input.length();
if (len > 0) {
LPINPUT ips = new INPUT[len * 5 + 3];
unsigned ii = 0;
bool shiftPressed = false;
bool ctrlPressed = false;
bool altPressed = false;
for (int i = 0; i < len; i++) {
short tmp = VkKeyScan(input.at(i).toLatin1());
WORD c = tmp & 0xFF;
short shiftState = tmp >> 8;
bool isShift = shiftState & 1;
bool isCtrl = shiftState & 2;
bool isAlt = shiftState & 4;
if (isShift && !shiftPressed) {
fillKiStruct(ips[ii++], VK_SHIFT, false);
shiftPressed = true;
} else if (!isShift && shiftPressed) {
fillKiStruct(ips[ii++], VK_SHIFT, true);
shiftPressed = false;
}
if (isCtrl && !ctrlPressed) {
fillKiStruct(ips[ii++], VK_CONTROL, false);
ctrlPressed = true;
} else if (!isCtrl && ctrlPressed) {
fillKiStruct(ips[ii++], VK_CONTROL, true);
ctrlPressed = false;
}
if (isAlt && !altPressed) {
fillKiStruct(ips[ii++], VK_MENU, false);
altPressed = true;
} else if (!isAlt && altPressed) {
fillKiStruct(ips[ii++], VK_MENU, true);
altPressed = false;
}
fillKiStruct(ips[ii++], c, false);
fillKiStruct(ips[ii++], c, true);
}
if (shiftPressed) {
fillKiStruct(ips[ii++], VK_SHIFT, true);
shiftPressed = false;
}
if (ctrlPressed) {
fillKiStruct(ips[ii++], VK_CONTROL, true);
ctrlPressed = false;
}
if (altPressed) {
fillKiStruct(ips[ii++], VK_MENU, true);
altPressed = false;
}
if (!SendInput(ii, ips, sizeof(INPUT))) {
char *err;
auto errCode = GetLastError();
if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
(LPTSTR)&err,
0,
NULL)){
LOG(ERROR) << "Error calling SendInput(): Could not get error message (" << errCode << ")";
} else {
LOG(ERROR) << "Error calling SendInput(): " << err;
}
}
delete ips;
}
}
void UtilitiesTabController::sendKeyboardEnter() {
LPINPUT ips = new INPUT[2];
fillKiStruct(ips[0], VK_RETURN, false);
fillKiStruct(ips[1], VK_RETURN, true);
if (!SendInput(2, ips, sizeof(INPUT))) {
char *err;
auto errCode = GetLastError();
if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
(LPTSTR)&err,
0,
NULL)) {
LOG(ERROR) << "Error calling SendInput(): Could not get error message (" << errCode << ")";
} else {
LOG(ERROR) << "Error calling SendInput(): " << err;
}
}
delete ips;
}
void UtilitiesTabController::sendKeyboardBackspace(int count) {
if (count > 0) {
LPINPUT ips = new INPUT[count * 2];
for (int i = 0; i < count; i++) {
fillKiStruct(ips[2 * i], VK_BACK, false);
fillKiStruct(ips[2 * i + 1], VK_BACK, true);
}
if (!SendInput(2 * count, ips, sizeof(INPUT))) {
char *err;
auto errCode = GetLastError();
if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
(LPTSTR)&err,
0,
NULL)) {
LOG(ERROR) << "Error calling SendInput(): Could not get error message (" << errCode << ")";
} else {
LOG(ERROR) << "Error calling SendInput(): " << err;
}
}
delete ips;
}
}
bool UtilitiesTabController::alarmEnabled() const {
return m_alarmEnabled;
}
bool UtilitiesTabController::alarmIsModal() const {
return m_alarmIsModal;
}
int UtilitiesTabController::alarmTimeHour() const {
return m_alarmTime.hour();
}
int UtilitiesTabController::alarmTimeMinute() const {
return m_alarmTime.minute();
}
void UtilitiesTabController::setAlarmEnabled(bool enabled, bool notify) {
if (m_alarmEnabled != enabled) {
m_alarmEnabled = enabled;
auto settings = OverlayController::appSettings();
settings->beginGroup("utilitiesSettings");
settings->setValue("alarmEnabled", m_alarmEnabled);
settings->endGroup();
settings->sync();
m_alarmLastCheckTime = QTime();
if (notify) {
emit alarmEnabledChanged(m_alarmEnabled);
}
}
}
void UtilitiesTabController::setAlarmIsModal(bool modal, bool notify) {
if (m_alarmIsModal != modal) {
m_alarmIsModal = modal;
auto settings = OverlayController::appSettings();
settings->beginGroup("utilitiesSettings");
settings->setValue("alarmIsModal", m_alarmIsModal);
settings->endGroup();
settings->sync();
if (notify) {
emit alarmIsModalChanged(m_alarmIsModal);
}
}
}
void UtilitiesTabController::setAlarmTimeHour(int hour, bool notify) {
if (m_alarmTime.hour() != hour) {
if (m_alarmTime.isValid()) {
m_alarmTime = QTime(hour, m_alarmTime.minute());
} else {
m_alarmTime = QTime(hour, 0);
}
auto settings = OverlayController::appSettings();
settings->beginGroup("utilitiesSettings");
settings->setValue("alarmHour", m_alarmTime.hour());
settings->setValue("alarmMinute", m_alarmTime.minute());
settings->endGroup();
settings->sync();
m_alarmLastCheckTime = QTime();
if (notify) {
emit alarmTimeHourChanged(hour);
}
}
}
void UtilitiesTabController::setAlarmTimeMinute(int min, bool notify) {
if (m_alarmTime.minute() != min) {
if (m_alarmTime.isValid()) {
m_alarmTime = QTime(m_alarmTime.hour(), min);
} else {
m_alarmTime = QTime(0, min);
}
auto settings = OverlayController::appSettings();
settings->beginGroup("utilitiesSettings");
settings->setValue("alarmHour", m_alarmTime.hour());
settings->setValue("alarmMinute", m_alarmTime.minute());
settings->endGroup();
settings->sync();
m_alarmLastCheckTime = QTime();
if (notify) {
emit alarmTimeMinuteChanged(min);
}
}
}
void UtilitiesTabController::setAlarmTimeToCurrentTime() {
auto now = QTime::currentTime();
setAlarmTimeHour(now.hour());
setAlarmTimeMinute(now.minute());
}
void UtilitiesTabController::modAlarmTimeHour(int value, bool notify) {
auto h = m_alarmTime.hour();
m_alarmTime = m_alarmTime.addSecs(value * 60 * 60);
auto settings = OverlayController::appSettings();
settings->beginGroup("utilitiesSettings");
settings->setValue("alarmHour", m_alarmTime.hour());
settings->setValue("alarmMinute", m_alarmTime.minute());
settings->endGroup();
settings->sync();
if (h != m_alarmTime.hour()) {
m_alarmLastCheckTime = QTime();
if (notify) {
emit alarmTimeHourChanged(m_alarmTime.hour());
}
}
}
void UtilitiesTabController::modAlarmTimeMinute(int value, bool notify) {
auto h = m_alarmTime.hour();
auto m = m_alarmTime.minute();
m_alarmTime = m_alarmTime.addSecs(value * 60);
auto settings = OverlayController::appSettings();
settings->beginGroup("utilitiesSettings");
settings->setValue("alarmHour", m_alarmTime.hour());
settings->setValue("alarmMinute", m_alarmTime.minute());
settings->endGroup();
settings->sync();
if (m != m_alarmTime.minute() || h != m_alarmTime.hour()) {
m_alarmLastCheckTime = QTime();
if (notify) {
if (h != m_alarmTime.hour()) {
emit alarmTimeHourChanged(m_alarmTime.hour());
}
if (m != m_alarmTime.minute()) {
emit alarmTimeMinuteChanged(m_alarmTime.minute());
}
}
}
}
void UtilitiesTabController::eventLoopTick() {
if (settingsUpdateCounter >= 10) {
vr::VROverlayHandle_t pOverlayHandle;
auto error = vr::VROverlay()->FindOverlay(steamDesktopOverlaykey, &pOverlayHandle);
if (error == vr::VROverlayError_None) {
if (!m_steamDesktopOverlayAvailable) {
m_steamDesktopOverlayAvailable = true;
emit steamDesktopOverlayAvailableChanged(m_steamDesktopOverlayAvailable);
}
float width;
error = vr::VROverlay()->GetOverlayWidthInMeters(pOverlayHandle, &width);
if (error != vr::VROverlayError_None) {
LOG(ERROR) << "Could not read overlay width of \"" << steamDesktopOverlaykey << "\": " << vr::VROverlay()->GetOverlayErrorNameFromEnum(error);
} else {
setSteamDesktopOverlayWidth(width, true, false);
}
} else {
if (m_steamDesktopOverlayAvailable) {
m_steamDesktopOverlayAvailable = false;
emit steamDesktopOverlayAvailableChanged(m_steamDesktopOverlayAvailable);
}
}
if (m_alarmEnabled && m_alarmTime.isValid()) {
auto now = QTime::currentTime();
if (m_alarmLastCheckTime.isValid() && m_alarmLastCheckTime <= m_alarmTime && m_alarmTime <= now) {
setAlarmEnabled(false);
char alarmMessageBuffer[1024];
std::snprintf(alarmMessageBuffer, 1024, "The alarm at %02i:%02i went off.", alarmTimeHour(), alarmTimeMinute());
if (m_alarmIsModal) {
std::thread messageThread([](UtilitiesTabController* parent, std::string message) {
auto res = vr::VROverlay()->ShowMessageOverlay(message.c_str(), "Alarm Clock", "Ok", "+15 min");
if (res == vr::VRMessageOverlayResponse_ButtonPress_1) {
parent->setAlarmTimeToCurrentTime();
parent->modAlarmTimeMinute(15);
parent->setAlarmEnabled(true);
} else if (res >= vr::VRMessageOverlayResponse_CouldntFindSystemOverlay) {
static const char* errorMessages[] = { "CouldntFindSystemOverlay", "CouldntFindOrCreateClientOverlay", "ApplicationQuit" };
int errorCode = res - vr::VRMessageOverlayResponse_CouldntFindSystemOverlay;
if (res < 3) {
LOG(ERROR) << "Could not create Alarm Overlay: " << errorMessages[errorCode];
} else {
LOG(ERROR) << "Could not create Alarm Overlay: Unknown Error";
}
}
}, this, std::string(alarmMessageBuffer));
messageThread.detach();
} else {
vr::VRNotificationId notificationId;
vr::EVRInitError eError;
vr::IVRNotifications* vrnotification = (vr::IVRNotifications*)vr::VR_GetGenericInterface(vr::IVRNotifications_Version, &eError);
if (eError != vr::VRInitError_None) {
LOG(ERROR) << "Error while getting IVRNotifications interface" << vr::VR_GetVRInitErrorAsEnglishDescription(eError);
vrnotification = nullptr;
} else {
vr::NotificationBitmap_t* messageIconPtr = nullptr;
/*
// Can i even create this object on the stack, who takes ownership?
vr::NotificationBitmap_t messageIcon;
// First get image width and height
vr::VROverlay()->GetOverlayImageData(parent->overlayThumbnailHandle(), nullptr, 0, (uint32_t*)&messageIcon.m_nWidth, (uint32_t*)&messageIcon.m_nHeight);
messageIcon.m_nBytesPerPixel = 4;
unsigned bufferSize = messageIcon.m_nWidth*messageIcon.m_nHeight*messageIcon.m_nBytesPerPixel;
// Can I delete this buffer after this section? Who takes ownership?
std::unique_ptr<char> imageBuffer;
imageBuffer.reset(new char[bufferSize]);
messageIcon.m_pImageData = imageBuffer.get();
// Get image data
auto iconError = vr::VROverlay()->GetOverlayImageData(parent->overlayThumbnailHandle(), messageIcon.m_pImageData, bufferSize, (uint32_t*)&messageIcon.m_nWidth, (uint32_t*)&messageIcon.m_nHeight);
if (iconError != vr::VROverlayError_None) {
LOG(ERROR) << "Error while getting message overlay icon: " << vr::VROverlay()->GetOverlayErrorNameFromEnum(iconError);
} else {
messageIconPtr = &messageIcon;
}
*/
auto nError = vrnotification->CreateNotification(
parent->overlayHandle(), 666, vr::EVRNotificationType_Transient, alarmMessageBuffer, vr::EVRNotificationStyle_Application, messageIconPtr, &notificationId
);
if (nError != vr::VRNotificationError_OK) {
LOG(ERROR) << "Error while creating notification: " << nError;
vrnotification = nullptr;
}
}
}
}
m_alarmLastCheckTime = now;
}
settingsUpdateCounter = 0;
} else {
settingsUpdateCounter++;
}
}
bool UtilitiesTabController::steamDesktopOverlayAvailable() const {
return m_steamDesktopOverlayAvailable;
}
float UtilitiesTabController::steamDesktopOverlayWidth() const {
return m_steamDesktopOverlayWidth;
}
void UtilitiesTabController::setSteamDesktopOverlayWidth(float width, bool notify, bool notifyOpenVr) {
if (std::abs(m_steamDesktopOverlayWidth - width) > 0.01) {
m_steamDesktopOverlayWidth = width;
if (notifyOpenVr) {
vr::VROverlayHandle_t pOverlayHandle;
auto error = vr::VROverlay()->FindOverlay(steamDesktopOverlaykey, &pOverlayHandle);
if (error != vr::VROverlayError_None) {
LOG(ERROR) << "Could not find overlay \"" << steamDesktopOverlaykey << "\": " << vr::VROverlay()->GetOverlayErrorNameFromEnum(error);
} else {
error = vr::VROverlay()->SetOverlayWidthInMeters(pOverlayHandle, m_steamDesktopOverlayWidth);
if (error != vr::VROverlayError_None) {
LOG(ERROR) << "Could not modify overlay width of \"" << steamDesktopOverlaykey << "\": " << vr::VROverlay()->GetOverlayErrorNameFromEnum(error);
}
}
}
if (notify) {
emit steamDesktopOverlayWidthChanged(m_steamDesktopOverlayWidth);
}
}
}
} // namespace advconfig