diff options
author | Timur Sultanov <SultanovTS@yandex.ru> | 2022-01-18 16:00:49 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-02-03 00:47:22 +0100 |
commit | 68a01f0e273675ba225e29c1522d997a5d898e61 (patch) | |
tree | fbf78f3de670fde5069d9be67aee3b9a287b3439 /Userland/Services | |
parent | 181d1e2dd6afd89d8e56f9aa7effd3dbca08b2f2 (diff) | |
download | serenity-68a01f0e273675ba225e29c1522d997a5d898e61.zip |
WindowManager: Basic support for system keymap switching
Diffstat (limited to 'Userland/Services')
-rw-r--r-- | Userland/Services/WindowServer/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Services/WindowServer/KeymapSwitcher.cpp | 99 | ||||
-rw-r--r-- | Userland/Services/WindowServer/KeymapSwitcher.h | 37 | ||||
-rw-r--r-- | Userland/Services/WindowServer/WindowManager.cpp | 6 | ||||
-rw-r--r-- | Userland/Services/WindowServer/WindowManager.h | 2 | ||||
-rw-r--r-- | Userland/Services/WindowServer/main.cpp | 8 |
6 files changed, 150 insertions, 3 deletions
diff --git a/Userland/Services/WindowServer/CMakeLists.txt b/Userland/Services/WindowServer/CMakeLists.txt index 154beb9ad8..f412145ea4 100644 --- a/Userland/Services/WindowServer/CMakeLists.txt +++ b/Userland/Services/WindowServer/CMakeLists.txt @@ -36,6 +36,7 @@ set(SOURCES WindowManagerServerEndpoint.h WindowManagerClientEndpoint.h WMClientConnection.cpp + KeymapSwitcher.cpp ) serenity_bin(WindowServer) diff --git a/Userland/Services/WindowServer/KeymapSwitcher.cpp b/Userland/Services/WindowServer/KeymapSwitcher.cpp new file mode 100644 index 0000000000..e34fdb3e0c --- /dev/null +++ b/Userland/Services/WindowServer/KeymapSwitcher.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021, Timur Sultanov <SultanovTS@yandex.ru> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/JsonObject.h> +#include <LibCore/File.h> +#include <WindowServer/KeymapSwitcher.h> +#include <spawn.h> +#include <unistd.h> + +namespace WindowServer { + +static KeymapSwitcher* s_the; + +KeymapSwitcher& KeymapSwitcher::the() +{ + VERIFY(s_the); + return *s_the; +} + +KeymapSwitcher::KeymapSwitcher() +{ + s_the = this; +} + +KeymapSwitcher::~KeymapSwitcher() +{ +} + +void KeymapSwitcher::refresh() +{ + m_keymaps.clear(); + + //TODO: load keymaps from file + m_keymaps.append("en-us"); + m_keymaps.append("ru"); +} + +void KeymapSwitcher::next_keymap() +{ + refresh(); + + if (m_keymaps.is_empty()) { + dbgln("No keymaps loaded - leaving system keymap unchanged"); + return; // TODO: figure out what to do when there is no keymap configured + } + + auto current_keymap_name = get_current_keymap(); + + dbgln("Current system keymap: {}", current_keymap_name); + + auto it = m_keymaps.find_if([&](const auto& enumerator) { + return enumerator == current_keymap_name; + }); + + if (it.is_end()) { + auto first_keymap = m_keymaps.first(); + dbgln("Cannot find current keymap in the keymap list - setting first available ({})", first_keymap); + setkeymap(first_keymap); + } else { + it++; + + if (it.is_end()) { + it = m_keymaps.begin(); + } + + dbgln("Setting system keymap to: {}", *it); + setkeymap(*it); + } +} + +String KeymapSwitcher::get_current_keymap() const +{ + auto proc_keymap = Core::File::construct("/proc/keymap"); + if (!proc_keymap->open(Core::OpenMode::ReadOnly)) + VERIFY_NOT_REACHED(); + + auto json = JsonValue::from_string(proc_keymap->read_all()).release_value_but_fixme_should_propagate_errors(); + auto const& keymap_object = json.as_object(); + VERIFY(keymap_object.has("keymap")); + auto keymap = keymap_object.get("keymap").to_string(); + dbgln("Current keymap is: {}", keymap); + + return keymap; +} + +void KeymapSwitcher::setkeymap(const AK::String& keymap) +{ + pid_t child_pid; + const char* argv[] = { "/bin/keymap", keymap.characters(), nullptr }; + if ((errno = posix_spawn(&child_pid, "/bin/keymap", nullptr, nullptr, const_cast<char**>(argv), environ))) { + perror("posix_spawn"); + dbgln("Failed to call /bin/keymap, error: {} ({})", errno, strerror(errno)); + } +} + +} diff --git a/Userland/Services/WindowServer/KeymapSwitcher.h b/Userland/Services/WindowServer/KeymapSwitcher.h new file mode 100644 index 0000000000..c9f6a0b77c --- /dev/null +++ b/Userland/Services/WindowServer/KeymapSwitcher.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021, Timur Sultanov <SultanovTS@yandex.ru> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/String.h> +#include <AK/Vector.h> +#include <AK/WeakPtr.h> +#include <LibCore/Object.h> +#include <LibKeyboard/CharacterMap.h> + +namespace WindowServer { + +class KeymapSwitcher final : public Core::Object { + C_OBJECT(KeymapSwitcher) +public: + static KeymapSwitcher& the(); + + virtual ~KeymapSwitcher() override; + + void refresh(); + + void next_keymap(); + +private: + KeymapSwitcher(); + + Vector<AK::String> m_keymaps; + + void setkeymap(AK::String const&); + String get_current_keymap() const; +}; + +} diff --git a/Userland/Services/WindowServer/WindowManager.cpp b/Userland/Services/WindowServer/WindowManager.cpp index 0739d86c9e..b9b8db61fc 100644 --- a/Userland/Services/WindowServer/WindowManager.cpp +++ b/Userland/Services/WindowServer/WindowManager.cpp @@ -36,6 +36,7 @@ WindowManager& WindowManager::the() WindowManager::WindowManager(Gfx::PaletteImpl const& palette) : m_switcher(WindowSwitcher::construct()) + , m_keymap_switcher(KeymapSwitcher::construct()) , m_palette(palette) { s_the = this; @@ -1557,6 +1558,11 @@ void WindowManager::process_key_event(KeyEvent& event) return; } + if (event.type() == Event::KeyDown && (event.modifiers() == (Mod_Alt | Mod_Shift) && (event.key() == Key_Shift || event.key() == Key_Alt))) { + m_keymap_switcher->next_keymap(); + return; + } + if (event.type() == Event::KeyDown && (event.modifiers() == (Mod_Ctrl | Mod_Alt) || event.modifiers() == (Mod_Ctrl | Mod_Shift | Mod_Alt)) && (window_stack_columns() > 1 || window_stack_rows() > 1)) { auto& current_stack = current_window_stack(); auto row = current_stack.row(); diff --git a/Userland/Services/WindowServer/WindowManager.h b/Userland/Services/WindowServer/WindowManager.h index 4b2eb47d3c..d7f8214222 100644 --- a/Userland/Services/WindowServer/WindowManager.h +++ b/Userland/Services/WindowServer/WindowManager.h @@ -19,6 +19,7 @@ #include <LibGfx/Rect.h> #include <WindowServer/Cursor.h> #include <WindowServer/Event.h> +#include <WindowServer/KeymapSwitcher.h> #include <WindowServer/MenuManager.h> #include <WindowServer/ScreenLayout.h> #include <WindowServer/WMClientConnection.h> @@ -433,6 +434,7 @@ private: u8 m_keyboard_modifiers { 0 }; NonnullRefPtr<WindowSwitcher> m_switcher; + NonnullRefPtr<KeymapSwitcher> m_keymap_switcher; WeakPtr<Button> m_cursor_tracking_button; WeakPtr<Button> m_hovered_button; diff --git a/Userland/Services/WindowServer/main.cpp b/Userland/Services/WindowServer/main.cpp index 60fcac658a..9697fda608 100644 --- a/Userland/Services/WindowServer/main.cpp +++ b/Userland/Services/WindowServer/main.cpp @@ -21,17 +21,19 @@ ErrorOr<int> serenity_main(Main::Arguments) { - TRY(Core::System::pledge("stdio video thread sendfd recvfd accept rpath wpath cpath unix proc sigaction")); + TRY(Core::System::pledge("stdio video thread sendfd recvfd accept rpath wpath cpath unix proc sigaction exec")); TRY(Core::System::unveil("/res", "r")); TRY(Core::System::unveil("/tmp", "cw")); TRY(Core::System::unveil("/etc/WindowServer.ini", "rwc")); TRY(Core::System::unveil("/dev", "rw")); + TRY(Core::System::unveil("/bin/keymap", "x")); + TRY(Core::System::unveil("/proc/keymap", "r")); struct sigaction act = {}; 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")); + TRY(Core::System::pledge("stdio video thread sendfd recvfd accept rpath wpath cpath unix proc exec")); auto wm_config = Core::ConfigFile::open("/etc/WindowServer.ini"); auto theme_name = wm_config->read_entry("Theme", "Name", "Default"); @@ -49,7 +51,7 @@ ErrorOr<int> serenity_main(Main::Arguments) WindowServer::EventLoop loop; - TRY(Core::System::pledge("stdio video thread sendfd recvfd accept rpath wpath cpath proc")); + TRY(Core::System::pledge("stdio video thread sendfd recvfd accept rpath wpath cpath proc exec")); // First check which screens are explicitly configured { |