diff --git a/debian/libmiral7.symbols b/debian/libmiral7.symbols index 6283670beb..0cf455d4e5 100644 --- a/debian/libmiral7.symbols +++ b/debian/libmiral7.symbols @@ -492,6 +492,14 @@ libmiral.so.7 libmiral7 #MINVER# (c++)"miral::InputConfiguration::~InputConfiguration()@MIRAL_5.1" 5.1.0 (c++)"miral::WindowManagerTools::move_cursor_to(mir::geometry::generic::Point)@MIRAL_5.1" 5.1.0 MIRAL_5.2@MIRAL_5.2 5.2.0 + (c++)"miral::InputConfiguration::Keyboard::Keyboard()@MIRAL_5.2" 5.2.0 + (c++)"miral::InputConfiguration::Keyboard::Keyboard(miral::InputConfiguration::Keyboard const&)@MIRAL_5.2" 5.2.0 + (c++)"miral::InputConfiguration::Keyboard::operator=(miral::InputConfiguration::Keyboard)@MIRAL_5.2" 5.2.0 + (c++)"miral::InputConfiguration::Keyboard::set_repeat_delay(int)@MIRAL_5.2" 5.2.0 + (c++)"miral::InputConfiguration::Keyboard::set_repeat_rate(int)@MIRAL_5.2" 5.2.0 + (c++)"miral::InputConfiguration::Keyboard::~Keyboard()@MIRAL_5.2" 5.2.0 + (c++)"miral::InputConfiguration::keyboard()@MIRAL_5.2" 5.2.0 + (c++)"miral::InputConfiguration::keyboard(miral::InputConfiguration::Keyboard const&)@MIRAL_5.2" 5.2.0 (c++)"miral::MinimalWindowManager::MinimalWindowManager(miral::WindowManagerTools const&, MirInputEventModifier, miral::FocusStealing)@MIRAL_5.0" 5.2.0 (c++)"miral::MinimalWindowManager::MinimalWindowManager(miral::WindowManagerTools const&, miral::FocusStealing)@MIRAL_5.0" 5.2.0 (c++)"miral::WindowManagementPolicy::~WindowManagementPolicy()@MIRAL_5.0" 5.2.0 diff --git a/examples/mir_demo_server/server_example.cpp b/examples/mir_demo_server/server_example.cpp index feaf166756..fbebb15315 100644 --- a/examples/mir_demo_server/server_example.cpp +++ b/examples/mir_demo_server/server_example.cpp @@ -18,6 +18,7 @@ #include "server_example_input_filter.h" #include "server_example_test_client.h" +#include #include #include #include @@ -33,12 +34,14 @@ #include "mir/options/option.h" #include "mir/report_exception.h" #include "mir/server.h" +#include "mir/log.h" #include #include #include #include +#include namespace mir { class AbnormalExit; } @@ -120,14 +123,24 @@ try miral::MirRunner runner{argc, argv, "mir/mir_demo_server.config"}; miral::InputConfiguration input_configuration; + auto mouse = input_configuration.mouse(); + auto touchpad = input_configuration.touchpad(); + auto keyboard = input_configuration.keyboard(); + std::mutex config_mutex; + + auto config_applier = [&] mutable + { + input_configuration.mouse(mouse); + input_configuration.touchpad(touchpad); + input_configuration.keyboard(keyboard); + }; miral::ConfigFile test{runner, "mir_demo_server.input", miral::ConfigFile::Mode::reload_on_change, - [&input_configuration](auto& in, auto path) + [&](auto& in, auto path) { std::cout << "** Reloading: " << path << std::endl; - auto mouse = input_configuration.mouse(); - auto touchpad = input_configuration.touchpad(); + std::lock_guard lock{config_mutex}; for (std::string line; std::getline(in, line);) { @@ -146,11 +159,53 @@ try touchpad.scroll_mode(mir_touchpad_scroll_mode_edge_scroll); if (line == "mir_touchpad_scroll_mode_button_down_scroll") touchpad.scroll_mode(mir_touchpad_scroll_mode_button_down_scroll); + + if (line.contains("=")) + { + auto const eq = line.find_first_of("="); + auto const key = line.substr(0, eq); + auto const value = line.substr(eq+1); + + auto const parse_and_validate = [](std::string const& key, std::string_view val) -> std::optional + { + auto const int_val = std::atoi(val.data()); + if (int_val < 0) + { + mir::log_warning( + "Config value %s does not support negative values. Ignoring the supplied value (%d)...", + key.c_str(), int_val); + return std::nullopt; + } + + return int_val; + }; + + if (key == "repeat_rate") + { + auto const parsed = parse_and_validate(key, value); + if (parsed) + keyboard.set_repeat_rate(*parsed); + } + + if (key == "repeat_delay") + { + auto const parsed = parse_and_validate(key, value); + if (parsed) + keyboard.set_repeat_delay(*parsed); + } + } } - input_configuration.mouse(mouse); - input_configuration.touchpad(touchpad); + + config_applier(); }}; + runner.add_start_callback( + [&] + { + std::lock_guard lock{config_mutex}; + config_applier(); + }); + runner.set_exception_handler(exception_handler); std::function shutdown_hook{[]{}}; diff --git a/include/miral/miral/input_configuration.h b/include/miral/miral/input_configuration.h index 960e71c24e..a51e591e28 100644 --- a/include/miral/miral/input_configuration.h +++ b/include/miral/miral/input_configuration.h @@ -40,11 +40,14 @@ class InputConfiguration class Mouse; class Touchpad; + class Keyboard; auto mouse() -> Mouse; void mouse(Mouse const& val); auto touchpad() -> Touchpad; void touchpad(Touchpad const& val); + auto keyboard() -> Keyboard; + void keyboard(Keyboard const& val); private: class Self; @@ -115,6 +118,27 @@ class InputConfiguration::Touchpad void scroll_mode(std::optionalconst& val); void tap_to_click(std::optionalconst& val); +private: + friend class InputConfiguration::Self; + class Self; + std::shared_ptr self; +}; + +/** Input configuration for keyboard devices + * \remark Since MirAL 5.3 + */ +class InputConfiguration::Keyboard +{ +public: + Keyboard(); + ~Keyboard(); + + Keyboard(Keyboard const& that); + auto operator=(Keyboard that) -> Keyboard&; + + void set_repeat_rate(int new_rate); + void set_repeat_delay(int new_delay); + private: friend class InputConfiguration::Self; class Self; diff --git a/include/server/mir/shell/keyboard_helper.h b/include/server/mir/shell/keyboard_helper.h new file mode 100644 index 0000000000..3be9e04d17 --- /dev/null +++ b/include/server/mir/shell/keyboard_helper.h @@ -0,0 +1,34 @@ +/* + * Copyright © Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MIR_SHELL_KEYBOARD_HELPER_ +#define MIR_SHELL_KEYBOARD_HELPER_ + +#include +namespace mir +{ +namespace shell +{ +class KeyboardHelper +{ +public: + virtual ~KeyboardHelper() = default; + virtual void repeat_info_changed(std::optional rate, int delay) const = 0; +}; +} +} + +#endif diff --git a/src/include/server/mir/default_server_configuration.h b/src/include/server/mir/default_server_configuration.h index cfd82d2c71..4f8f00edbc 100644 --- a/src/include/server/mir/default_server_configuration.h +++ b/src/include/server/mir/default_server_configuration.h @@ -64,6 +64,7 @@ class SurfaceStack; namespace shell { +class AccessibilityManager; class DisplayConfigurationController; class InputTargeter; class FocusController; @@ -281,6 +282,7 @@ class DefaultServerConfiguration : public virtual ServerConfiguration virtual std::shared_ptr the_persistent_surface_store(); virtual std::shared_ptr the_shell_report(); + virtual std::shared_ptr the_accessibility_manager(); /** @} */ /** @name internal scene configuration @@ -430,6 +432,7 @@ class DefaultServerConfiguration : public virtual ServerConfiguration CachedPtr shared_library_prober_report; CachedPtr shell; CachedPtr shell_report; + CachedPtr accessibility_manager; CachedPtr decoration_manager; CachedPtr application_not_responding_detector; CachedPtr cookie_authority; diff --git a/src/include/server/mir/server.h b/src/include/server/mir/server.h index 6cad0f1c1c..5e47b47682 100644 --- a/src/include/server/mir/server.h +++ b/src/include/server/mir/server.h @@ -43,6 +43,7 @@ class SessionAuthorizer; } namespace shell { +class AccessibilityManager; class DisplayLayout; class DisplayConfigurationController; class FocusController; @@ -438,6 +439,9 @@ class Server auto the_token_authority() const -> std::shared_ptr; + + auto the_accessibility_manager() const -> + std::shared_ptr; /** @} */ /** @name Client side support diff --git a/src/include/server/mir/shell/accessibility_manager.h b/src/include/server/mir/shell/accessibility_manager.h new file mode 100644 index 0000000000..1e56c1af86 --- /dev/null +++ b/src/include/server/mir/shell/accessibility_manager.h @@ -0,0 +1,54 @@ +/* + * Copyright © Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MIR_SHELL_ACCESSIBILITY_MANAGER_H +#define MIR_SHELL_ACCESSIBILITY_MANAGER_H + +#include +#include +#include + +namespace mir +{ +namespace shell +{ +class KeyboardHelper; +class AccessibilityManager +{ +public: + void register_keyboard_helper(std::shared_ptr const&); + + std::optional repeat_rate() const; + int repeat_delay() const; + + void repeat_rate(int new_rate); + void repeat_delay(int new_rate); + void override_key_repeat_settings(bool enable); + + void notify_helpers() const; + +private: + std::vector> keyboard_helpers; + + // 25 rate and 600 delay are the default in Weston and Sway + int repeat_rate_{25}; + int repeat_delay_{600}; + bool enable_key_repeat{true}; +}; +} +} + +#endif diff --git a/src/miral/input_configuration.cpp b/src/miral/input_configuration.cpp index 69a7f1176d..100f07a5fd 100644 --- a/src/miral/input_configuration.cpp +++ b/src/miral/input_configuration.cpp @@ -17,7 +17,9 @@ #include "miral/input_configuration.h" #include "input_device_config.h" +#include "mir/shell/accessibility_manager.h" +#include #include #include @@ -35,16 +37,25 @@ class miral::InputConfiguration::Touchpad::Self : public TouchpadInputConfigurat using TouchpadInputConfiguration::operator=; }; +class miral::InputConfiguration::Keyboard::Self : public KeyboardInputConfiguration +{ + friend class miral::InputConfiguration::Self; + using KeyboardInputConfiguration::operator=; +}; + class miral::InputConfiguration::Self { public: std::weak_ptr input_device_hub{}; std::shared_ptr input_device_config; + std::shared_ptr accessibility_manager; auto mouse() -> Mouse; void mouse(Mouse const& val); auto touchpad() -> Touchpad; void touchpad(Touchpad const& val); + auto keyboard() -> Keyboard; + void keyboard(Keyboard const& val); void apply(Mouse const& m) { @@ -71,6 +82,20 @@ class miral::InputConfiguration::Self touchpad(t); } + + void apply(Keyboard const& k) + { + if(accessibility_manager) + { + if (k.self->repeat_rate) + accessibility_manager->repeat_rate(*k.self->repeat_rate); + if (k.self->repeat_delay) + accessibility_manager->repeat_delay(*k.self->repeat_delay); + + accessibility_manager->notify_helpers(); + } + keyboard(k); + } }; auto miral::InputConfiguration::Self::mouse() -> Mouse @@ -109,6 +134,23 @@ void miral::InputConfiguration::Self::touchpad(Touchpad const& val) } } +auto miral::InputConfiguration::Self::keyboard() -> Keyboard { + Keyboard result; + if (input_device_config) + { + *result.self = input_device_config->keyboard(); + } + return result; +} + +void miral::InputConfiguration::Self::keyboard(Keyboard const& val) +{ + if (input_device_config) + { + input_device_config->keyboard(*val.self); + } +} + miral::InputConfiguration::InputConfiguration() : self{std::make_shared()} { @@ -127,6 +169,7 @@ void miral::InputConfiguration::operator()(mir::Server& server) { self->input_device_hub = server.the_input_device_hub(); self->input_device_config = InputDeviceConfig::the_input_configuration(server.get_options()); + self->accessibility_manager = server.the_accessibility_manager(); }); } @@ -145,6 +188,16 @@ void miral::InputConfiguration::touchpad(Touchpad const& t) self->apply(t); } +auto miral::InputConfiguration::keyboard() -> Keyboard +{ + return self->keyboard(); +} + +void miral::InputConfiguration::keyboard(Keyboard const& k) +{ + self->apply(k); +} + miral::InputConfiguration::Mouse::Mouse() : self{std::make_unique()} { @@ -321,3 +374,29 @@ void miral::InputConfiguration::Touchpad::tap_to_click(std::optional const { self->tap_to_click = val; } + +miral::InputConfiguration::Keyboard::Keyboard() : + self{std::make_unique()} +{ +} + +miral::InputConfiguration::Keyboard::~Keyboard() = default; + +miral::InputConfiguration::Keyboard::Keyboard(Keyboard const& that) : + self{std::make_unique(*that.self)} +{ +} + +auto miral::InputConfiguration::Keyboard::operator=(Keyboard that) -> Keyboard& +{ + std::swap(self, that.self); + return *this; +} + +void miral::InputConfiguration::Keyboard::set_repeat_rate(int new_rate) { + self->repeat_rate = new_rate; +} + +void miral::InputConfiguration::Keyboard::set_repeat_delay(int new_delay) { + self->repeat_delay = new_delay; +} diff --git a/src/miral/input_device_config.cpp b/src/miral/input_device_config.cpp index a7390ac756..2e2b5b6af9 100644 --- a/src/miral/input_device_config.cpp +++ b/src/miral/input_device_config.cpp @@ -322,6 +322,11 @@ auto miral::InputDeviceConfig::touchpad() const -> TouchpadInputConfiguration return touchpad_config; } +auto miral::InputDeviceConfig::keyboard() const -> KeyboardInputConfiguration +{ + return keyboard_config; +} + void miral::InputDeviceConfig::mouse(MouseInputConfiguration const& val) { mouse_config = val; @@ -332,6 +337,11 @@ void miral::InputDeviceConfig::touchpad(TouchpadInputConfiguration const& val) touchpad_config = val; } +void miral::InputDeviceConfig::keyboard(KeyboardInputConfiguration const& val) +{ + keyboard_config = val; +} + void miral::TouchpadInputConfiguration::apply_to(mi::Device& device) const { if (contains(device.capabilities(), mi::DeviceCapability::touchpad)) diff --git a/src/miral/input_device_config.h b/src/miral/input_device_config.h index 85280f8096..a90938632a 100644 --- a/src/miral/input_device_config.h +++ b/src/miral/input_device_config.h @@ -54,6 +54,13 @@ class TouchpadInputConfiguration std::optional middle_button_emulation; }; +class KeyboardInputConfiguration +{ +public: + std::optional repeat_rate; + std::optional repeat_delay; +}; + class InputDeviceConfig : public mir::input::InputDeviceObserver { public: @@ -67,14 +74,17 @@ class InputDeviceConfig : public mir::input::InputDeviceObserver auto mouse() const -> MouseInputConfiguration; auto touchpad() const -> TouchpadInputConfiguration; + auto keyboard() const -> KeyboardInputConfiguration; void mouse(MouseInputConfiguration const& val); void touchpad(TouchpadInputConfiguration const& val); + void keyboard(KeyboardInputConfiguration const& val); private: explicit InputDeviceConfig(std::shared_ptr const& options); MouseInputConfiguration mouse_config; TouchpadInputConfiguration touchpad_config; + KeyboardInputConfiguration keyboard_config; }; } diff --git a/src/miral/symbols.map b/src/miral/symbols.map index 29624e3027..1ff71b58c7 100644 --- a/src/miral/symbols.map +++ b/src/miral/symbols.map @@ -506,3 +506,16 @@ global: }; } MIRAL_5.0; +MIRAL_5.2 { +global: + extern "C++" { + miral::InputConfiguration::Keyboard::?Keyboard*; + miral::InputConfiguration::Keyboard::Keyboard*; + miral::InputConfiguration::Keyboard::config_changed*; + miral::InputConfiguration::Keyboard::operator*; + miral::InputConfiguration::Keyboard::set_repeat_delay*; + miral::InputConfiguration::Keyboard::set_repeat_rate*; + miral::InputConfiguration::keyboard*; + typeinfo?for?miral::InputConfiguration::Keyboard; + }; +} MIRAL_5.1; diff --git a/src/server/frontend_wayland/input_method_grab_keyboard_v2.h b/src/server/frontend_wayland/input_method_grab_keyboard_v2.h index cea041a4b2..bdee629e94 100644 --- a/src/server/frontend_wayland/input_method_grab_keyboard_v2.h +++ b/src/server/frontend_wayland/input_method_grab_keyboard_v2.h @@ -54,7 +54,7 @@ class InputMethodGrabKeyboardV2 class Handler; std::shared_ptr const handler; - std::unique_ptr const helper; + std::shared_ptr const helper; wayland::Weak wl_client; /// KeyboardImpl overrides diff --git a/src/server/frontend_wayland/keyboard_helper.cpp b/src/server/frontend_wayland/keyboard_helper.cpp index bb343bc449..f2016efcfe 100644 --- a/src/server/frontend_wayland/keyboard_helper.cpp +++ b/src/server/frontend_wayland/keyboard_helper.cpp @@ -33,7 +33,8 @@ mf::KeyboardHelper::KeyboardHelper( KeyboardCallbacks* callbacks, std::shared_ptr const& initial_keymap, std::shared_ptr const& seat, - bool enable_key_repeat) + std::optional default_repeat_rate, + int default_repeat_delay) : callbacks{callbacks}, mir_seat{seat}, current_keymap{nullptr}, // will be set later in the constructor by set_keymap() @@ -51,11 +52,11 @@ mf::KeyboardHelper::KeyboardHelper( */ set_keymap(initial_keymap); - // 25 rate and 600 delay are the default in Weston and Sway - // At some point we will want to make this configurable - callbacks->send_repeat_info(enable_key_repeat ? 25 : 0, 600); + repeat_info_changed(default_repeat_rate, default_repeat_delay); } +mf::KeyboardHelper::~KeyboardHelper() = default; + void mf::KeyboardHelper::handle_event(std::shared_ptr const& event) { switch (mir_input_event_get_type(mir_event_get_input_event(event.get()))) @@ -102,6 +103,11 @@ void mf::KeyboardHelper::refresh_modifiers() set_modifiers(mir_seat->xkb_modifiers()); } +void mf::KeyboardHelper::repeat_info_changed(std::optional rate, int delay) const +{ + callbacks->send_repeat_info(rate.value_or(0), delay); +} + void mf::KeyboardHelper::handle_keyboard_event(std::shared_ptr const& event) { auto const action = mir_keyboard_event_action(event.get()); diff --git a/src/server/frontend_wayland/keyboard_helper.h b/src/server/frontend_wayland/keyboard_helper.h index 61653c4771..3cb656cf1e 100644 --- a/src/server/frontend_wayland/keyboard_helper.h +++ b/src/server/frontend_wayland/keyboard_helper.h @@ -17,9 +17,11 @@ #ifndef MIR_FRONTEND_KEYBOARD_HELPER_H #define MIR_FRONTEND_KEYBOARD_HELPER_H +#include "mir/shell/keyboard_helper.h" #include "wayland_wrapper.h" #include "mir/events/xkb_modifiers.h" +#include #include #include @@ -38,9 +40,14 @@ namespace input class Keymap; class Seat; } +namespace shell +{ +class AccessibilityManager; +} namespace frontend { +class WlSeat; class KeyboardCallbacks { public: @@ -57,14 +64,10 @@ class KeyboardCallbacks KeyboardCallbacks& operator=(KeyboardCallbacks const&) = delete; }; -class KeyboardHelper +class KeyboardHelper : public mir::shell::KeyboardHelper { public: - KeyboardHelper( - KeyboardCallbacks* keybaord_impl, - std::shared_ptr const& initial_keymap, - std::shared_ptr const& seat, - bool enable_key_repeat); + ~KeyboardHelper() override; void handle_event(std::shared_ptr const& event); @@ -73,7 +76,18 @@ class KeyboardHelper /// Updates the modifiers from the seat void refresh_modifiers(); + void repeat_info_changed(std::optional rate, int delay) const override; + private: + friend class mir::frontend::WlSeat; + friend class mir::shell::AccessibilityManager; + KeyboardHelper( + KeyboardCallbacks* keybaord_impl, + std::shared_ptr const& initial_keymap, + std::shared_ptr const& seat, + std::optional default_repeat_rate, + int default_repeat_delay); + void handle_keyboard_event(std::shared_ptr const& event); void set_keymap(std::shared_ptr const& new_keymap); void set_modifiers(MirXkbModifiers const& new_modifiers); diff --git a/src/server/frontend_wayland/wayland_connector.cpp b/src/server/frontend_wayland/wayland_connector.cpp index 5c7a90e45d..1c9e6db43b 100644 --- a/src/server/frontend_wayland/wayland_connector.cpp +++ b/src/server/frontend_wayland/wayland_connector.cpp @@ -241,7 +241,7 @@ mf::WaylandConnector::WaylandConnector( bool arw_socket, std::unique_ptr extensions_, WaylandProtocolExtensionFilter const& extension_filter, - bool enable_key_repeat, + std::shared_ptr const& accessibility_manager, std::shared_ptr const& session_lock, std::shared_ptr const& decoration_strategy, std::shared_ptr const& session_coordinator, @@ -297,7 +297,7 @@ mf::WaylandConnector::WaylandConnector( input_hub, keyboard_observer_registrar, seat, - enable_key_repeat); + accessibility_manager); output_manager = std::make_unique( display.get(), executor, diff --git a/src/server/frontend_wayland/wayland_connector.h b/src/server/frontend_wayland/wayland_connector.h index f2b3fc634b..415c330e9f 100644 --- a/src/server/frontend_wayland/wayland_connector.h +++ b/src/server/frontend_wayland/wayland_connector.h @@ -60,6 +60,7 @@ class DisplayConfigurationObserver; namespace shell { class Shell; +class AccessibilityManager; } namespace scene { @@ -168,7 +169,7 @@ class WaylandConnector : public Connector bool arw_socket, std::unique_ptr extensions, WaylandProtocolExtensionFilter const& extension_filter, - bool enable_key_repeat, + std::shared_ptr const& accessibility_manager, std::shared_ptr const& session_lock, std::shared_ptr const& decoration_strategy, std::shared_ptr const& session_coordinator, diff --git a/src/server/frontend_wayland/wayland_default_configuration.cpp b/src/server/frontend_wayland/wayland_default_configuration.cpp index 52e89f4cc4..dda2900a60 100644 --- a/src/server/frontend_wayland/wayland_default_configuration.cpp +++ b/src/server/frontend_wayland/wayland_default_configuration.cpp @@ -29,6 +29,7 @@ #include "input_method_v1.h" #include "input_method_v2.h" #include "layer_shell_v1.h" +#include "mir/shell/accessibility_manager.h" #include "mir_shell.h" #include "pointer_constraints_unstable_v1.h" #include "primary_selection_v1.h" @@ -367,6 +368,8 @@ std::shared_ptr enabled_wayland_extensions.end()}; auto const enable_repeat = options->get(options::enable_key_repeat_opt); + the_accessibility_manager()->override_key_repeat_settings(enable_repeat); + auto const x11_enabled = options->is_set(mo::x11_display_opt) && options->get(mo::x11_display_opt); return std::make_shared( @@ -395,7 +398,7 @@ std::shared_ptr x11_enabled, wayland_extension_hooks), wayland_extension_filter, - enable_repeat, + the_accessibility_manager(), the_session_lock(), the_decoration_strategy(), the_session_coordinator(), diff --git a/src/server/frontend_wayland/wl_keyboard.h b/src/server/frontend_wayland/wl_keyboard.h index 2456603281..425aed2015 100644 --- a/src/server/frontend_wayland/wl_keyboard.h +++ b/src/server/frontend_wayland/wl_keyboard.h @@ -44,7 +44,7 @@ class WlKeyboard void focus_on(WlSurface* surface); private: - std::unique_ptr const helper; + std::shared_ptr const helper; wayland::Weak focused_surface; /// KeyboardCallbacks overrides diff --git a/src/server/frontend_wayland/wl_seat.cpp b/src/server/frontend_wayland/wl_seat.cpp index d448409f24..08b0d1ca0c 100644 --- a/src/server/frontend_wayland/wl_seat.cpp +++ b/src/server/frontend_wayland/wl_seat.cpp @@ -35,6 +35,7 @@ #include "mir/input/mir_keyboard_config.h" #include "mir/input/keyboard_observer.h" #include "mir/scene/surface.h" +#include "mir/shell/accessibility_manager.h" #include "mir_toolkit/events/input/pointer_event.h" #include @@ -194,7 +195,7 @@ mf::WlSeat::WlSeat( std::shared_ptr const& input_hub, std::shared_ptr> const& keyboard_observer_registrar, std::shared_ptr const& seat, - bool enable_key_repeat) + std::shared_ptr const& accessibility_manager) : Global(display, Version<8>()), keymap{std::make_shared()}, config_observer{ @@ -213,7 +214,7 @@ mf::WlSeat::WlSeat( clock{clock}, input_hub{input_hub}, seat{seat}, - enable_key_repeat{enable_key_repeat} + accessibility_manager{accessibility_manager} { input_hub->add_observer(config_observer); keyboard_observer_registrar->register_interest(keyboard_observer, wayland_executor); @@ -250,9 +251,16 @@ void mf::WlSeat::for_each_listener(mw::Client* client, std::functionfor_each(client, func); } -auto mf::WlSeat::make_keyboard_helper(KeyboardCallbacks* callbacks) -> std::unique_ptr +auto mf::WlSeat::make_keyboard_helper(KeyboardCallbacks* callbacks) -> std::shared_ptr { - return std::make_unique(callbacks, keymap, seat, enable_key_repeat); + // https://wayland.app/protocols/wayland#wl_keyboard:event:repeat_info + // " A rate of zero will disable any repeating (regardless of the value of + // delay)." + auto const default_repeat_rate = accessibility_manager->repeat_rate(); + auto const default_repeat_delay = accessibility_manager->repeat_delay(); + auto const keyboard_helper = std::shared_ptr(new KeyboardHelper(callbacks, keymap, seat, default_repeat_rate, default_repeat_delay)); + accessibility_manager->register_keyboard_helper(keyboard_helper); + return keyboard_helper; } void mf::WlSeat::bind(wl_resource* new_wl_seat) diff --git a/src/server/frontend_wayland/wl_seat.h b/src/server/frontend_wayland/wl_seat.h index 7d4ae12028..c732a68fac 100644 --- a/src/server/frontend_wayland/wl_seat.h +++ b/src/server/frontend_wayland/wl_seat.h @@ -20,8 +20,6 @@ #include "wayland_wrapper.h" #include "mir/wayland/weak.h" -#include -#include #include struct MirPointerEvent; @@ -38,6 +36,10 @@ class Seat; class Keymap; class KeyboardObserver; } +namespace shell +{ +class AccessibilityManager; +} namespace time { class Clock; @@ -76,7 +78,7 @@ class WlSeat : public wayland::Seat::Global std::shared_ptr const& input_hub, std::shared_ptr> const& keyboard_observer_registrar, std::shared_ptr const& seat, - bool enable_key_repeat); + std::shared_ptr const& accessibility_manager); ~WlSeat(); @@ -99,7 +101,7 @@ class WlSeat : public wayland::Seat::Global FocusListener& operator=(FocusListener const&) = delete; }; - auto make_keyboard_helper(KeyboardCallbacks* callbacks) -> std::unique_ptr; + auto make_keyboard_helper(KeyboardCallbacks* callbacks) -> std::shared_ptr; /// Adds the listener for future use, and makes a call into it to inform of initial state void add_focus_listener(wayland::Client* client, FocusListener* listener); @@ -133,7 +135,8 @@ class WlSeat : public wayland::Seat::Global std::shared_ptr const clock; std::shared_ptr const input_hub; std::shared_ptr const seat; - bool const enable_key_repeat; + + std::shared_ptr const accessibility_manager; void bind(wl_resource* new_wl_seat) override; }; diff --git a/src/server/server.cpp b/src/server/server.cpp index b2cede8b22..62fb396b9d 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -134,7 +134,8 @@ struct TemporaryCompositeEventFilter : public mi::CompositeEventFilter MACRO(the_decoration_strategy)\ MACRO(the_input_device_registry)\ MACRO(the_idle_handler)\ - MACRO(the_token_authority) + MACRO(the_token_authority)\ + MACRO(the_accessibility_manager) #define MIR_SERVER_BUILDER(name)\ std::function()> name##_builder; diff --git a/src/server/shell/CMakeLists.txt b/src/server/shell/CMakeLists.txt index c5f8a450d2..325cc59fd1 100644 --- a/src/server/shell/CMakeLists.txt +++ b/src/server/shell/CMakeLists.txt @@ -16,6 +16,7 @@ set( surface_stack_wrapper.cpp ${CMAKE_SOURCE_DIR}/src/include/server/mir/shell/surface_stack_wrapper.h basic_idle_handler.cpp ${CMAKE_SOURCE_DIR}/src/include/server/mir/shell/idle_handler.h token_authority.cpp ${CMAKE_SOURCE_DIR}/src/include/server/mir/shell/token_authority.h + accessibility_manager.cpp ${CMAKE_SOURCE_DIR}/src/include/server/mir/shell/accessibility_manager.h ) add_library( diff --git a/src/server/shell/accessibility_manager.cpp b/src/server/shell/accessibility_manager.cpp new file mode 100644 index 0000000000..636eb43eb8 --- /dev/null +++ b/src/server/shell/accessibility_manager.cpp @@ -0,0 +1,53 @@ +/* + * Copyright © Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "mir/shell/accessibility_manager.h" +#include "mir/shell/keyboard_helper.h" + +#include + +void mir::shell::AccessibilityManager::register_keyboard_helper(std::shared_ptr const& helper) +{ + keyboard_helpers.push_back(helper); +} + +std::optional mir::shell::AccessibilityManager::repeat_rate() const { + if(!enable_key_repeat) + return {}; + return repeat_rate_; +} + +int mir::shell::AccessibilityManager::repeat_delay() const { + return repeat_delay_; +} + +void mir::shell::AccessibilityManager::repeat_rate(int new_rate) { + repeat_rate_ = new_rate; +} + +void mir::shell::AccessibilityManager::repeat_delay(int new_delay) { + repeat_delay_ = new_delay; +} + +void mir::shell::AccessibilityManager::override_key_repeat_settings(bool enable) +{ + enable_key_repeat = enable; +} + +void mir::shell::AccessibilityManager::notify_helpers() const { + for(auto const& helper: keyboard_helpers) + helper->repeat_info_changed(repeat_rate(), repeat_delay()); +} diff --git a/src/server/shell/default_configuration.cpp b/src/server/shell/default_configuration.cpp index 6e74e4b20e..996102da03 100644 --- a/src/server/shell/default_configuration.cpp +++ b/src/server/shell/default_configuration.cpp @@ -14,20 +14,22 @@ * along with this program. If not, see . */ -#include -#include #include "mir/default_server_configuration.h" -#include "mir/abnormal_exit.h" +#include "basic_idle_handler.h" +#include "decoration/basic_decoration.h" +#include "decoration/basic_manager.h" +#include "default_persistent_surface_store.h" +#include "graphics_display_layout.h" + +#include "mir/abnormal_exit.h" #include "mir/input/composite_event_filter.h" -#include "mir/shell/abstract_shell.h" +#include "mir/main_loop.h" #include "mir/options/configuration.h" #include "mir/options/option.h" -#include "default_persistent_surface_store.h" -#include "graphics_display_layout.h" -#include "decoration/basic_manager.h" -#include "decoration/basic_decoration.h" -#include "basic_idle_handler.h" +#include "mir/shell/abstract_shell.h" +#include "mir/shell/accessibility_manager.h" +#include "mir/shell/system_compositor_window_manager.h" #include "mir/shell/token_authority.h" namespace ms = mir::scene; @@ -182,3 +184,13 @@ mir::DefaultServerConfiguration::the_shell_display_layout() return std::make_shared(the_display()); }); } + +auto mir::DefaultServerConfiguration::the_accessibility_manager() -> std::shared_ptr +{ + return accessibility_manager( + [] + { + return std::make_shared(); + }); +} + diff --git a/src/server/symbols.map b/src/server/symbols.map index ea4eea7a10..f26032d788 100644 --- a/src/server/symbols.map +++ b/src/server/symbols.map @@ -19,6 +19,7 @@ global: mir::DefaultServerConfiguration::set_enabled_wayland_extensions*; mir::DefaultServerConfiguration::set_the_decoration_strategy*; mir::DefaultServerConfiguration::set_wayland_extension_filter*; + mir::DefaultServerConfiguration::the_accessibility_manager*; mir::DefaultServerConfiguration::the_application_not_responding_detector*; mir::DefaultServerConfiguration::the_buffer_allocator*; mir::DefaultServerConfiguration::the_clock*; @@ -190,6 +191,7 @@ global: mir::Server::set_wayland_extension_filter*; mir::Server::stop*; mir::Server::supported_pixel_formats*; + mir::Server::the_accessibility_manager*; mir::Server::the_application_not_responding_detector*; mir::Server::the_composite_event_filter*; mir::Server::the_compositor*; @@ -621,6 +623,11 @@ global: mir::shell::AbstractShell::surface_at*; mir::shell::AbstractShell::surface_ready*; mir::shell::AbstractShell::swap_z_order*; + mir::shell::AccessibilityManager::notify_helpers*; + mir::shell::AccessibilityManager::override_key_repeat_settings*; + mir::shell::AccessibilityManager::register_keyboard_helper*; + mir::shell::AccessibilityManager::repeat_delay*; + mir::shell::AccessibilityManager::repeat_rate*; mir::shell::DefaultWindowManager::handle_keyboard_event*; mir::shell::DisplayConfigurationController::?DisplayConfigurationController*; mir::shell::DisplayConfigurationController::DisplayConfigurationController*; @@ -710,6 +717,7 @@ global: non-virtual?thunk?to?mir::DefaultServerConfiguration::set_enabled_wayland_extensions*; non-virtual?thunk?to?mir::DefaultServerConfiguration::set_the_decoration_strategy*; non-virtual?thunk?to?mir::DefaultServerConfiguration::set_wayland_extension_filter*; + non-virtual?thunk?to?mir::DefaultServerConfiguration::the_accessibility_manager*; non-virtual?thunk?to?mir::DefaultServerConfiguration::the_application_not_responding_detector*; non-virtual?thunk?to?mir::DefaultServerConfiguration::the_buffer_allocator*; non-virtual?thunk?to?mir::DefaultServerConfiguration::the_clock*; @@ -1194,6 +1202,7 @@ global: typeinfo?for?mir::scene::TextInputState; typeinfo?for?mir::scene::TextInputStateObserver; typeinfo?for?mir::shell::AbstractShell; + typeinfo?for?mir::shell::AccessibilityManager; typeinfo?for?mir::shell::DefaultWindowManager; typeinfo?for?mir::shell::DisplayConfigurationController; typeinfo?for?mir::shell::DisplayLayout;