From 9e21b3f216447d502413bcb8ca7c504ca8211d5d Mon Sep 17 00:00:00 2001 From: sbcohen2000 Date: Mon, 12 Dec 2022 13:35:55 -0600 Subject: [PATCH] KeyboardSettings: Add checkbox to enable Caps Lock mapping to Ctrl This patch adds an additional control to KeyboardSettings allowing the user to map Caps Lock to Ctrl. Previously, this was only possible by writing to /sys/kernel/variables/caps_lock_to_ctrl. Writing to /sys/kernel/variables/caps_lock_to_ctrl requires root privileges, but KeyboardSettings will not attempt to elevate the privilege of the user if they are not root. Instead, the checkbox is rendered as un-editable. --- .../KeyboardSettings/Keyboard.gml | 14 ++++++++ .../KeyboardSettingsWidget.cpp | 32 +++++++++++++++++++ .../KeyboardSettings/KeyboardSettingsWidget.h | 5 +++ .../Applications/KeyboardSettings/main.cpp | 2 ++ 4 files changed, 53 insertions(+) diff --git a/Userland/Applications/KeyboardSettings/Keyboard.gml b/Userland/Applications/KeyboardSettings/Keyboard.gml index 89ee28391d..a1b5588678 100644 --- a/Userland/Applications/KeyboardSettings/Keyboard.gml +++ b/Userland/Applications/KeyboardSettings/Keyboard.gml @@ -124,4 +124,18 @@ name: "num_lock_checkbox" } } + + @GUI::GroupBox { + title: "Caps Lock" + fixed_height: 60 + layout: @GUI::HorizontalBoxLayout { + margins: [16, 8, 8] + spacing: 16 + } + + @GUI::CheckBox { + text: "Use Caps Lock as an additional Ctrl" + name: "caps_lock_remapped_to_ctrl_checkbox" + } + } } diff --git a/Userland/Applications/KeyboardSettings/KeyboardSettingsWidget.cpp b/Userland/Applications/KeyboardSettings/KeyboardSettingsWidget.cpp index 842018a569..eb97fa661f 100644 --- a/Userland/Applications/KeyboardSettings/KeyboardSettingsWidget.cpp +++ b/Userland/Applications/KeyboardSettings/KeyboardSettingsWidget.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2020, Hüseyin Aslıtürk * Copyright (c) 2021-2023, Sam Atkins + * Copyright (c) 2022, Sam Cohen * Copyright (c) 2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause @@ -255,6 +256,19 @@ KeyboardSettingsWidget::KeyboardSettingsWidget() m_num_lock_checkbox->on_checked = [&](auto) { set_modified(true); }; + + m_caps_lock_checkbox = find_descendant_of_type_named("caps_lock_remapped_to_ctrl_checkbox"); + auto caps_lock_is_remapped = read_caps_lock_to_ctrl_sys_variable(); + if (caps_lock_is_remapped.is_error()) { + auto error_message = DeprecatedString::formatted("Could not determine if Caps Lock is remapped to Ctrl: {}", caps_lock_is_remapped.error()); + GUI::MessageBox::show_error(window(), error_message); + } else { + m_caps_lock_checkbox->set_checked(caps_lock_is_remapped.value()); + } + m_caps_lock_checkbox->set_enabled(getuid() == 0); + m_caps_lock_checkbox->on_checked = [&](auto) { + set_modified(true); + }; } KeyboardSettingsWidget::~KeyboardSettingsWidget() @@ -282,6 +296,7 @@ void KeyboardSettingsWidget::apply_settings() } m_initial_active_keymap = m_keymaps_list_model.active_keymap(); Config::write_bool("KeyboardSettings"sv, "StartupEnable"sv, "NumLock"sv, m_num_lock_checkbox->is_checked()); + write_caps_lock_to_ctrl_sys_variable(m_caps_lock_checkbox->is_checked()); } void KeyboardSettingsWidget::set_keymaps(Vector const& keymaps, DeprecatedString const& active_keymap) @@ -289,3 +304,20 @@ void KeyboardSettingsWidget::set_keymaps(Vector const& keymaps auto keymaps_string = DeprecatedString::join(',', keymaps); GUI::Process::spawn_or_show_error(window(), "/bin/keymap"sv, Array { "-s", keymaps_string.characters(), "-m", active_keymap.characters() }); } + +void KeyboardSettingsWidget::write_caps_lock_to_ctrl_sys_variable(bool caps_lock_to_ctrl) +{ + if (getuid() != 0) + return; + + auto write_command = DeprecatedString::formatted("caps_lock_to_ctrl={}", caps_lock_to_ctrl ? "1" : "0"); + GUI::Process::spawn_or_show_error(window(), "/bin/sysctl"sv, Array { "-w", write_command.characters() }); +} + +ErrorOr KeyboardSettingsWidget::read_caps_lock_to_ctrl_sys_variable() +{ + auto file = TRY(Core::File::open("/sys/kernel/variables/caps_lock_to_ctrl"sv, Core::File::OpenMode::Read)); + auto buffer = TRY(file->read_until_eof()); + StringView contents_string((char const*)buffer.data(), min(1, buffer.size())); + return contents_string == "1"; +} diff --git a/Userland/Applications/KeyboardSettings/KeyboardSettingsWidget.h b/Userland/Applications/KeyboardSettings/KeyboardSettingsWidget.h index ff2dba31b9..25720b49d7 100644 --- a/Userland/Applications/KeyboardSettings/KeyboardSettingsWidget.h +++ b/Userland/Applications/KeyboardSettings/KeyboardSettingsWidget.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -28,6 +29,9 @@ private: void set_keymaps(Vector const& keymaps, DeprecatedString const& active_keymap); + void write_caps_lock_to_ctrl_sys_variable(bool); + ErrorOr read_caps_lock_to_ctrl_sys_variable(); + Vector m_initial_keymap_list; DeprecatedString m_initial_active_keymap; @@ -35,6 +39,7 @@ private: RefPtr m_selected_keymaps_listview; RefPtr m_active_keymap_label; RefPtr m_num_lock_checkbox; + RefPtr m_caps_lock_checkbox; RefPtr m_activate_keymap_button; RefPtr m_add_keymap_button; RefPtr m_remove_keymap_button; diff --git a/Userland/Applications/KeyboardSettings/main.cpp b/Userland/Applications/KeyboardSettings/main.cpp index 3d8fcb491e..b34c2ba13d 100644 --- a/Userland/Applications/KeyboardSettings/main.cpp +++ b/Userland/Applications/KeyboardSettings/main.cpp @@ -27,7 +27,9 @@ ErrorOr serenity_main(Main::Arguments arguments) TRY(Core::System::pledge("stdio rpath recvfd sendfd proc exec")); TRY(Core::System::unveil("/res", "r")); TRY(Core::System::unveil("/bin/keymap", "x")); + TRY(Core::System::unveil("/bin/sysctl", "x")); TRY(Core::System::unveil("/sys/kernel/keymap", "r")); + TRY(Core::System::unveil("/sys/kernel/variables/caps_lock_to_ctrl", "r")); TRY(Core::System::unveil("/etc/Keyboard.ini", "r")); TRY(Core::System::unveil(nullptr, nullptr));