WindowServer: Fix alt shortcut navigation for non-default keymaps

Some keymaps will bind key presses with the alt modifier to characters
other than the unmodified one, in which case you couldn't activate the
alt shortcuts in the menu bar before.

We now ask the current keymap for the code point that is mapped to the
pressed (unmodified) key instead.
This commit is contained in:
Julian Offenhäuser 2023-03-20 20:45:36 +01:00 committed by Sam Atkins
parent e59137d4f6
commit e32ab161ae
Notes: sideshowbarker 2024-07-16 23:54:15 +09:00
3 changed files with 30 additions and 17 deletions

View file

@ -45,5 +45,5 @@ set(GENERATED_SOURCES
)
serenity_bin(WindowServer)
target_link_libraries(WindowServer PRIVATE LibCore LibFileSystem LibGfx LibThreading LibIPC LibMain)
target_link_libraries(WindowServer PRIVATE LibCore LibFileSystem LibKeyboard LibGfx LibThreading LibIPC LibMain)
serenity_install_headers(Services/WindowServer)

View file

@ -19,6 +19,7 @@
#include <LibCore/Account.h>
#include <LibCore/ProcessStatisticsReader.h>
#include <LibCore/SessionManagement.h>
#include <LibKeyboard/CharacterMap.h>
namespace WindowServer {
@ -516,20 +517,32 @@ void Window::handle_keydown_event(KeyEvent const& event)
return;
}
if (event.modifiers() == Mod_Alt && event.code_point() && m_menubar.has_menus()) {
Menu* menu_to_open = nullptr;
m_menubar.for_each_menu([&](Menu& menu) {
if (to_ascii_lowercase(menu.alt_shortcut_character()) == to_ascii_lowercase(event.code_point())) {
menu_to_open = &menu;
return IterationDecision::Break;
}
return IterationDecision::Continue;
});
// When handling alt shortcuts, we only care about the key that has been pressed in addition
// to alt, not the code point that has been mapped to alt+[key], so we have to look up the
// scancode directly from the "unmodified" character map.
auto character_map_or_error = Keyboard::CharacterMap::fetch_system_map();
if (!character_map_or_error.is_error()) {
auto& character_map = character_map_or_error.value();
if (menu_to_open) {
frame().open_menubar_menu(*menu_to_open);
if (!menu_to_open->is_empty())
menu_to_open->set_hovered_index(0);
return;
// The lowest byte serves as our index into the character table.
auto index = event.scancode() & 0xff;
u32 character = to_ascii_lowercase(character_map.character_map_data().map[index]);
Menu* menu_to_open = nullptr;
m_menubar.for_each_menu([&](Menu& menu) {
if (to_ascii_lowercase(menu.alt_shortcut_character()) == character) {
menu_to_open = &menu;
return IterationDecision::Break;
}
return IterationDecision::Continue;
});
if (menu_to_open) {
frame().open_menubar_menu(*menu_to_open);
if (!menu_to_open->is_empty())
menu_to_open->set_hovered_index(0);
return;
}
}
}
m_client->async_key_down(m_window_id, (u32)event.code_point(), (u32)event.key(), event.modifiers(), (u32)event.scancode());

View file

@ -25,7 +25,7 @@ RefPtr<Core::ConfigFile> g_config;
ErrorOr<int> serenity_main(Main::Arguments)
{
TRY(Core::System::pledge("stdio video thread sendfd recvfd accept rpath wpath cpath unix proc sigaction exec tty"));
TRY(Core::System::pledge("stdio video thread sendfd recvfd accept rpath wpath cpath unix proc getkeymap sigaction exec tty"));
TRY(Core::System::unveil("/res", "r"));
TRY(Core::System::unveil("/tmp", "cw"));
TRY(Core::System::unveil("/etc/WindowServer.ini", "rwc"));
@ -42,7 +42,7 @@ ErrorOr<int> serenity_main(Main::Arguments)
act.sa_flags = SA_NOCLDWAIT;
act.sa_handler = SIG_IGN;
TRY(Core::System::sigaction(SIGCHLD, &act, nullptr));
TRY(Core::System::pledge("stdio video thread sendfd recvfd accept rpath wpath cpath unix proc exec tty"));
TRY(Core::System::pledge("stdio video thread sendfd recvfd accept rpath wpath cpath unix proc getkeymap exec tty"));
WindowServer::g_config = TRY(Core::ConfigFile::open("/etc/WindowServer.ini", Core::ConfigFile::AllowWriting::Yes));
auto theme_name = WindowServer::g_config->read_entry("Theme", "Name", "Default");
@ -73,7 +73,7 @@ ErrorOr<int> serenity_main(Main::Arguments)
WindowServer::EventLoop loop;
TRY(Core::System::pledge("stdio video thread sendfd recvfd accept rpath wpath cpath unix proc exec"));
TRY(Core::System::pledge("stdio video thread sendfd recvfd accept rpath wpath cpath unix proc getkeymap exec"));
// First check which screens are explicitly configured
{