From: LoRd_MuldeR Date: Mon, 8 Dec 2014 21:03:36 +0000 (+0100) Subject: Moved JobObject as well as the remaining GUI functions into the MUtilities library. X-Git-Tag: v1.02~36 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=8b3e28a13161c61ea2b99e416df02424224d8a7b;p=mutilities%2FMUtilities.git Moved JobObject as well as the remaining GUI functions into the MUtilities library. --- diff --git a/MUtilities_VS2013.vcxproj b/MUtilities_VS2013.vcxproj index 16a7da4..a1f9d34 100644 --- a/MUtilities_VS2013.vcxproj +++ b/MUtilities_VS2013.vcxproj @@ -23,6 +23,8 @@ + + @@ -37,6 +39,7 @@ + diff --git a/MUtilities_VS2013.vcxproj.filters b/MUtilities_VS2013.vcxproj.filters index d4318a0..272fdb4 100644 --- a/MUtilities_VS2013.vcxproj.filters +++ b/MUtilities_VS2013.vcxproj.filters @@ -72,6 +72,12 @@ Source Files + + Source Files + + + Source Files + @@ -122,6 +128,9 @@ Public Headers + + Public Headers + diff --git a/include/MUtils/GUI.h b/include/MUtils/GUI.h index f11ef60..9140e02 100644 --- a/include/MUtils/GUI.h +++ b/include/MUtils/GUI.h @@ -24,6 +24,9 @@ //MUtils #include +//Qt +#include + //Forward Declaration class QIcon; class QWidget; @@ -41,11 +44,45 @@ namespace MUtils USER_EVENT_ENDSESSION = USER_EVENT + 667 } user_events_t; + + typedef enum + { + SYSCOLOR_TEXT = 1, + SYSCOLOR_BACKGROUND = 2, + SYSCOLOR_CAPTION = 3 + } + system_color_t; //Broadcast message MUTILS_API bool broadcast(int eventType, const bool &onlyToVisible); - MUTILS_API bool set_window_icon(QWidget *window, const QIcon &icon, const bool bIsBigIcon); + //Window icon + MUTILS_API bool set_window_icon(QWidget *const window, const QIcon &icon, const bool bIsBigIcon); + + //Theme support + MUTILS_API bool themes_enabled(void); + + //System menu + MUTILS_API bool sysmenu_append(const QWidget *const win, const unsigned int identifier, const QString &text); + MUTILS_API bool sysmenu_update(const QWidget *const win, const unsigned int identifier, const QString &text); + MUTILS_API bool sysmenu_check_msg(void *const message, const unsigned int &identifier); + + //Close button + MUTILS_API bool enable_close_button(const QWidget *const win, const bool &bEnable); + + //Bring to front + MUTILS_API bool bring_to_front(const QWidget *const window); + MUTILS_API bool bring_to_front(const unsigned long pid); + + //Sheet of glass + MUTILS_API bool sheet_of_glass(QWidget *const window); + MUTILS_API bool sheet_of_glass_update(QWidget *const window); + + //System colors + MUTILS_API QColor system_color(const int &color_id); + + //Blink window + MUTILS_API void blink_window(QWidget *const poWindow, const unsigned int &count = 10, const unsigned int &delay = 150); //Force quit application MUTILS_API void force_quit(void); diff --git a/include/MUtils/JobObject.h b/include/MUtils/JobObject.h new file mode 100644 index 0000000..62fb4be --- /dev/null +++ b/include/MUtils/JobObject.h @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////// +// MuldeR's Utilities for Qt +// Copyright (C) 2004-2014 LoRd_MuldeR +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +// http://www.gnu.org/licenses/lgpl-2.1.txt +////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +class QProcess; + +namespace MUtils +{ + class MUTILS_API JobObject_Private; + + class MUTILS_API JobObject + { + public: + JobObject(void); + ~JobObject(void); + + bool addProcessToJob(const QProcess *proc); + bool terminateJob(unsigned int exitCode); + + private: + QScopedPointer p; + }; +} diff --git a/include/MUtils/OSSupport.h b/include/MUtils/OSSupport.h index b21d3c1..7db9988 100644 --- a/include/MUtils/OSSupport.h +++ b/include/MUtils/OSSupport.h @@ -156,6 +156,8 @@ namespace MUtils MUTILS_API bool setup_timer_resolution(const quint32 &interval = 1); MUTILS_API bool reset_timer_resolution(const quint32 &interval = 1); + MUTILS_API bool check_key_state_esc(void); + //Check if debugger is present MUTILS_API void check_debugger(void); diff --git a/src/GUI.cpp b/src/GUI.cpp index 9bbf587..39863d4 100644 --- a/src/GUI.cpp +++ b/src/GUI.cpp @@ -19,7 +19,9 @@ // http://www.gnu.org/licenses/lgpl-2.1.txt ////////////////////////////////////////////////////////////////////////////////// +//MUtils #include +#include //Internal #include "Utils_Win32.h" @@ -28,6 +30,7 @@ #include #include #include +#include /////////////////////////////////////////////////////////////////////////////// // BROADCAST @@ -101,7 +104,7 @@ namespace MUtils } } -bool MUtils::GUI::set_window_icon(QWidget *window, const QIcon &icon, const bool bIsBigIcon) +bool MUtils::GUI::set_window_icon(QWidget *const window, const QIcon &icon, const bool bIsBigIcon) { if((!icon.isNull()) && window->winId()) { @@ -118,6 +121,58 @@ bool MUtils::GUI::set_window_icon(QWidget *window, const QIcon &icon, const bool } /////////////////////////////////////////////////////////////////////////////// +// BLINK WINDOW +/////////////////////////////////////////////////////////////////////////////// + +static QMutex g_blinkMutex; + +void MUtils::GUI::blink_window(QWidget *const poWindow, const unsigned int &count, const unsigned int &delay) +{ + const double maxOpac = 1.0; + const double minOpac = 0.3; + const double delOpac = 0.1; + + if(!g_blinkMutex.tryLock()) + { + qWarning("Blinking is already in progress, skipping!"); + return; + } + + try + { + const int steps = static_cast(ceil(maxOpac - minOpac) / delOpac); + const int sleep = static_cast(floor(static_cast(delay) / static_cast(steps))); + const double opacity = poWindow->windowOpacity(); + + for(unsigned int i = 0; i < count; i++) + { + for(double x = maxOpac; x >= minOpac; x -= delOpac) + { + poWindow->setWindowOpacity(x); + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + MUtils::OS::sleep_ms(sleep); + } + + for(double x = minOpac; x <= maxOpac; x += delOpac) + { + poWindow->setWindowOpacity(x); + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + MUtils::OS::sleep_ms(sleep); + } + } + + poWindow->setWindowOpacity(opacity); + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + } + catch(...) + { + qWarning("Exception error while blinking!"); + } + + g_blinkMutex.unlock(); +} + +/////////////////////////////////////////////////////////////////////////////// // FORCE QUIT /////////////////////////////////////////////////////////////////////////////// diff --git a/src/GUI_Win32.cpp b/src/GUI_Win32.cpp new file mode 100644 index 0000000..66bf78b --- /dev/null +++ b/src/GUI_Win32.cpp @@ -0,0 +1,363 @@ +/////////////////////////////////////////////////////////////////////////////// +// MuldeR's Utilities for Qt +// Copyright (C) 2004-2014 LoRd_MuldeR +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +// http://www.gnu.org/licenses/lgpl-2.1.txt +////////////////////////////////////////////////////////////////////////////////// + +//Win32 API +#define WIN32_LEAN_AND_MEAN 1 +#include + +//MUtils +#include +#include + +//Internal +#include "Utils_Win32.h" + +//Qt +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// THEME SUPPORT +/////////////////////////////////////////////////////////////////////////////// + +static QReadWriteLock g_themes_lock; +static bool g_themes_initialized = false; +static bool g_themes_enabled = false; + +typedef int (WINAPI *IsAppThemedFunction)(void); + +bool MUtils::GUI::themes_enabled(void) +{ + QReadLocker readLock(&g_themes_lock); + + if(g_themes_initialized) + { + return g_themes_enabled; + } + + readLock.unlock(); + QWriteLocker writeLock(&g_themes_lock); + + if(g_themes_initialized) + { + return g_themes_enabled; + } + + const MUtils::OS::Version::os_version_t &osVersion = MUtils::OS::os_version(); + if(osVersion >= MUtils::OS::Version::WINDOWS_WINXP) + { + IsAppThemedFunction IsAppThemedPtr = NULL; + QLibrary uxTheme("UxTheme.dll"); + if(uxTheme.load()) + { + IsAppThemedPtr = (IsAppThemedFunction) uxTheme.resolve("IsAppThemed"); + } + if(IsAppThemedPtr) + { + g_themes_enabled = IsAppThemedPtr(); + if(!g_themes_enabled) + { + qWarning("Theme support is disabled for this process!"); + } + } + } + + g_themes_initialized = true; + return g_themes_enabled; +} + +/////////////////////////////////////////////////////////////////////////////// +// SYSTEM MENU +/////////////////////////////////////////////////////////////////////////////// + +bool MUtils::GUI::sysmenu_append(const QWidget *win, const unsigned int identifier, const QString &text) +{ + bool ok = false; + + if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE)) + { + ok = (AppendMenuW(hMenu, MF_SEPARATOR, 0, 0) == TRUE); + ok = (AppendMenuW(hMenu, MF_STRING, identifier, MUTILS_WCHR(text)) == TRUE); + } + + return ok; +} + +bool MUtils::GUI::sysmenu_update(const QWidget *win, const unsigned int identifier, const QString &text) +{ + bool ok = false; + + if(HMENU hMenu = ::GetSystemMenu(win->winId(), FALSE)) + { + ok = (ModifyMenu(hMenu, identifier, MF_STRING | MF_BYCOMMAND, identifier, MUTILS_WCHR(text)) == TRUE); + } + return ok; +} + +bool MUtils::GUI::sysmenu_check_msg(void *const message, const unsigned int &identifier) +{ + return (((MSG*)message)->message == WM_SYSCOMMAND) && ((((MSG*)message)->wParam & 0xFFF0) == identifier); +} + +/////////////////////////////////////////////////////////////////////////////// +// CLOSE BUTTON +/////////////////////////////////////////////////////////////////////////////// + +bool MUtils::GUI::enable_close_button(const QWidget *win, const bool &bEnable) +{ + bool ok = false; + + if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE)) + { + ok = (EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (bEnable ? MF_ENABLED : MF_GRAYED)) == TRUE); + } + + return ok; +} + +/////////////////////////////////////////////////////////////////////////////// +// BRING WINDOW TO FRONT +/////////////////////////////////////////////////////////////////////////////// + +static BOOL CALLBACK bring_process_to_front_helper(HWND hwnd, LPARAM lParam) +{ + DWORD processId = *reinterpret_cast(lParam); + DWORD windowProcessId = NULL; + GetWindowThreadProcessId(hwnd, &windowProcessId); + if(windowProcessId == processId) + { + SwitchToThisWindow(hwnd, TRUE); + SetForegroundWindow(hwnd); + return FALSE; + } + + return TRUE; +} + +bool MUtils::GUI::bring_to_front(const QWidget *window) +{ + bool ret = false; + + if(window) + { + for(int i = 0; (i < 5) && (!ret); i++) + { + ret = (SetForegroundWindow(window->winId()) != FALSE); + SwitchToThisWindow(window->winId(), TRUE); + } + LockSetForegroundWindow(LSFW_LOCK); + } + + return ret; +} + +bool MUtils::GUI::bring_to_front(const unsigned long pid) +{ + return EnumWindows(bring_process_to_front_helper, reinterpret_cast(&pid)) == TRUE; +} + +/////////////////////////////////////////////////////////////////////////////// +// SHEET OF GLASS EFFECT +/////////////////////////////////////////////////////////////////////////////// + +static QReadWriteLock g_dwmapi_lock; +static QScopedPointer g_dwmapi_library; +static bool g_dwmapi_initialized = false; + +static struct +{ + HRESULT (__stdcall *dwmIsCompositionEnabled)(BOOL *bEnabled); + HRESULT (__stdcall *dwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS* pMarInset); + HRESULT (__stdcall *dwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind); +} +g_dwmapi_pointers = { NULL, NULL, NULL }; + +static void initialize_dwmapi(void) +{ + QReadLocker writeLock(&g_dwmapi_lock); + + //Not initialized yet? + if(g_dwmapi_initialized) + { + return; + } + + //Reset function pointers + g_dwmapi_pointers.dwmIsCompositionEnabled = NULL; + g_dwmapi_pointers.dwmExtendFrameIntoClientArea = NULL; + g_dwmapi_pointers.dwmEnableBlurBehindWindow = NULL; + + //Does OS support DWM? + const MUtils::OS::Version::os_version_t &osVersion = MUtils::OS::os_version(); + if(osVersion >= MUtils::OS::Version::WINDOWS_VISTA) + { + //Load DWMAPI.DLL + g_dwmapi_library.reset(new QLibrary("dwmapi.dll")); + if(g_dwmapi_library->load()) + { + //Initialize function pointers + g_dwmapi_pointers.dwmIsCompositionEnabled = (HRESULT (__stdcall*)(BOOL*)) g_dwmapi_library->resolve("DwmIsCompositionEnabled"); + g_dwmapi_pointers.dwmExtendFrameIntoClientArea = (HRESULT (__stdcall*)(HWND, const MARGINS*)) g_dwmapi_library->resolve("DwmExtendFrameIntoClientArea"); + g_dwmapi_pointers.dwmEnableBlurBehindWindow = (HRESULT (__stdcall*)(HWND, const DWM_BLURBEHIND*)) g_dwmapi_library->resolve("DwmEnableBlurBehindWindow"); + } + else + { + g_dwmapi_library.reset(NULL); + qWarning("Failed to load DWMAPI.DLL on a DWM-enabled system!"); + } + } + + g_dwmapi_initialized = true; +} + +bool MUtils::GUI::sheet_of_glass(QWidget *const window) +{ + QReadLocker readLock(&g_dwmapi_lock); + + //Initialize the DWM API + if(!g_dwmapi_initialized) + { + readLock.unlock(); + initialize_dwmapi(); + readLock.relock(); + } + + //Required functions available? + BOOL bCompositionEnabled = FALSE; + if(g_dwmapi_pointers.dwmIsCompositionEnabled && g_dwmapi_pointers.dwmExtendFrameIntoClientArea && g_dwmapi_pointers.dwmEnableBlurBehindWindow) + { + //Check if composition is currently enabled + if(HRESULT hr = g_dwmapi_pointers.dwmIsCompositionEnabled(&bCompositionEnabled)) + { + qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr); + return false; + } + } + + //All functions available *and* composition enabled? + if(!bCompositionEnabled) + { + return false; + } + + //Enable the "sheet of glass" effect on this window + MARGINS margins = {-1, -1, -1, -1}; + if(HRESULT hr = g_dwmapi_pointers.dwmExtendFrameIntoClientArea(window->winId(), &margins)) + { + qWarning("DwmExtendFrameIntoClientArea function has failed! (error %d)", hr); + return false; + } + + //Create and populate the Blur Behind structure + DWM_BLURBEHIND bb; + memset(&bb, 0, sizeof(DWM_BLURBEHIND)); + bb.fEnable = TRUE; + bb.dwFlags = DWM_BB_ENABLE; + if(HRESULT hr = g_dwmapi_pointers.dwmEnableBlurBehindWindow(window->winId(), &bb)) + { + qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr); + return false; + } + + //Required for Qt + window->setAutoFillBackground(false); + window->setAttribute(Qt::WA_TranslucentBackground); + window->setAttribute(Qt::WA_NoSystemBackground); + + return true; +} + +bool MUtils::GUI::sheet_of_glass_update(QWidget *const window) +{ + QReadLocker readLock(&g_dwmapi_lock); + + //Initialize the DWM API + if(!g_dwmapi_initialized) + { + readLock.unlock(); + initialize_dwmapi(); + readLock.relock(); + } + + //Required functions available? + BOOL bCompositionEnabled = FALSE; + if(g_dwmapi_pointers.dwmIsCompositionEnabled && g_dwmapi_pointers.dwmExtendFrameIntoClientArea && g_dwmapi_pointers.dwmEnableBlurBehindWindow) + { + //Check if composition is currently enabled + if(HRESULT hr = g_dwmapi_pointers.dwmIsCompositionEnabled(&bCompositionEnabled)) + { + qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr); + return false; + } + } + + //All functions available *and* composition enabled? + if(!bCompositionEnabled) + { + return false; + } + + //Create and populate the Blur Behind structure + DWM_BLURBEHIND bb; + memset(&bb, 0, sizeof(DWM_BLURBEHIND)); + bb.fEnable = TRUE; + bb.dwFlags = DWM_BB_ENABLE; + if(HRESULT hr = g_dwmapi_pointers.dwmEnableBlurBehindWindow(window->winId(), &bb)) + { + qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr); + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// SYSTEM COLORS +/////////////////////////////////////////////////////////////////////////////// + +QColor MUtils::GUI::system_color(const int &color_id) +{ + int nIndex = -1; + + switch(color_id) + { + case SYSCOLOR_TEXT: + nIndex = COLOR_WINDOWTEXT; /*Text in windows*/ + break; + case SYSCOLOR_BACKGROUND: + nIndex = COLOR_WINDOW; /*Window background*/ + break; + case SYSCOLOR_CAPTION: + nIndex = COLOR_CAPTIONTEXT; /*Text in caption, size box, and scroll bar arrow box*/ + break; + default: + qWarning("Unknown system color id (%d) specified!", color_id); + nIndex = COLOR_WINDOWTEXT; + } + + const DWORD rgb = GetSysColor(nIndex); + QColor color(GetRValue(rgb), GetGValue(rgb), GetBValue(rgb)); + return color; +} diff --git a/src/JobObject_Win32.cpp b/src/JobObject_Win32.cpp new file mode 100644 index 0000000..51c1295 --- /dev/null +++ b/src/JobObject_Win32.cpp @@ -0,0 +1,146 @@ +/////////////////////////////////////////////////////////////////////////////// +// LameXP - Audio Encoder Front-End +// Copyright (C) 2004-2014 LoRd_MuldeR +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version, but always including the *additional* +// restrictions defined in the "License.txt" file. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +//Internal +#include + +//Qt +#include + +//Windows includes +#define NOMINMAX +#define WIN32_LEAN_AND_MEAN 1 +#include +#include +#include +#include + +namespace MUtils +{ + class JobObject_Private + { + friend class JobObject; + + protected: + JobObject_Private(void) + { + m_hJobObject = NULL; + } + + HANDLE m_hJobObject; + }; +} + +MUtils::JobObject::JobObject(void) +: + p(new JobObject_Private()) +{ + const HANDLE jobObject = CreateJobObject(NULL, NULL); + if((jobObject != NULL) && (jobObject != INVALID_HANDLE_VALUE)) + { + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobExtendedLimitInfo; + memset(&jobExtendedLimitInfo, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); + memset(&jobExtendedLimitInfo.BasicLimitInformation, 0, sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION)); + jobExtendedLimitInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION; + if(SetInformationJobObject(jobObject, JobObjectExtendedLimitInformation, &jobExtendedLimitInfo, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION))) + { + p->m_hJobObject = jobObject; + } + else + { + qWarning("Failed to set job object information!"); + CloseHandle(jobObject); + } + } + else + { + qWarning("Failed to create the job object!"); + } +} + +MUtils::JobObject::~JobObject(void) +{ + if(p->m_hJobObject) + { + CloseHandle(p->m_hJobObject); + p->m_hJobObject = NULL; + } +} + +bool MUtils::JobObject::addProcessToJob(const QProcess *proc) +{ + if(!p->m_hJobObject) + { + qWarning("Cannot assign process to job: No job bject available!"); + return false; + } + + if(Q_PID pid = proc->pid()) + { + DWORD exitCode; + if(!GetExitCodeProcess(pid->hProcess, &exitCode)) + { + qWarning("Cannot assign process to job: Failed to query process status!"); + return false; + } + + if(exitCode != STILL_ACTIVE) + { + qWarning("Cannot assign process to job: Process is not running anymore!"); + return false; + } + + if(!AssignProcessToJobObject(p->m_hJobObject, pid->hProcess)) + { + qWarning("Failed to assign process to job object!"); + return false; + } + + return true; + } + else + { + qWarning("Cannot assign process to job: Process handle not available!"); + return false; + } +} + +bool MUtils::JobObject::terminateJob(unsigned int exitCode) +{ + if(p->m_hJobObject) + { + if(TerminateJobObject(p->m_hJobObject, exitCode)) + { + return true; + } + else + { + qWarning("Failed to terminate job object!"); + return false; + } + } + else + { + qWarning("Cannot assign process to job: No job bject available!"); + return false; + } +} diff --git a/src/OSSupport_Win32.cpp b/src/OSSupport_Win32.cpp index 3df1dba..a875e3d 100644 --- a/src/OSSupport_Win32.cpp +++ b/src/OSSupport_Win32.cpp @@ -949,6 +949,15 @@ bool MUtils::OS::reset_timer_resolution(const quint32 &interval) } /////////////////////////////////////////////////////////////////////////////// +// CHECK KEY STATE +/////////////////////////////////////////////////////////////////////////////// + +bool MUtils::OS::check_key_state_esc(void) +{ + return (GetAsyncKeyState(VK_ESCAPE) & 0x0001) != 0; +} + +/////////////////////////////////////////////////////////////////////////////// // DEBUGGER CHECK ///////////////////////////////////////////////////////////////////////////////