Serenity Operating System
at master 112 lines 3.2 kB view raw
1/* 2 * Copyright (c) 2021, Timur Sultanov <SultanovTS@yandex.ru> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/JsonObject.h> 8#include <LibCore/ConfigFile.h> 9#include <LibCore/DeprecatedFile.h> 10#include <LibCore/Process.h> 11#include <WindowServer/KeymapSwitcher.h> 12#include <spawn.h> 13#include <unistd.h> 14 15namespace WindowServer { 16 17KeymapSwitcher::KeymapSwitcher() 18{ 19 m_file_watcher = MUST(Core::FileWatcher::create()); 20 21 m_file_watcher->on_change = [this](auto&) { 22 refresh(); 23 }; 24 25 MUST(m_file_watcher->add_watch(m_keyboard_config, Core::FileWatcherEvent::Type::ContentModified)); 26 27 refresh(); 28} 29 30void KeymapSwitcher::refresh() 31{ 32 m_keymaps.clear(); 33 34 auto mapper_config(Core::ConfigFile::open(m_keyboard_config).release_value_but_fixme_should_propagate_errors()); 35 auto keymaps = mapper_config->read_entry("Mapping", "Keymaps", ""); 36 37 auto keymaps_vector = keymaps.split(','); 38 39 for (auto& keymap : keymaps_vector) { 40 m_keymaps.append(keymap); 41 } 42 43 if (m_keymaps.is_empty()) { 44 dbgln("Empty list of keymaps - adding default (en-us)"); 45 m_keymaps.append("en-us"); 46 } 47 48 auto current_keymap = get_current_keymap(); 49 50 // Refresh might indicate that some external program has changed the keymap, 51 // so better notify our clients that we may have a new keymap 52 if (on_keymap_change) 53 on_keymap_change(current_keymap); 54 55 if (m_keymaps.find(current_keymap).is_end()) { 56 set_keymap(m_keymaps.first()); 57 } 58} 59 60void KeymapSwitcher::next_keymap() 61{ 62 if (m_keymaps.is_empty()) { 63 dbgln("No keymaps loaded - leaving system keymap unchanged"); 64 return; // TODO: figure out what to do when there is no keymap configured 65 } 66 67 auto current_keymap_name = get_current_keymap(); 68 69 dbgln("Current system keymap: {}", current_keymap_name); 70 71 auto it = m_keymaps.find_if([&](auto const& enumerator) { 72 return enumerator == current_keymap_name; 73 }); 74 75 if (it.is_end()) { 76 auto first_keymap = m_keymaps.first(); 77 dbgln("Cannot find current keymap in the keymap list - setting first available ({})", first_keymap); 78 set_keymap(first_keymap); 79 } else { 80 it++; 81 82 if (it.is_end()) { 83 it = m_keymaps.begin(); 84 } 85 86 dbgln("Setting system keymap to: {}", *it); 87 set_keymap(*it); 88 } 89} 90 91DeprecatedString KeymapSwitcher::get_current_keymap() const 92{ 93 auto proc_keymap = Core::DeprecatedFile::construct("/sys/kernel/keymap"); 94 if (!proc_keymap->open(Core::OpenMode::ReadOnly)) 95 VERIFY_NOT_REACHED(); 96 97 auto json = JsonValue::from_string(proc_keymap->read_all()).release_value_but_fixme_should_propagate_errors(); 98 auto const& keymap_object = json.as_object(); 99 VERIFY(keymap_object.has_string("keymap"sv)); 100 return keymap_object.get_deprecated_string("keymap"sv).value(); 101} 102 103void KeymapSwitcher::set_keymap(const AK::DeprecatedString& keymap) 104{ 105 if (Core::Process::spawn("/bin/keymap"sv, Array { "-m", keymap.characters() }).is_error()) 106 dbgln("Failed to call /bin/keymap, error: {} ({})", errno, strerror(errno)); 107 108 if (on_keymap_change) 109 on_keymap_change(keymap); 110} 111 112}