Format shortcut_guide according to .clang-format

This commit is contained in:
yuyoyuppe 2019-12-06 14:07:54 +03:00 committed by yuyoyuppe
parent 946e74a918
commit f22a30ca87
10 changed files with 1395 additions and 1171 deletions

View File

@ -5,26 +5,32 @@
#include "overlay_window.h" #include "overlay_window.h"
#include "trace.h" #include "trace.h"
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
switch (ul_reason_for_call) { {
case DLL_PROCESS_ATTACH: switch (ul_reason_for_call)
Trace::RegisterProvider(); {
break; case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH: Trace::RegisterProvider();
case DLL_THREAD_DETACH: break;
break; case DLL_THREAD_ATTACH:
case DLL_PROCESS_DETACH: case DLL_THREAD_DETACH:
Trace::UnregisterProvider(); break;
break; case DLL_PROCESS_DETACH:
} Trace::UnregisterProvider();
return TRUE; break;
}
return TRUE;
} }
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create() { extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
if (!instance) { {
instance = new OverlayWindow(); if (!instance)
return instance; {
} else { instance = new OverlayWindow();
return nullptr; return instance;
} }
else
{
return nullptr;
}
} }

View File

@ -1,22 +1,25 @@
#include "pch.h" #include "pch.h"
#include "keyboard_state.h" #include "keyboard_state.h"
bool winkey_held() { bool winkey_held()
auto left = GetAsyncKeyState(VK_LWIN); {
auto right = GetAsyncKeyState(VK_RWIN); auto left = GetAsyncKeyState(VK_LWIN);
return (left & 0x8000) || (right & 0x8000); auto right = GetAsyncKeyState(VK_RWIN);
return (left & 0x8000) || (right & 0x8000);
} }
bool only_winkey_key_held() { bool only_winkey_key_held()
/* There are situations, when some of the keys are not registered correctly by {
/* There are situations, when some of the keys are not registered correctly by
GetKeyboardState. The M key can get stuck as "pressed" after Win+M, and GetKeyboardState. The M key can get stuck as "pressed" after Win+M, and
Shift etc. keys are not always reported as expected. Shift etc. keys are not always reported as expected.
*/ */
for (int vk = 0; vk <= VK_OEM_CLEAR; ++vk) { for (int vk = 0; vk <= VK_OEM_CLEAR; ++vk)
if (vk == VK_LWIN || vk == VK_RWIN) {
continue; if (vk == VK_LWIN || vk == VK_RWIN)
if (GetAsyncKeyState(vk) & 0x8000) continue;
return false; if (GetAsyncKeyState(vk) & 0x8000)
} return false;
return true; }
return true;
} }

File diff suppressed because it is too large Load Diff

View File

@ -7,85 +7,94 @@
#include "common/windows_colors.h" #include "common/windows_colors.h"
#include "common/tasklist_positions.h" #include "common/tasklist_positions.h"
struct ScaleResult { struct ScaleResult
double scale; {
RECT rect; double scale;
RECT rect;
}; };
class D2DOverlaySVG : public D2DSVG { class D2DOverlaySVG : public D2DSVG
{
public: public:
D2DOverlaySVG& load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc); D2DOverlaySVG& load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc);
D2DOverlaySVG& resize(int x, int y, int width, int height, float fill, float max_scale = -1.0f); D2DOverlaySVG& resize(int x, int y, int width, int height, float fill, float max_scale = -1.0f);
D2DOverlaySVG& find_thumbnail(const std::wstring& id); D2DOverlaySVG& find_thumbnail(const std::wstring& id);
D2DOverlaySVG& find_window_group(const std::wstring& id); D2DOverlaySVG& find_window_group(const std::wstring& id);
ScaleResult get_thumbnail_rect_and_scale(int x_offset, int y_offset, int window_cx, int window_cy, float fill); ScaleResult get_thumbnail_rect_and_scale(int x_offset, int y_offset, int window_cx, int window_cy, float fill);
D2DOverlaySVG& toggle_window_group(bool active); D2DOverlaySVG& toggle_window_group(bool active);
winrt::com_ptr<ID2D1SvgElement> find_element(const std::wstring& id); winrt::com_ptr<ID2D1SvgElement> find_element(const std::wstring& id);
D2D1_RECT_F get_maximize_label() const; D2D1_RECT_F get_maximize_label() const;
D2D1_RECT_F get_minimize_label() const; D2D1_RECT_F get_minimize_label() const;
D2D1_RECT_F get_snap_left() const; D2D1_RECT_F get_snap_left() const;
D2D1_RECT_F get_snap_right() const; D2D1_RECT_F get_snap_right() const;
private: private:
D2D1_POINT_2F thumbnail_top_left = {}; D2D1_POINT_2F thumbnail_top_left = {};
D2D1_POINT_2F thumbnail_bottom_right = {}; D2D1_POINT_2F thumbnail_bottom_right = {};
RECT thumbnail_scaled_rect = {}; RECT thumbnail_scaled_rect = {};
winrt::com_ptr<ID2D1SvgElement> window_group; winrt::com_ptr<ID2D1SvgElement> window_group;
}; };
struct AnimateKeys { struct AnimateKeys
Animation animation; {
D2D1_COLOR_F original; Animation animation;
winrt::com_ptr<ID2D1SvgElement> button; D2D1_COLOR_F original;
int vk_code; winrt::com_ptr<ID2D1SvgElement> button;
int vk_code;
}; };
class D2DOverlayWindow : public D2DWindow { class D2DOverlayWindow : public D2DWindow
{
public: public:
D2DOverlayWindow(); D2DOverlayWindow();
void show(HWND active_window); void show(HWND active_window);
void animate(int vk_code); void animate(int vk_code);
~D2DOverlayWindow(); ~D2DOverlayWindow();
void apply_overlay_opacity(float opacity); void apply_overlay_opacity(float opacity);
void set_theme(const std::wstring& theme); void set_theme(const std::wstring& theme);
void quick_hide(); void quick_hide();
private: private:
void animate(int vk_code, int offset); void animate(int vk_code, int offset);
bool show_thumbnail(const RECT& rect, double alpha); bool show_thumbnail(const RECT& rect, double alpha);
void hide_thumbnail(); void hide_thumbnail();
virtual void init() override; virtual void init() override;
virtual void resize() override; virtual void resize() override;
virtual void render(ID2D1DeviceContext5* d2d_dc) override; virtual void render(ID2D1DeviceContext5* d2d_dc) override;
virtual void on_show() override; virtual void on_show() override;
virtual void on_hide() override; virtual void on_hide() override;
float get_overlay_opacity(); float get_overlay_opacity();
bool running = true; bool running = true;
std::vector<AnimateKeys> key_animations; std::vector<AnimateKeys> key_animations;
std::vector<int> key_pressed; std::vector<int> key_pressed;
std::vector<MonitorInfo> monitors; std::vector<MonitorInfo> monitors;
ScreenSize total_screen; ScreenSize total_screen;
int monitor_dx = 0, monitor_dy = 0; int monitor_dx = 0, monitor_dy = 0;
D2DText text; D2DText text;
WindowsColors colors; WindowsColors colors;
Animation animation; Animation animation;
RECT window_rect = {}; RECT window_rect = {};
Tasklist tasklist; Tasklist tasklist;
std::vector<TasklistButton> tasklist_buttons; std::vector<TasklistButton> tasklist_buttons;
std::thread tasklist_thread; std::thread tasklist_thread;
bool tasklist_update = false; bool tasklist_update = false;
std::mutex tasklist_cv_mutex; std::mutex tasklist_cv_mutex;
std::condition_variable tasklist_cv; std::condition_variable tasklist_cv;
HTHUMBNAIL thumbnail; HTHUMBNAIL thumbnail;
HWND active_window = nullptr; HWND active_window = nullptr;
D2DOverlaySVG landscape, portrait; D2DOverlaySVG landscape, portrait;
D2DOverlaySVG* use_overlay = nullptr; D2DOverlaySVG* use_overlay = nullptr;
D2DSVG no_active; D2DSVG no_active;
std::vector<D2DSVG> arrows; std::vector<D2DSVG> arrows;
std::chrono::steady_clock::time_point shown_start_time; std::chrono::steady_clock::time_point shown_start_time;
float overlay_opacity = 0.9f; float overlay_opacity = 0.9f;
enum { enum
Light, Dark, System {
} theme_setting = System; Light,
bool light_mode = true; Dark,
System
} theme_setting = System;
bool light_mode = true;
}; };

View File

@ -8,169 +8,199 @@ extern "C" IMAGE_DOS_HEADER __ImageBase;
OverlayWindow* instance = nullptr; OverlayWindow* instance = nullptr;
OverlayWindow::OverlayWindow() { OverlayWindow::OverlayWindow()
init_settings(); {
init_settings();
} }
const wchar_t * OverlayWindow::get_name() { const wchar_t* OverlayWindow::get_name()
return L"Shortcut Guide"; {
return L"Shortcut Guide";
} }
const wchar_t ** OverlayWindow::get_events() { const wchar_t** OverlayWindow::get_events()
static const wchar_t* events[2] = { ll_keyboard, 0 }; {
return events; static const wchar_t* events[2] = { ll_keyboard, 0 };
return events;
} }
bool OverlayWindow::get_config(wchar_t* buffer, int *buffer_size) { bool OverlayWindow::get_config(wchar_t* buffer, int* buffer_size)
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase); {
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
PowerToysSettings::Settings settings(hinstance, get_name()); PowerToysSettings::Settings settings(hinstance, get_name());
settings.set_description(L"Shows a help overlay with Windows shortcuts when the Windows key is pressed."); settings.set_description(L"Shows a help overlay with Windows shortcuts when the Windows key is pressed.");
settings.set_overview_link(L"https://github.com/microsoft/PowerToys/blob/master/src/modules/shortcut_guide/README.md"); settings.set_overview_link(L"https://github.com/microsoft/PowerToys/blob/master/src/modules/shortcut_guide/README.md");
settings.set_icon_key(L"pt-shortcut-guide"); settings.set_icon_key(L"pt-shortcut-guide");
settings.add_int_spinner( settings.add_int_spinner(
pressTime.name, pressTime.name,
pressTime.resourceId, pressTime.resourceId,
pressTime.value, pressTime.value,
100, 100,
10000, 10000,
100 100);
);
settings.add_int_spinner( settings.add_int_spinner(
overlayOpacity.name, overlayOpacity.name,
overlayOpacity.resourceId, overlayOpacity.resourceId,
overlayOpacity.value, overlayOpacity.value,
0, 0,
100, 100,
1 1);
);
settings.add_choice_group( settings.add_choice_group(
theme.name, theme.name,
theme.resourceId, theme.resourceId,
theme.value, theme.value,
theme.keys_and_texts theme.keys_and_texts);
);
return settings.serialize_to_buffer(buffer, buffer_size); return settings.serialize_to_buffer(buffer, buffer_size);
} }
void OverlayWindow::set_config(const wchar_t * config) { void OverlayWindow::set_config(const wchar_t* config)
try { {
PowerToysSettings::PowerToyValues _values = try
PowerToysSettings::PowerToyValues::from_json_string(config); {
if (const auto press_delay_time = _values.get_int_value(pressTime.name)) { PowerToysSettings::PowerToyValues _values =
pressTime.value = *press_delay_time; PowerToysSettings::PowerToyValues::from_json_string(config);
if (target_state) { if (const auto press_delay_time = _values.get_int_value(pressTime.name))
target_state->set_delay(*press_delay_time); {
} pressTime.value = *press_delay_time;
if (target_state)
{
target_state->set_delay(*press_delay_time);
}
}
if (const auto overlay_opacity = _values.get_int_value(overlayOpacity.name))
{
overlayOpacity.value = *overlay_opacity;
if (winkey_popup)
{
winkey_popup->apply_overlay_opacity(((float)overlayOpacity.value) / 100.0f);
}
}
if (auto val = _values.get_string_value(theme.name))
{
theme.value = std::move(*val);
winkey_popup->set_theme(theme.value);
}
_values.save_to_settings_file();
Trace::SettingsChanged(pressTime.value, overlayOpacity.value, theme.value);
} }
if (const auto overlay_opacity = _values.get_int_value(overlayOpacity.name)) { catch (...)
overlayOpacity.value = *overlay_opacity; {
if (winkey_popup) { // Improper JSON. TODO: handle the error.
}
}
void OverlayWindow::enable()
{
if (!_enabled)
{
Trace::EnableShortcutGuide(true);
winkey_popup = std::make_unique<D2DOverlayWindow>();
winkey_popup->apply_overlay_opacity(((float)overlayOpacity.value) / 100.0f); winkey_popup->apply_overlay_opacity(((float)overlayOpacity.value) / 100.0f);
} winkey_popup->set_theme(theme.value);
target_state = std::make_unique<TargetState>(pressTime.value);
winkey_popup->initialize();
} }
if (auto val = _values.get_string_value(theme.name)) { _enabled = true;
theme.value = std::move(*val); }
winkey_popup->set_theme(theme.value);
void OverlayWindow::disable(bool trace_event)
{
if (_enabled)
{
_enabled = false;
if (trace_event)
{
Trace::EnableShortcutGuide(false);
}
winkey_popup->hide();
target_state->exit();
target_state.reset();
winkey_popup.reset();
} }
_values.save_to_settings_file();
Trace::SettingsChanged(pressTime.value, overlayOpacity.value, theme.value);
}
catch (...) {
// Improper JSON. TODO: handle the error.
}
} }
void OverlayWindow::enable() { void OverlayWindow::disable()
if (!_enabled) { {
Trace::EnableShortcutGuide(true); this->disable(true);
winkey_popup = std::make_unique<D2DOverlayWindow>();
winkey_popup->apply_overlay_opacity(((float)overlayOpacity.value)/100.0f);
winkey_popup->set_theme(theme.value);
target_state = std::make_unique<TargetState>(pressTime.value);
winkey_popup->initialize();
}
_enabled = true;
} }
void OverlayWindow::disable(bool trace_event) { bool OverlayWindow::is_enabled()
if (_enabled) { {
_enabled = false; return _enabled;
if (trace_event) { }
Trace::EnableShortcutGuide(false);
intptr_t OverlayWindow::signal_event(const wchar_t* name, intptr_t data)
{
if (_enabled && wcscmp(name, ll_keyboard) == 0)
{
auto& event = *(reinterpret_cast<LowlevelKeyboardEvent*>(data));
if (event.wParam == WM_KEYDOWN ||
event.wParam == WM_SYSKEYDOWN ||
event.wParam == WM_KEYUP ||
event.wParam == WM_SYSKEYUP)
{
bool supress = target_state->signal_event(event.lParam->vkCode,
event.wParam == WM_KEYDOWN || event.wParam == WM_SYSKEYDOWN);
return supress ? 1 : 0;
}
} }
winkey_popup->hide(); return 0;
target_state->exit();
target_state.reset();
winkey_popup.reset();
}
} }
void OverlayWindow::disable() { void OverlayWindow::on_held()
this->disable(true); {
auto active_window = get_filtered_active_window();
winkey_popup->show(active_window);
} }
bool OverlayWindow::is_enabled() { void OverlayWindow::on_held_press(DWORD vkCode)
return _enabled; {
winkey_popup->animate(vkCode);
} }
intptr_t OverlayWindow::signal_event(const wchar_t * name, intptr_t data) { void OverlayWindow::quick_hide()
if (_enabled && wcscmp(name, ll_keyboard) == 0) { {
auto& event = *(reinterpret_cast<LowlevelKeyboardEvent*>(data)); winkey_popup->quick_hide();
if (event.wParam == WM_KEYDOWN || }
event.wParam == WM_SYSKEYDOWN ||
event.wParam == WM_KEYUP || void OverlayWindow::was_hidden()
event.wParam == WM_SYSKEYUP) { {
bool supress = target_state->signal_event(event.lParam->vkCode, target_state->was_hiden();
event.wParam == WM_KEYDOWN || event.wParam == WM_SYSKEYDOWN); }
return supress ? 1 : 0;
void OverlayWindow::destroy()
{
this->disable(false);
delete this;
instance = nullptr;
}
void OverlayWindow::init_settings()
{
try
{
PowerToysSettings::PowerToyValues settings =
PowerToysSettings::PowerToyValues::load_from_settings_file(OverlayWindow::get_name());
if (const auto val = settings.get_int_value(pressTime.name))
{
pressTime.value = *val;
}
if (const auto val = settings.get_int_value(overlayOpacity.name))
{
overlayOpacity.value = *val;
}
if (auto val = settings.get_string_value(theme.name))
{
theme.value = std::move(*val);
}
} }
} catch (std::exception&)
return 0; {
} // Error while loading from the settings file. Just let default values stay as they are.
void OverlayWindow::on_held() {
auto active_window = get_filtered_active_window();
winkey_popup->show(active_window);
}
void OverlayWindow::on_held_press(DWORD vkCode) {
winkey_popup->animate(vkCode);
}
void OverlayWindow::quick_hide() {
winkey_popup->quick_hide();
}
void OverlayWindow::was_hidden() {
target_state->was_hiden();
}
void OverlayWindow::destroy() {
this->disable(false);
delete this;
instance = nullptr;
}
void OverlayWindow::init_settings() {
try {
PowerToysSettings::PowerToyValues settings =
PowerToysSettings::PowerToyValues::load_from_settings_file(OverlayWindow::get_name());
if (const auto val = settings.get_int_value(pressTime.name)) {
pressTime.value = *val;
} }
if (const auto val = settings.get_int_value(overlayOpacity.name)) {
overlayOpacity.value = *val;
}
if (auto val = settings.get_string_value(theme.name)) {
theme.value = std::move(*val);
}
}
catch (std::exception&) {
// Error while loading from the settings file. Just let default values stay as they are.
}
} }

View File

@ -8,57 +8,61 @@ extern class OverlayWindow* instance;
class TargetState; class TargetState;
class OverlayWindow : public PowertoyModuleIface { class OverlayWindow : public PowertoyModuleIface
{
public: public:
OverlayWindow(); OverlayWindow();
virtual const wchar_t* get_name() override; virtual const wchar_t* get_name() override;
virtual const wchar_t** get_events() override; virtual const wchar_t** get_events() override;
virtual bool get_config(wchar_t* buffer, int *buffer_size) override; virtual bool get_config(wchar_t* buffer, int* buffer_size) override;
virtual void set_config(const wchar_t* config) override; virtual void set_config(const wchar_t* config) override;
virtual void enable() override; virtual void enable() override;
virtual void disable() override; virtual void disable() override;
virtual bool is_enabled() override; virtual bool is_enabled() override;
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override; virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override;
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) override { } virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) override {}
virtual void signal_system_menu_action(const wchar_t* name) override { } virtual void signal_system_menu_action(const wchar_t* name) override {}
void on_held(); void on_held();
void on_held_press(DWORD vkCode); void on_held_press(DWORD vkCode);
void quick_hide(); void quick_hide();
void was_hidden(); void was_hidden();
virtual void destroy() override; virtual void destroy() override;
private: private:
std::unique_ptr<TargetState> target_state; std::unique_ptr<TargetState> target_state;
std::unique_ptr<D2DOverlayWindow> winkey_popup; std::unique_ptr<D2DOverlayWindow> winkey_popup;
bool _enabled = false; bool _enabled = false;
void init_settings(); void init_settings();
void disable(bool trace_event); void disable(bool trace_event);
struct PressTime { struct PressTime
PCWSTR name = L"press_time"; {
int value = 900; // ms PCWSTR name = L"press_time";
int resourceId = IDS_SETTING_DESCRIPTION_PRESS_TIME; int value = 900; // ms
} pressTime; int resourceId = IDS_SETTING_DESCRIPTION_PRESS_TIME;
} pressTime;
struct OverlayOpacity { struct OverlayOpacity
PCWSTR name = L"overlay_opacity"; {
int value = 90; // percent PCWSTR name = L"overlay_opacity";
int resourceId = IDS_SETTING_DESCRIPTION_OVERLAY_OPACITY; int value = 90; // percent
} overlayOpacity; int resourceId = IDS_SETTING_DESCRIPTION_OVERLAY_OPACITY;
} overlayOpacity;
struct Theme { struct Theme
PCWSTR name = L"theme"; {
std::wstring value = L"system"; PCWSTR name = L"theme";
int resourceId = IDS_SETTING_DESCRIPTION_THEME; std::wstring value = L"system";
std::vector<std::pair<std::wstring, UINT>> keys_and_texts = { int resourceId = IDS_SETTING_DESCRIPTION_THEME;
{ L"system", IDS_SETTING_DESCRIPTION_THEME_SYSTEM }, std::vector<std::pair<std::wstring, UINT>> keys_and_texts = {
{ L"light", IDS_SETTING_DESCRIPTION_THEME_LIGHT }, { L"system", IDS_SETTING_DESCRIPTION_THEME_SYSTEM },
{ L"dark", IDS_SETTING_DESCRIPTION_THEME_DARK } { L"light", IDS_SETTING_DESCRIPTION_THEME_LIGHT },
}; { L"dark", IDS_SETTING_DESCRIPTION_THEME_DARK }
} theme; };
} theme;
}; };

View File

@ -3,155 +3,180 @@
#include "common/start_visible.h" #include "common/start_visible.h"
#include "keyboard_state.h" #include "keyboard_state.h"
TargetState::TargetState(int ms_delay) : delay(std::chrono::milliseconds(ms_delay)), thread(&TargetState::thread_proc, this) TargetState::TargetState(int ms_delay) :
{ } delay(std::chrono::milliseconds(ms_delay)), thread(&TargetState::thread_proc, this)
{
bool TargetState::signal_event(unsigned vk_code, bool key_down) {
std::unique_lock lock(mutex);
if (!events.empty() && events.back().key_down == key_down && events.back().vk_code == vk_code) {
return false;
}
// Hide the overlay when WinKey + Shift + S is pressed. 0x53 is the VK code of the S key
if (key_down && state == Shown && vk_code == 0x53 && (GetKeyState(VK_LSHIFT) || GetKeyState(VK_RSHIFT))) {
// We cannot use normal hide() here, there is stuff that needs deinitialization.
// It can be safely done when the user releases the WinKey.
instance->quick_hide();
}
bool supress = false;
if (!key_down && (vk_code == VK_LWIN || vk_code == VK_RWIN) &&
state == Shown &&
std::chrono::system_clock::now() - singnal_timestamp > std::chrono::milliseconds(300) &&
!key_was_pressed) {
supress = true;
}
events.push_back({ key_down, vk_code });
lock.unlock();
cv.notify_one();
if (supress) {
// Send a fake key-stroke to prevent the start menu from appearing.
// We use 0xCF VK code, which is reserved. It still prevents the
// start menu from appearing, but should not interfere with any
// keyboard shortcuts.
INPUT input[3] = { {},{},{} };
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = 0xCF;
input[1].type = INPUT_KEYBOARD;
input[1].ki.wVk = 0xCF;
input[1].ki.dwFlags = KEYEVENTF_KEYUP;
input[2].type = INPUT_KEYBOARD;
input[2].ki.wVk = VK_LWIN;
input[2].ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(3, input, sizeof(INPUT));
}
return supress;
} }
void TargetState::was_hiden() { bool TargetState::signal_event(unsigned vk_code, bool key_down)
std::unique_lock<std::mutex> lock(mutex); {
state = Hidden; std::unique_lock lock(mutex);
events.clear(); if (!events.empty() && events.back().key_down == key_down && events.back().vk_code == vk_code)
lock.unlock(); {
cv.notify_one(); return false;
}
void TargetState::exit() {
std::unique_lock lock(mutex);
events.clear();
state = Exiting;
lock.unlock();
cv.notify_one();
thread.join();
}
KeyEvent TargetState::next() {
auto e = events.front();
events.pop_front();
return e;
}
void TargetState::handle_hidden() {
std::unique_lock lock(mutex);
if (events.empty())
cv.wait(lock);
if (events.empty() || state == Exiting)
return;
auto event = next();
if (event.key_down && (event.vk_code == VK_LWIN || event.vk_code == VK_RWIN)) {
state = Timeout;
winkey_timestamp = std::chrono::system_clock::now();
}
}
void TargetState::handle_shown() {
std::unique_lock lock(mutex);
if (events.empty()) {
cv.wait(lock);
}
if (events.empty() || state == Exiting) {
return;
}
auto event = next();
if (event.key_down && (event.vk_code == VK_LWIN || event.vk_code == VK_RWIN)) {
return;
}
if (!event.key_down && (event.vk_code == VK_LWIN || event.vk_code == VK_RWIN) || !winkey_held()) {
state = Hidden;
lock.unlock();
return;
}
if (event.key_down) {
key_was_pressed = true;
lock.unlock();
instance->on_held_press(event.vk_code);
}
}
void TargetState::thread_proc() {
while (true) {
switch (state) {
case Hidden:
handle_hidden();
break;
case Timeout:
handle_timeout();
break;
case Shown:
handle_shown();
break;
case Exiting:
default:
return;
} }
} // Hide the overlay when WinKey + Shift + S is pressed. 0x53 is the VK code of the S key
if (key_down && state == Shown && vk_code == 0x53 && (GetKeyState(VK_LSHIFT) || GetKeyState(VK_RSHIFT)))
{
// We cannot use normal hide() here, there is stuff that needs deinitialization.
// It can be safely done when the user releases the WinKey.
instance->quick_hide();
}
bool supress = false;
if (!key_down && (vk_code == VK_LWIN || vk_code == VK_RWIN) &&
state == Shown &&
std::chrono::system_clock::now() - singnal_timestamp > std::chrono::milliseconds(300) &&
!key_was_pressed)
{
supress = true;
}
events.push_back({ key_down, vk_code });
lock.unlock();
cv.notify_one();
if (supress)
{
// Send a fake key-stroke to prevent the start menu from appearing.
// We use 0xCF VK code, which is reserved. It still prevents the
// start menu from appearing, but should not interfere with any
// keyboard shortcuts.
INPUT input[3] = { {}, {}, {} };
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = 0xCF;
input[1].type = INPUT_KEYBOARD;
input[1].ki.wVk = 0xCF;
input[1].ki.dwFlags = KEYEVENTF_KEYUP;
input[2].type = INPUT_KEYBOARD;
input[2].ki.wVk = VK_LWIN;
input[2].ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(3, input, sizeof(INPUT));
}
return supress;
} }
void TargetState::handle_timeout() { void TargetState::was_hiden()
std::unique_lock lock(mutex); {
auto wait_time = delay - (std::chrono::system_clock::now() - winkey_timestamp); std::unique_lock<std::mutex> lock(mutex);
if (events.empty())
cv.wait_for(lock, wait_time);
if (state == Exiting)
return;
while (!events.empty()) {
auto event = events.front();
if (event.key_down && (event.vk_code == VK_LWIN || event.vk_code == VK_RWIN))
events.pop_front();
else
break;
}
if (!events.empty() || !only_winkey_key_held() || is_start_visible()) {
state = Hidden; state = Hidden;
return; events.clear();
} lock.unlock();
if (std::chrono::system_clock::now() - winkey_timestamp < delay) cv.notify_one();
return;
singnal_timestamp = std::chrono::system_clock::now();
key_was_pressed = false;
state = Shown;
lock.unlock();
instance->on_held();
} }
void TargetState::set_delay(int ms_delay) { void TargetState::exit()
delay = std::chrono::milliseconds(ms_delay); {
std::unique_lock lock(mutex);
events.clear();
state = Exiting;
lock.unlock();
cv.notify_one();
thread.join();
}
KeyEvent TargetState::next()
{
auto e = events.front();
events.pop_front();
return e;
}
void TargetState::handle_hidden()
{
std::unique_lock lock(mutex);
if (events.empty())
cv.wait(lock);
if (events.empty() || state == Exiting)
return;
auto event = next();
if (event.key_down && (event.vk_code == VK_LWIN || event.vk_code == VK_RWIN))
{
state = Timeout;
winkey_timestamp = std::chrono::system_clock::now();
}
}
void TargetState::handle_shown()
{
std::unique_lock lock(mutex);
if (events.empty())
{
cv.wait(lock);
}
if (events.empty() || state == Exiting)
{
return;
}
auto event = next();
if (event.key_down && (event.vk_code == VK_LWIN || event.vk_code == VK_RWIN))
{
return;
}
if (!event.key_down && (event.vk_code == VK_LWIN || event.vk_code == VK_RWIN) || !winkey_held())
{
state = Hidden;
lock.unlock();
return;
}
if (event.key_down)
{
key_was_pressed = true;
lock.unlock();
instance->on_held_press(event.vk_code);
}
}
void TargetState::thread_proc()
{
while (true)
{
switch (state)
{
case Hidden:
handle_hidden();
break;
case Timeout:
handle_timeout();
break;
case Shown:
handle_shown();
break;
case Exiting:
default:
return;
}
}
}
void TargetState::handle_timeout()
{
std::unique_lock lock(mutex);
auto wait_time = delay - (std::chrono::system_clock::now() - winkey_timestamp);
if (events.empty())
cv.wait_for(lock, wait_time);
if (state == Exiting)
return;
while (!events.empty())
{
auto event = events.front();
if (event.key_down && (event.vk_code == VK_LWIN || event.vk_code == VK_RWIN))
events.pop_front();
else
break;
}
if (!events.empty() || !only_winkey_key_held() || is_start_visible())
{
state = Hidden;
return;
}
if (std::chrono::system_clock::now() - winkey_timestamp < delay)
return;
singnal_timestamp = std::chrono::system_clock::now();
key_was_pressed = false;
state = Shown;
lock.unlock();
instance->on_held();
}
void TargetState::set_delay(int ms_delay)
{
delay = std::chrono::milliseconds(ms_delay);
} }

View File

@ -6,30 +6,39 @@
#include <chrono> #include <chrono>
#include "shortcut_guide.h" #include "shortcut_guide.h"
struct KeyEvent { struct KeyEvent
bool key_down; {
unsigned vk_code; bool key_down;
unsigned vk_code;
}; };
class TargetState { class TargetState
{
public: public:
TargetState(int ms_delay); TargetState(int ms_delay);
bool signal_event(unsigned vk_code, bool key_down); bool signal_event(unsigned vk_code, bool key_down);
void was_hiden(); void was_hiden();
void exit(); void exit();
void set_delay(int ms_delay); void set_delay(int ms_delay);
private: private:
KeyEvent next(); KeyEvent next();
void handle_hidden(); void handle_hidden();
void handle_timeout(); void handle_timeout();
void handle_shown(); void handle_shown();
void thread_proc(); void thread_proc();
std::mutex mutex; std::mutex mutex;
std::condition_variable cv; std::condition_variable cv;
std::chrono::system_clock::time_point winkey_timestamp, singnal_timestamp; std::chrono::system_clock::time_point winkey_timestamp, singnal_timestamp;
std::chrono::milliseconds delay; std::chrono::milliseconds delay;
std::deque<KeyEvent> events; std::deque<KeyEvent> events;
enum { Hidden, Timeout, Shown, Exiting } state = Hidden; enum
bool key_was_pressed = false; {
std::thread thread; Hidden,
Timeout,
Shown,
Exiting
} state = Hidden;
bool key_was_pressed = false;
std::thread thread;
}; };

View File

@ -2,59 +2,66 @@
#include "trace.h" #include "trace.h"
TRACELOGGING_DEFINE_PROVIDER( TRACELOGGING_DEFINE_PROVIDER(
g_hProvider, g_hProvider,
"Microsoft.PowerToys", "Microsoft.PowerToys",
// {38e8889b-9731-53f5-e901-e8a7c1753074} // {38e8889b-9731-53f5-e901-e8a7c1753074}
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74), (0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
TraceLoggingOptionProjectTelemetry()); TraceLoggingOptionProjectTelemetry());
void Trace::RegisterProvider() noexcept { void Trace::RegisterProvider() noexcept
TraceLoggingRegister(g_hProvider); {
TraceLoggingRegister(g_hProvider);
} }
void Trace::UnregisterProvider() noexcept { void Trace::UnregisterProvider() noexcept
TraceLoggingUnregister(g_hProvider); {
TraceLoggingUnregister(g_hProvider);
} }
void Trace::HideGuide(const __int64 duration_ms, std::vector<int> &key_pressed) noexcept { void Trace::HideGuide(const __int64 duration_ms, std::vector<int>& key_pressed) noexcept
std::string vk_codes; {
std::vector<int>::iterator it; std::string vk_codes;
for (it = key_pressed.begin(); it != key_pressed.end(); ) { std::vector<int>::iterator it;
vk_codes += std::to_string(*it); for (it = key_pressed.begin(); it != key_pressed.end();)
if (++it != key_pressed.end()) { {
vk_codes += " "; vk_codes += std::to_string(*it);
if (++it != key_pressed.end())
{
vk_codes += " ";
}
} }
}
TraceLoggingWrite( TraceLoggingWrite(
g_hProvider, g_hProvider,
"ShortcutGuide_HideGuide", "ShortcutGuide_HideGuide",
TraceLoggingInt64(duration_ms, "DurationInMs"), TraceLoggingInt64(duration_ms, "DurationInMs"),
TraceLoggingInt64(key_pressed.size(), "NumberOfKeysPressed"), TraceLoggingInt64(key_pressed.size(), "NumberOfKeysPressed"),
TraceLoggingString(vk_codes.c_str(), "ListOfKeysPressed"), TraceLoggingString(vk_codes.c_str(), "ListOfKeysPressed"),
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
} }
void Trace::EnableShortcutGuide(const bool enabled) noexcept { void Trace::EnableShortcutGuide(const bool enabled) noexcept
TraceLoggingWrite( {
g_hProvider, TraceLoggingWrite(
"ShortcutGuide_EnableGuide", g_hProvider,
TraceLoggingBoolean(enabled, "Enabled"), "ShortcutGuide_EnableGuide",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), TraceLoggingBoolean(enabled, "Enabled"),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
} }
void Trace::SettingsChanged(const int press_delay_time, const int overlay_opacity, const std::wstring& theme) noexcept { void Trace::SettingsChanged(const int press_delay_time, const int overlay_opacity, const std::wstring& theme) noexcept
TraceLoggingWrite( {
g_hProvider, TraceLoggingWrite(
"ShortcutGuide_SettingsChanged", g_hProvider,
TraceLoggingInt32(press_delay_time, "PressDelayTime"), "ShortcutGuide_SettingsChanged",
TraceLoggingInt32(overlay_opacity, "OverlayOpacity"), TraceLoggingInt32(press_delay_time, "PressDelayTime"),
TraceLoggingWideString(theme.c_str(), "Theme"), TraceLoggingInt32(overlay_opacity, "OverlayOpacity"),
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), TraceLoggingWideString(theme.c_str(), "Theme"),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
} }

View File

@ -1,10 +1,11 @@
#pragma once #pragma once
class Trace { class Trace
{
public: public:
static void RegisterProvider() noexcept; static void RegisterProvider() noexcept;
static void UnregisterProvider() noexcept; static void UnregisterProvider() noexcept;
static void HideGuide(const __int64 duration_ms, std::vector<int> &key_pressed) noexcept; static void HideGuide(const __int64 duration_ms, std::vector<int>& key_pressed) noexcept;
static void EnableShortcutGuide(const bool enabled) noexcept; static void EnableShortcutGuide(const bool enabled) noexcept;
static void SettingsChanged(const int press_delay_time, const int overlay_opacity, const std::wstring& theme) noexcept; static void SettingsChanged(const int press_delay_time, const int overlay_opacity, const std::wstring& theme) noexcept;
}; };