Skip to content

Commit

Permalink
Merge pull request #1109 from reupen/focus-handling
Browse files Browse the repository at this point in the history
Improve focus restoration logic on window activation
  • Loading branch information
reupen authored Jan 29, 2025
2 parents 3dab03a + 2657811 commit 420ba66
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 57 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@
foobar2000 was minimised to the system tray.
[[#1110](https://github.com/reupen/columns_ui/pull/1110)]

- A bug where the keyboard focus changed after minimising and restoring
foobar2000 was fixed.
[[#1109](https://github.com/reupen/columns_ui/pull/1109)]

- Some logic that normally occurs when main window is activated or focused was
surpressed while foobar2000 is exiting, as that logic is unnecessary at that
point. [[#1109](https://github.com/reupen/columns_ui/pull/1109)]

### Internal changes

- `ui_config_callback::ui_fonts_changed()` is now called once instead of
Expand Down
19 changes: 19 additions & 0 deletions foo_ui_columns/main_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,25 @@ void cui::MainWindow::update_taskbar_buttons(bool update) const
}
}

void cui::MainWindow::save_focus_state()
{
HWND wnd_focused_before_menu{};

if (!rebar::g_rebar_window || !rebar::g_rebar_window->get_previous_menu_focus_window(wnd_focused_before_menu))
wnd_focused_before_menu = g_layout_window.get_previous_menu_focus_window();

if (wnd_focused_before_menu) {
m_last_focused_wnd = wnd_focused_before_menu;
return;
}

HWND wnd_focus = GetFocus();
if (wnd_focus && IsChild(m_wnd, wnd_focus))
m_last_focused_wnd = wnd_focus;
else
m_last_focused_wnd = nullptr;
}

void cui::MainWindow::queue_taskbar_button_update(bool update)
{
PostMessage(m_wnd, update ? MSG_UPDATE_TASKBAR_BUTTONS : MSG_CREATE_TASKBAR_BUTTONS, 0, 0);
Expand Down
14 changes: 12 additions & 2 deletions foo_ui_columns/main_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,26 @@ class MainWindow {
void set_title(const char* ptr);
bool update_taskbar_button_images() const;
void update_taskbar_buttons(bool update) const;
void save_focus_state();

pfc::string8 m_window_title;
wil::com_ptr<ITaskbarList3> m_taskbar_list;
HWND m_wnd{};
HWND m_last_focused_wnd{};
HMONITOR m_monitor{};
user_interface::HookProc_t m_hook_proc{};
bool m_should_handle_multimedia_keys{true};
bool m_shell_hook_registered{};
ULONG_PTR m_gdiplus_instance{NULL};
bool m_gdiplus_initialised{false};
bool m_gdiplus_initialised{};
bool m_is_destroying{};
bool m_last_sysray_r_down{};
bool m_last_sysray_x1_down{};
bool m_last_sysray_x2_down{};
ULONG_PTR m_gdiplus_instance{};
UINT m_wm_taskbarcreated{};
UINT m_wm_taskbarbuttoncreated{};
UINT m_wm_shellhookmessage{};

wil::unique_himagelist m_taskbar_button_images;
};

Expand Down
117 changes: 62 additions & 55 deletions foo_ui_columns/mw_wnd_proc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ service_ptr_t<contextmenu_manager> g_main_nowplaying;
} // namespace systray_contextmenus

GetMsgHook g_get_msg_hook;
static HWND wnd_last;

LRESULT cui::MainWindow::s_on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp) noexcept
{
Expand All @@ -58,32 +57,22 @@ LRESULT cui::MainWindow::s_on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)

LRESULT cui::MainWindow::on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
{
static UINT WM_TASKBARCREATED;
static UINT WM_TASKBARBUTTONCREATED;
static UINT WM_SHELLHOOKMESSAGE;
static bool g_last_sysray_r_down;
static bool g_last_sysray_x1_down;
static bool g_last_sysray_x2_down;
static HWND g_wnd_focused_before_menu;

if (m_hook_proc) {
LRESULT ret;
if (m_hook_proc(wnd, msg, wp, lp, &ret)) {
return ret;
}
}

// ermm we should probably use some kind of class so we can initialise this as a const value
if (WM_TASKBARCREATED && msg == WM_TASKBARCREATED) {
if (m_wm_taskbarcreated && msg == m_wm_taskbarcreated) {
if (g_icon_created) {
g_icon_created = false;
create_systray_icon();
update_systray();
}
// return 0;
}

if (WM_TASKBARBUTTONCREATED && msg == WM_TASKBARBUTTONCREATED) {
if (m_wm_taskbarbuttoncreated && msg == m_wm_taskbarbuttoncreated) {
m_taskbar_list = wil::CoCreateInstanceNoThrow<ITaskbarList3>(CLSID_TaskbarList);
if (m_taskbar_list && SUCCEEDED(m_taskbar_list->HrInit())) {
const int cx = GetSystemMetrics(SM_CXSMICON);
Expand All @@ -100,7 +89,7 @@ LRESULT cui::MainWindow::on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
}
}

if (WM_SHELLHOOKMESSAGE && msg == WM_SHELLHOOKMESSAGE && m_should_handle_multimedia_keys) {
if (m_wm_shellhookmessage && msg == m_wm_shellhookmessage && m_should_handle_multimedia_keys) {
if (wp == HSHELL_APPCOMMAND) {
const auto cmd = GET_APPCOMMAND_LPARAM(lp);

Expand Down Expand Up @@ -131,13 +120,13 @@ LRESULT cui::MainWindow::on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)

switch (msg) {
case WM_CREATE: {
WM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated");
WM_TASKBARBUTTONCREATED = RegisterWindowMessage(L"TaskbarButtonCreated");
m_wm_taskbarcreated = RegisterWindowMessage(L"TaskbarCreated");
m_wm_taskbarbuttoncreated = RegisterWindowMessage(L"TaskbarButtonCreated");
m_wnd = wnd;
m_monitor = MonitorFromWindow(wnd, MONITOR_DEFAULTTONEAREST);

if (m_should_handle_multimedia_keys) {
WM_SHELLHOOKMESSAGE = RegisterWindowMessage(TEXT("SHELLHOOK"));
m_wm_shellhookmessage = RegisterWindowMessage(TEXT("SHELLHOOK"));
m_shell_hook_registered = RegisterShellHookWindow(wnd) != 0;
}

Expand All @@ -162,7 +151,8 @@ LRESULT cui::MainWindow::on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
}

return 0;
case WM_DESTROY: {
case WM_DESTROY:
m_is_destroying = true;
g_get_msg_hook.deregister_hook();
g_layout_window.destroy();
if (m_shell_hook_registered)
Expand All @@ -174,7 +164,8 @@ LRESULT cui::MainWindow::on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
RevokeDragDrop(m_wnd);
destroy_systray_icon();
on_destroy();
} break;
m_is_destroying = false;
break;
case WM_NCDESTROY:
m_taskbar_button_images.reset();
break;
Expand Down Expand Up @@ -249,38 +240,54 @@ LRESULT cui::MainWindow::on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
RedrawWindow(wnd, nullptr, nullptr, RDW_ALLCHILDREN | RDW_ERASE | RDW_INVALIDATE | RDW_FRAME);
break;
case WM_ACTIVATE: {
if ((LOWORD(wp) == WA_INACTIVE)) {
if (!uih::are_keyboard_cues_enabled())
SendMessage(wnd, WM_UPDATEUISTATE, MAKEWPARAM(UIS_SET, UISF_HIDEFOCUS), NULL);
wnd_last = GetFocus();
if (!rebar::g_rebar_window
|| !rebar::g_rebar_window->get_previous_menu_focus_window(g_wnd_focused_before_menu))
g_wnd_focused_before_menu = g_layout_window.get_previous_menu_focus_window();

if (rebar::g_rebar_window)
rebar::g_rebar_window->hide_accelerators();
g_layout_window.hide_menu_access_keys();
}
} break;
case WM_SETFOCUS: {
HWND wnd_focus = g_wnd_focused_before_menu ? g_wnd_focused_before_menu : wnd_last;
if (wnd_focus && IsWindow(wnd_focus))
SetFocus(wnd_focus);
const auto is_minimised = HIWORD(wp);
const auto state = LOWORD(wp);

if (m_is_destroying || state != WA_INACTIVE)
return 0;

if (!is_minimised)
save_focus_state();

if (!uih::are_keyboard_cues_enabled())
SendMessage(wnd, WM_UPDATEUISTATE, MAKEWPARAM(UIS_SET, UISF_HIDEFOCUS), NULL);

if (rebar::g_rebar_window)
rebar::g_rebar_window->hide_accelerators();

g_layout_window.hide_menu_access_keys();

return 0;
}
case WM_SETFOCUS:
if (m_is_destroying)
break;

if (m_last_focused_wnd && IsWindow(m_last_focused_wnd))
SetFocus(m_last_focused_wnd);
else
g_layout_window.set_focus();

// wnd_last = 0; // meh minimised fuko
} break;
break;
case WM_SYSCOMMAND:
if (wp == SC_KEYMENU && !lp) {
if (!HIBYTE(GetKeyState(VK_CONTROL))) // Workaround for obscure OS bug involving global keyboard shortcuts
{
if (rebar::g_rebar_window && rebar::g_rebar_window->set_menu_focus())
g_layout_window.hide_menu_access_keys();
else
g_layout_window.set_menu_focus();
}
switch (wp) {
case SC_KEYMENU:
if (lp)
break;

// Workaround for obscure OS bug involving global keyboard shortcuts
if (HIBYTE(GetKeyState(VK_CONTROL)))
break;

if (rebar::g_rebar_window && rebar::g_rebar_window->set_menu_focus())
g_layout_window.hide_menu_access_keys();
else
g_layout_window.set_menu_focus();

return 0;
case SC_MINIMIZE:
if (GetForegroundWindow() == wnd)
save_focus_state();
break;
}
break;
case WM_MENUCHAR: {
Expand Down Expand Up @@ -555,7 +562,7 @@ LRESULT cui::MainWindow::on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
// if (b_wasDown)
standard_commands::main_activate_or_hide();
} else if (lp == WM_RBUTTONDOWN) {
g_last_sysray_r_down = true;
m_last_sysray_r_down = true;
}
#if 0
/* There was some misbehaviour with the newer messages. So we don't use them. */
Expand All @@ -567,24 +574,24 @@ LRESULT cui::MainWindow::on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
}
#endif
else if (lp == WM_XBUTTONDOWN) {
g_last_sysray_x1_down = HIBYTE(GetKeyState(VK_XBUTTON1)) != 0;
g_last_sysray_x2_down = HIBYTE(GetKeyState(VK_XBUTTON2)) != 0;
m_last_sysray_x1_down = HIBYTE(GetKeyState(VK_XBUTTON1)) != 0;
m_last_sysray_x2_down = HIBYTE(GetKeyState(VK_XBUTTON2)) != 0;
return TRUE;
} else if (lp == WM_MOUSEMOVE) {
} else if (lp == WM_XBUTTONUP) {
if (config::advbool_system_tray_icon_x_buttons.get()) {
if (g_last_sysray_x1_down && !g_last_sysray_x2_down)
if (m_last_sysray_x1_down && !m_last_sysray_x2_down)
standard_commands::main_previous();
if (g_last_sysray_x2_down && !g_last_sysray_x1_down)
if (m_last_sysray_x2_down && !m_last_sysray_x1_down)
standard_commands::main_next();
}
g_last_sysray_x1_down = false;
g_last_sysray_x2_down = false;
m_last_sysray_x1_down = false;
m_last_sysray_x2_down = false;
return TRUE;
}
// else if (lp == WM_CONTEXTMENU)
else if (lp == WM_RBUTTONUP) {
if (g_last_sysray_r_down) {
if (m_last_sysray_r_down) {
SetForegroundWindow(wnd);

POINT pt; // = {(short)LOWORD(lp),(short)HIWORD(lp)};
Expand Down

0 comments on commit 420ba66

Please sign in to comment.