mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
Detect Shortcut: Hold Esc/Enter to Cancel/Accept (#2135)
* Detect Shortcut: Hold Esc/Enter to Discard/Apply changes Bypass shorcut/single key remapping by holding the navigation keys
This commit is contained in:
committed by
GitHub
parent
5d9b71b038
commit
c37884bdb7
165
src/modules/keyboardmanager/common/KeyDelay.cpp
Normal file
165
src/modules/keyboardmanager/common/KeyDelay.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
#include "pch.h"
|
||||
#include "KeyDelay.h"
|
||||
|
||||
KeyDelay::~KeyDelay()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(_queueMutex);
|
||||
_quit = true;
|
||||
_cv.notify_all();
|
||||
l.unlock();
|
||||
_delayThread.join();
|
||||
}
|
||||
|
||||
void KeyDelay::KeyEvent(LowlevelKeyboardEvent* ev)
|
||||
{
|
||||
std::lock_guard guard(_queueMutex);
|
||||
_queue.push({ ev->lParam->time, ev->wParam });
|
||||
_cv.notify_all();
|
||||
}
|
||||
|
||||
KeyTimedEvent KeyDelay::NextEvent()
|
||||
{
|
||||
auto ev = _queue.front();
|
||||
_queue.pop();
|
||||
return ev;
|
||||
}
|
||||
|
||||
bool KeyDelay::CheckIfMillisHaveElapsed(DWORD first, DWORD last, DWORD duration)
|
||||
{
|
||||
if (first < last && first <= first + duration)
|
||||
{
|
||||
return first + duration < last;
|
||||
}
|
||||
else
|
||||
{
|
||||
first += ULONG_MAX / 2;
|
||||
last += ULONG_MAX / 2;
|
||||
return first + duration < last;
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyDelay::HasNextEvent()
|
||||
{
|
||||
return !_queue.empty();
|
||||
}
|
||||
|
||||
bool KeyDelay::HandleRelease()
|
||||
{
|
||||
while (HasNextEvent())
|
||||
{
|
||||
auto ev = NextEvent();
|
||||
switch (ev.message)
|
||||
{
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
_state = KeyDelayState::ON_HOLD;
|
||||
_initialHoldKeyDown = ev.time;
|
||||
return false;
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyDelay::HandleOnHold(std::unique_lock<std::mutex>& cvLock)
|
||||
{
|
||||
while (HasNextEvent())
|
||||
{
|
||||
auto ev = NextEvent();
|
||||
switch (ev.message)
|
||||
{
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
break;
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
if (CheckIfMillisHaveElapsed(_initialHoldKeyDown, ev.time, LONG_PRESS_DELAY_MILLIS))
|
||||
{
|
||||
if (_onLongPressDetected != nullptr)
|
||||
{
|
||||
_onLongPressDetected(_key);
|
||||
}
|
||||
if (_onLongPressReleased != nullptr)
|
||||
{
|
||||
_onLongPressReleased(_key);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_onShortPress != nullptr)
|
||||
{
|
||||
_onShortPress(_key);
|
||||
}
|
||||
}
|
||||
_state = KeyDelayState::RELEASED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (CheckIfMillisHaveElapsed(_initialHoldKeyDown, GetTickCount(), LONG_PRESS_DELAY_MILLIS))
|
||||
{
|
||||
if (_onLongPressDetected != nullptr)
|
||||
{
|
||||
_onLongPressDetected(_key);
|
||||
}
|
||||
_state = KeyDelayState::ON_HOLD_TIMEOUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cv.wait_for(cvLock, std::chrono::milliseconds(ON_HOLD_WAIT_TIMEOUT_MILLIS));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeyDelay::HandleOnHoldTimeout()
|
||||
{
|
||||
while (HasNextEvent())
|
||||
{
|
||||
auto ev = NextEvent();
|
||||
switch (ev.message)
|
||||
{
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
break;
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
if (_onLongPressReleased != nullptr)
|
||||
{
|
||||
_onLongPressReleased(_key);
|
||||
}
|
||||
_state = KeyDelayState::RELEASED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void KeyDelay::DelayThread()
|
||||
{
|
||||
std::unique_lock<std::mutex> qLock(_queueMutex);
|
||||
bool shouldWait = true;
|
||||
while (!_quit)
|
||||
{
|
||||
if (shouldWait)
|
||||
{
|
||||
_cv.wait(qLock);
|
||||
}
|
||||
|
||||
switch (_state)
|
||||
{
|
||||
case KeyDelayState::RELEASED:
|
||||
shouldWait = HandleRelease();
|
||||
break;
|
||||
case KeyDelayState::ON_HOLD:
|
||||
shouldWait = HandleOnHold(qLock);
|
||||
break;
|
||||
case KeyDelayState::ON_HOLD_TIMEOUT:
|
||||
shouldWait = HandleOnHoldTimeout();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user