From 769a6ce9876849a2de7bde76f304c224f4129400 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Thu, 16 Nov 2023 19:16:03 +0100 Subject: [PATCH] touch_keyboard: use dialog API Fixes #5059 --- .../gems/src/app/touch_keyboard/child_state.h | 124 ------- repos/gems/src/app/touch_keyboard/gui.h | 141 -------- .../app/touch_keyboard/input_event_handler.h | 28 -- repos/gems/src/app/touch_keyboard/main.cc | 302 +++--------------- repos/gems/src/app/touch_keyboard/report.h | 89 ------ repos/gems/src/app/touch_keyboard/target.mk | 4 +- .../touch_keyboard/touch_keyboard_dialog.cc | 144 --------- .../touch_keyboard/touch_keyboard_dialog.h | 208 ------------ .../touch_keyboard/touch_keyboard_widget.cc | 77 +++++ .../touch_keyboard/touch_keyboard_widget.h | 235 ++++++++++++++ repos/gems/src/app/touch_keyboard/types.h | 21 -- 11 files changed, 361 insertions(+), 1012 deletions(-) delete mode 100644 repos/gems/src/app/touch_keyboard/child_state.h delete mode 100644 repos/gems/src/app/touch_keyboard/gui.h delete mode 100644 repos/gems/src/app/touch_keyboard/input_event_handler.h delete mode 100644 repos/gems/src/app/touch_keyboard/report.h delete mode 100644 repos/gems/src/app/touch_keyboard/touch_keyboard_dialog.cc delete mode 100644 repos/gems/src/app/touch_keyboard/touch_keyboard_dialog.h create mode 100644 repos/gems/src/app/touch_keyboard/touch_keyboard_widget.cc create mode 100644 repos/gems/src/app/touch_keyboard/touch_keyboard_widget.h delete mode 100644 repos/gems/src/app/touch_keyboard/types.h diff --git a/repos/gems/src/app/touch_keyboard/child_state.h b/repos/gems/src/app/touch_keyboard/child_state.h deleted file mode 100644 index 712a14487a..0000000000 --- a/repos/gems/src/app/touch_keyboard/child_state.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * \brief Runtime state of a child hosted in the runtime subsystem - * \author Norman Feske - * \date 2018-09-03 - */ - -/* - * Copyright (C) 2018 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CHILD_STATE_H_ -#define _CHILD_STATE_H_ - -/* Genode includes */ -#include -#include -#include -#include -#include - -/* local includes */ -#include "types.h" - -namespace Touch_keyboard { struct Child_state; } - -struct Touch_keyboard::Child_state : Noncopyable -{ - private: - - using Start_name = String<128>; - - Registry::Element _element; - - Start_name const _name; - - Ram_quota const _initial_ram_quota; - Cap_quota const _initial_cap_quota; - - Ram_quota _ram_quota = _initial_ram_quota; - Cap_quota _cap_quota = _initial_cap_quota; - - struct Version { unsigned value; } _version { 0 }; - - public: - - /** - * Constructor - * - * \param ram_quota initial RAM quota - * \param cap_quota initial capability quota - */ - Child_state(Registry ®istry, Start_name const &name, - Ram_quota ram_quota, Cap_quota cap_quota) - : - _element(registry, *this), - _name(name), - _initial_ram_quota(ram_quota), _initial_cap_quota(cap_quota) - { } - - void trigger_restart() - { - _version.value++; - _ram_quota = _initial_ram_quota; - _cap_quota = _initial_cap_quota; - } - - void gen_start_node_version(Xml_generator &xml) const - { - if (_version.value) - xml.attribute("version", _version.value); - } - - void gen_start_node_content(Xml_generator &xml) const - { - xml.attribute("name", _name); - - gen_start_node_version(xml); - - xml.attribute("caps", _cap_quota.value); - xml.node("resource", [&] () { - xml.attribute("name", "RAM"); - Number_of_bytes const bytes(_ram_quota.value); - xml.attribute("quantum", String<64>(bytes)); }); - } - - /** - * Adapt runtime state information to the child - * - * This method responds to RAM and cap-resource requests by increasing - * the resource quotas as needed. - * - * \param child child node of the runtime'r state report - * \return true if runtime must be reconfigured so that the changes - * can take effect - */ - bool apply_child_state_report(Xml_node child) - { - bool result = false; - - if (child.attribute_value("name", Start_name()) != _name) - return false; - - if (child.has_sub_node("ram") && child.sub_node("ram").has_attribute("requested")) { - _ram_quota.value *= 2; - result = true; - } - - if (child.has_sub_node("caps") && child.sub_node("caps").has_attribute("requested")) { - _cap_quota.value += 100; - result = true; - } - - return result; - } - - Ram_quota ram_quota() const { return _ram_quota; } - - Start_name name() const { return _name; } -}; - -#endif /* _CHILD_STATE_H_ */ diff --git a/repos/gems/src/app/touch_keyboard/gui.h b/repos/gems/src/app/touch_keyboard/gui.h deleted file mode 100644 index 2934f64bb3..0000000000 --- a/repos/gems/src/app/touch_keyboard/gui.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * \brief GUI wrapper for monitoring the user input of GUI components - * \author Norman Feske - * \date 2020-01-12 - */ - -/* - * Copyright (C) 2020 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _GUI_H_ -#define _GUI_H_ - -/* Genode includes */ -#include -#include -#include - -/* local includes */ -#include - -namespace Gui { - - using namespace Genode; - - struct Session_component; -} - - -struct Gui::Session_component : Session_object -{ - Env &_env; - - Input_event_handler &_event_handler; - - Input::Seq_number &_global_seq_number; - - Gui::Connection _connection; - - Input::Session_component _input_component { _env, _env.ram() }; - - Signal_handler _input_handler { - _env.ep(), *this, &Session_component::_handle_input }; - - void _handle_input() - { - _connection.input()->for_each_event([&] (Input::Event ev) { - - /* - * Augment input stream with sequence numbers to correlate - * clicks with hover reports. - */ - if (ev.touch() || ev.touch_release()) { - _global_seq_number.value++; - _input_component.submit(_global_seq_number); - } - - /* - * Feed touch coordinates of primary finger as absolute motion to - * the menu view to trigger an update of the hover report. - */ - ev.handle_touch([&] (Input::Touch_id id, float x, float y) { - Input::Absolute_motion const xy { (int)x, (int)y }; - if (id.value == 0) - _input_component.submit(xy); }); - - _event_handler.handle_input_event(ev); - }); - } - - template - Session_component(Env &env, Input_event_handler &event_handler, - Input::Seq_number &global_seq_number, ARGS &&... args) - : - Session_object(args...), - _env(env), _event_handler(event_handler), - _global_seq_number(global_seq_number), - _connection(env, _label.string()) - { - _connection.input()->sigh(_input_handler); - _env.ep().manage(_input_component); - _input_component.event_queue().enabled(true); - } - - ~Session_component() { _env.ep().dissolve(_input_component); } - - void upgrade(Session::Resources const &resources) - { - _connection.upgrade(resources); - } - - Framebuffer::Session_capability framebuffer_session() override { - return _connection.framebuffer_session(); } - - Input::Session_capability input_session() override { - return _input_component.cap(); } - - View_handle create_view(View_handle parent) override { - return _connection.create_view(parent); } - - void destroy_view(View_handle view) override { - _connection.destroy_view(view); } - - View_handle view_handle(View_capability view_cap, View_handle handle) override { - return _connection.view_handle(view_cap, handle); } - - View_capability view_capability(View_handle view) override { - return _connection.view_capability(view); } - - void release_view_handle(View_handle view) override { - _connection.release_view_handle(view); } - - Dataspace_capability command_dataspace() override { - return _connection.command_dataspace(); } - - void execute() override { - _connection.execute(); } - - Framebuffer::Mode mode() override { - return _connection.mode(); } - - void mode_sigh(Signal_context_capability sigh) override { - _connection.mode_sigh(sigh); } - - void buffer(Framebuffer::Mode mode, bool use_alpha) override - { - /* - * Do not call 'Connection::buffer' to avoid paying session quota - * from our own budget. - */ - _connection.Client::buffer(mode, use_alpha); - } - - void focus(Capability session) override { - _connection.focus(session); } -}; - -#endif /* _GUI_H_ */ diff --git a/repos/gems/src/app/touch_keyboard/input_event_handler.h b/repos/gems/src/app/touch_keyboard/input_event_handler.h deleted file mode 100644 index 25329dcb52..0000000000 --- a/repos/gems/src/app/touch_keyboard/input_event_handler.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * \brief Interface for handling input events - * \author Norman Feske - * \date 2018-05-02 - */ - -/* - * Copyright (C) 2018 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INPUT_EVENT_HANDLER_H_ -#define _INPUT_EVENT_HANDLER_H_ - -/* Genode includes */ -#include -#include - -namespace Gui { struct Input_event_handler; } - -struct Gui::Input_event_handler : Genode::Interface -{ - virtual void handle_input_event(Input::Event const &) = 0; -}; - -#endif /* _INPUT_EVENT_HANDLER_H_ */ diff --git a/repos/gems/src/app/touch_keyboard/main.cc b/repos/gems/src/app/touch_keyboard/main.cc index 2b02e0a215..5ff2f4ee97 100644 --- a/repos/gems/src/app/touch_keyboard/main.cc +++ b/repos/gems/src/app/touch_keyboard/main.cc @@ -13,26 +13,23 @@ /* Genode includes */ #include -#include #include -#include -#include -#include -#include #include +#include +#include /* local includes */ -#include -#include -#include -#include +#include -namespace Touch_keyboard { struct Main; } +namespace Touch_keyboard { -struct Touch_keyboard::Main : Sandbox::Local_service_base::Wakeup, - Sandbox::State_handler, - Gui::Input_event_handler, - Dialog::Event_emitter + using namespace Dialog; + + struct Main; +} + + +struct Touch_keyboard::Main : Top_level_dialog { Env &_env; @@ -41,238 +38,43 @@ struct Touch_keyboard::Main : Sandbox::Local_service_base::Wakeup, Attached_rom_dataspace _config { _env, "config" }; Attached_rom_dataspace _layout { _env, "layout" }; - int _xpos = 0; - int _ypos = 0; - unsigned _min_width = 0; - unsigned _min_height = 0; - - bool _opaque = false; - Color _background { }; - - Registry _children { }; - - Child_state _menu_view_child_state { _children, "menu_view", - Ram_quota { 10*1024*1024 }, - Cap_quota { 200 } }; - /** - * Sandbox::State_handler - */ - void handle_sandbox_state() override - { - /* obtain current sandbox state */ - Buffered_xml state(_heap, "state", [&] (Xml_generator &xml) { - _sandbox.generate_state_report(xml); - }); - - bool reconfiguration_needed = false; - - state.with_xml_node([&] (Xml_node state) { - state.for_each_sub_node("child", [&] (Xml_node const &child) { - if (_menu_view_child_state.apply_child_state_report(child)) - reconfiguration_needed = true; }); }); - - if (reconfiguration_needed) - _update_sandbox_config(); - } - - Sandbox _sandbox { _env, *this }; - - typedef Sandbox::Local_service Gui_service; - - Gui_service _gui_service { _sandbox, *this }; - - typedef Sandbox::Local_service Rom_service; - - Rom_service _rom_service { _sandbox, *this }; - - typedef Sandbox::Local_service Report_service; - - Report_service _report_service { _sandbox, *this }; - - void _handle_hover(Xml_node const &node) - { - Input::Seq_number hover_seq { node.attribute_value("seq_number", 0U) }; - - node.with_optional_sub_node("dialog", [&] (Xml_node const &dialog) { - _dialog.handle_hover(hover_seq, dialog); }); - } - - Report::Session_component::Xml_handler
- _hover_handler { *this, &Main::_handle_hover }; - - Dialog _dialog { _env.ep(), _env.ram(), _env.rm(), _heap, *this }; - - void _generate_sandbox_config(Xml_generator &xml) const - { - xml.node("report", [&] () { - xml.attribute("child_ram", "yes"); - xml.attribute("child_caps", "yes"); - xml.attribute("delay_ms", 20*1000); - }); - xml.node("parent-provides", [&] () { - - auto service_node = [&] (char const *name) { - xml.node("service", [&] () { - xml.attribute("name", name); }); }; - - service_node("ROM"); - service_node("CPU"); - service_node("PD"); - service_node("LOG"); - service_node("File_system"); - service_node("Gui"); - service_node("Timer"); - service_node("Report"); - }); - - xml.node("start", [&] () { - _menu_view_child_state.gen_start_node_content(xml); - - xml.node("config", [&] () { - xml.attribute("xpos", _xpos); - xml.attribute("ypos", _ypos); - - if (_min_width) xml.attribute("width", _min_width); - if (_min_height) xml.attribute("height", _min_height); - - if (_opaque) xml.attribute("opaque", "yes"); - xml.attribute("background", String<20>(_background)); - - xml.node("report", [&] () { - xml.attribute("hover", "yes"); }); - - xml.node("libc", [&] () { - xml.attribute("stderr", "/dev/log"); }); - - xml.node("vfs", [&] () { - xml.node("tar", [&] () { - xml.attribute("name", "menu_view_styles.tar"); }); - xml.node("dir", [&] () { - xml.attribute("name", "dev"); - xml.node("log", [&] () { }); - }); - xml.node("dir", [&] () { - xml.attribute("name", "fonts"); - xml.node("fs", [&] () { - xml.attribute("label", "fonts"); - }); - }); - }); - }); - - xml.node("route", [&] () { - - xml.node("service", [&] () { - xml.attribute("name", "ROM"); - xml.attribute("label", "dialog"); - xml.node("local", [&] () { }); - }); - - xml.node("service", [&] () { - xml.attribute("name", "Report"); - xml.attribute("label", "hover"); - xml.node("local", [&] () { }); - }); - - xml.node("service", [&] () { - xml.attribute("name", "Gui"); - xml.node("local", [&] () { }); - }); - - xml.node("service", [&] () { - xml.attribute("name", "File_system"); - xml.attribute("label", "fonts"); - xml.node("parent", [&] () { - xml.attribute("label", "fonts"); }); - }); - - xml.node("any-service", [&] () { - xml.node("parent", [&] () { }); }); - }); - }); - } - - /** - * Sandbox::Local_service_base::Wakeup interface - */ - void wakeup_local_service() override - { - _rom_service.for_each_requested_session([&] (Rom_service::Request &request) { - - if (request.label == "menu_view -> dialog") - request.deliver_session(_dialog.rom_session); - else - request.deny(); - }); - - _report_service.for_each_requested_session([&] (Report_service::Request &request) { - - if (request.label == "menu_view -> hover") { - Report::Session_component &session = *new (_heap) - Report::Session_component(_env, _hover_handler, - _env.ep(), - request.resources, "", request.diag); - request.deliver_session(session); - } - }); - - _report_service.for_each_session_to_close([&] (Report::Session_component &session) { - - destroy(_heap, &session); - return Report_service::Close_response::CLOSED; - }); - - _gui_service.for_each_requested_session([&] (Gui_service::Request &request) { - - Gui::Session_component &session = *new (_heap) - Gui::Session_component(_env, *this, _global_input_seq_number, _env.ep(), - request.resources, "", request.diag); - - request.deliver_session(session); - }); - - _gui_service.for_each_upgraded_session([&] (Gui::Session_component &session, - Session::Resources const &amount) { - session.upgrade(amount); - return Gui_service::Upgrade_response::CONFIRMED; - }); - - _gui_service.for_each_session_to_close([&] (Gui::Session_component &session) { - - destroy(_heap, &session); - return Gui_service::Close_response::CLOSED; - }); - } + Hosted _keyboard { Id { "keyboard" }, _heap }; Event::Connection _event_connection { _env }; - /** - * Dialog::Event_emitter interface + Runtime _runtime { _env, _heap }; + + Runtime::View _view { _runtime, *this, Runtime::View::Attr { + .opaque = true, + .initial_ram = Ram_quota { 4*1024*1024 } + } }; + + /* + * Top_level_dialog interface */ - void emit_characters(Dialog::Emit const &characters) override + + void view(Scope<> &s) const override { s.widget(_keyboard); } + + void click(Clicked_at const &at) override { _keyboard.propagate(at); } + + void clack(Clacked_at const &at) override { - _event_connection.with_batch([&] (Event::Session_client::Batch &batch) { + _keyboard.propagate(at, [&] (Touch_keyboard_widget::Emit const &characters) { + _event_connection.with_batch([&] (Event::Session_client::Batch &batch) { - Utf8_ptr utf8_ptr(characters.string()); + Utf8_ptr utf8_ptr(characters.string()); - for (; utf8_ptr.complete(); utf8_ptr = utf8_ptr.next()) { + for (; utf8_ptr.complete(); utf8_ptr = utf8_ptr.next()) { - Codepoint c = utf8_ptr.codepoint(); - batch.submit( Input::Press_char { Input::KEY_UNKNOWN, c } ); - batch.submit( Input::Release { Input::KEY_UNKNOWN } ); - } + Codepoint c = utf8_ptr.codepoint(); + batch.submit( Input::Press_char { Input::KEY_UNKNOWN, c } ); + batch.submit( Input::Release { Input::KEY_UNKNOWN } ); + } + }); }); } - Input::Seq_number _global_input_seq_number { }; - - /** - * Gui::Input_event_handler interface - */ - void handle_input_event(Input::Event const &event) override - { - _dialog.handle_input_event(_global_input_seq_number, event); - } + void drag (Dragged_at const &) override { } void _handle_config() { @@ -281,38 +83,28 @@ struct Touch_keyboard::Main : Sandbox::Local_service_base::Wakeup, Xml_node const config = _config.xml(); - _xpos = (int)config.attribute_value("xpos", 0L); - _ypos = (int)config.attribute_value("ypos", 0L); + _view.xpos = (int)config.attribute_value("xpos", 0L); + _view.ypos = (int)config.attribute_value("ypos", 0L); - _min_width = config.attribute_value("min_width", 0U); - _min_height = config.attribute_value("min_height", 0U); + _view.min_width = config.attribute_value("min_width", 0U); + _view.min_height = config.attribute_value("min_height", 0U); - _opaque = config.attribute_value("opaque", false); - _background = config.attribute_value("background", Color(127, 127, 127, 255)); + _view.opaque = config.attribute_value("opaque", false); + _view.background = config.attribute_value("background", Color(127, 127, 127, 255)); - _dialog.configure(_layout.xml()); + _keyboard.configure(_layout.xml()); + + _runtime.update_view_config(); } Signal_handler
_config_handler { _env.ep(), *this, &Main::_handle_config }; - void _update_sandbox_config() - { - Buffered_xml const config { _heap, "config", [&] (Xml_generator &xml) { - _generate_sandbox_config(xml); } }; - - config.with_xml_node([&] (Xml_node const &config) { - _sandbox.apply_config(config); }); - } - - Main(Env &env) - : - _env(env) + Main(Env &env) : Top_level_dialog("touch_keyboard"), _env(env) { _config.sigh(_config_handler); _layout.sigh(_config_handler); _handle_config(); - _update_sandbox_config(); } }; diff --git a/repos/gems/src/app/touch_keyboard/report.h b/repos/gems/src/app/touch_keyboard/report.h deleted file mode 100644 index f9e402c1ca..0000000000 --- a/repos/gems/src/app/touch_keyboard/report.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * \brief Report session provided to the sandbox - * \author Norman Feske - * \date 2020-01-14 - */ - -/* - * Copyright (C) 2020 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _REPORT_H_ -#define _REPORT_H_ - -/* Genode includes */ -#include -#include - -namespace Report { - - using namespace Genode; - - struct Session_component; -} - - -class Report::Session_component : public Session_object -{ - public: - - struct Handler_base : Interface, Genode::Noncopyable - { - virtual void handle_report(char const *, size_t) = 0; - }; - - template - struct Xml_handler : Handler_base - { - T &_obj; - void (T::*_member) (Xml_node const &); - - Xml_handler(T &obj, void (T::*member)(Xml_node const &)) - : _obj(obj), _member(member) { } - - void handle_report(char const *start, size_t length) override - { - (_obj.*_member)(Xml_node(start, length)); - } - }; - - private: - - Attached_ram_dataspace _ds; - - Handler_base &_handler; - - - /******************************* - ** Report::Session interface ** - *******************************/ - - Dataspace_capability dataspace() override { return _ds.cap(); } - - void submit(size_t length) override - { - _handler.handle_report(_ds.local_addr(), - min(_ds.size(), length)); - } - - void response_sigh(Signal_context_capability) override { } - - size_t obtain_response() override { return 0; } - - public: - - template - Session_component(Env &env, Handler_base &handler, - Entrypoint &ep, Resources const &resources, - ARGS &&... args) - : - Session_object(ep, resources, args...), - _ds(env.ram(), env.rm(), resources.ram_quota.value), - _handler(handler) - { } -}; - -#endif /* _REPORT_H_ */ diff --git a/repos/gems/src/app/touch_keyboard/target.mk b/repos/gems/src/app/touch_keyboard/target.mk index 61da68e691..9643e87ed1 100644 --- a/repos/gems/src/app/touch_keyboard/target.mk +++ b/repos/gems/src/app/touch_keyboard/target.mk @@ -1,4 +1,4 @@ TARGET = touch_keyboard -SRC_CC = main.cc touch_keyboard_dialog.cc -LIBS += base sandbox +SRC_CC = main.cc touch_keyboard_widget.cc +LIBS += base sandbox dialog INC_DIR += $(PRG_DIR) diff --git a/repos/gems/src/app/touch_keyboard/touch_keyboard_dialog.cc b/repos/gems/src/app/touch_keyboard/touch_keyboard_dialog.cc deleted file mode 100644 index e1405fdf87..0000000000 --- a/repos/gems/src/app/touch_keyboard/touch_keyboard_dialog.cc +++ /dev/null @@ -1,144 +0,0 @@ -/* - * \brief Touch-screen keyboard dialog - * \author Norman Feske - * \date 2022-01-11 - */ - -/* - * Copyright (C) 2022 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* local includes */ -#include - -using namespace Touch_keyboard; - - -void Dialog::produce_xml(Xml_generator &xml) -{ - auto gen_key = [&] (Key const &key) - { - xml.node("vbox", [&] () { - xml.attribute("name", key._id); - - xml.node("button", [&] () { - bool const selected = (_emit_on_release.length() > 1) - && (key.emit == _emit_on_release); - if (selected) - xml.attribute("selected", "yes"); - - if (key.map.length() > 1) - xml.attribute("style", "unimportant"); - - if (key.label.length() == 1) - xml.attribute("style", "invisible"); - - xml.node("vbox", [&] () { - xml.node("label", [&] () { - xml.attribute("name", "spacer"); - unsigned const min_ex = key.min_ex - ? key.min_ex - : _default_key_min_ex; - if (min_ex) - xml.attribute("min_ex", min_ex); - }); - xml.node("label", [&] () { - xml.attribute("name", "label"); - xml.attribute("text", key.label); - if (key.small) - xml.attribute("font", "annotation/regular"); - }); - }); - }); - }); - }; - - auto gen_row = [&] (Row const &row) - { - xml.node("hbox", [&] () { - xml.attribute("name", row._id); - row.keys.for_each([&] (Key const &key) { - gen_key(key); }); }); - }; - - auto gen_map = [&] (Map const &map) - { - if (map.name != _current_map) - return; - - xml.node("vbox", [&] () { - map.rows.for_each([&] (Row const &row) { - gen_row(row); }); }); - }; - - _maps.for_each([&] (Map const &map) { - gen_map(map); }); -} - - -void Dialog::handle_input_event(Input::Seq_number curr_seq, Input::Event const &event) -{ - if (event.touch()) - _clicked_seq_number.construct(curr_seq); - - if (_emit_on_release.length() > 1 && event.touch_release()) { - _event_emitter.emit_characters(_emit_on_release); - _emit_on_release = { }; - rom_session.trigger_update(); - } -} - - -void Dialog::handle_hover(Input::Seq_number seq, Xml_node const &dialog) -{ - Row::Id hovered_row_id { }; - Key::Id hovered_key_id { }; - - dialog.with_optional_sub_node("vbox", [&] (Xml_node const &vbox) { - vbox.with_optional_sub_node("hbox", [&] (Xml_node const &hbox) { - hbox.with_optional_sub_node("vbox", [&] (Xml_node const &button) { - hovered_row_id = hbox .attribute_value("name", Row::Id()); - hovered_key_id = button.attribute_value("name", Key::Id()); - }); - }); - }); - - _maps.for_each([&] (Map const &map) { - if (map.name != _current_map) - return; - - map.rows.for_each([&] (Row const &row) { - if (row._id != hovered_row_id) - return; - - row.keys.for_each([&] (Key const &key) { - if (key._id != hovered_key_id) - return; - - if (_clicked_seq_number.constructed()) { - if (seq.value >= _clicked_seq_number->value) { - _emit_on_release = key.emit; - _clicked_seq_number.destruct(); - - if (key.map.length() > 1) - _current_map = key.map; - - rom_session.trigger_update(); - } - } - }); - }); - }); -} - - -Dialog::Dialog(Entrypoint &ep, Ram_allocator &ram, Region_map &rm, - Allocator &alloc, Event_emitter &event_emitter) -: - Xml_producer("dialog"), - rom_session(ep, ram, rm, *this), - _alloc(alloc), _event_emitter(event_emitter) -{ } diff --git a/repos/gems/src/app/touch_keyboard/touch_keyboard_dialog.h b/repos/gems/src/app/touch_keyboard/touch_keyboard_dialog.h deleted file mode 100644 index 91ab87ecdb..0000000000 --- a/repos/gems/src/app/touch_keyboard/touch_keyboard_dialog.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * \brief Touch-screen keyboard dialog - * \author Norman Feske - * \date 2022-01-11 - */ - -/* - * Copyright (C) 2022 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _TOUCH_KEYBOARD_DIALOG_H_ -#define _TOUCH_KEYBOARD_DIALOG_H_ - -/* Genode includes */ -#include -#include -#include -#include -#include -#include - -/* local includes */ -#include -#include - -namespace Touch_keyboard { struct Dialog; } - - -struct Touch_keyboard::Dialog : private Dynamic_rom_session::Xml_producer -{ - public: - - Dynamic_rom_session rom_session; - - using Emit = String<8>; - - struct Event_emitter : Interface - { - virtual void emit_characters(Emit const &) = 0; - }; - - private: - - Allocator &_alloc; - - Event_emitter &_event_emitter; - - unsigned _default_key_min_ex = 0; - - struct Key : List_model::Element - { - using Id = String<8>; - Id const _id; - - static Id id_attr(Xml_node const &node) { - return node.attribute_value("id", Id()); } - - using Label = String<8>; - Label label { }; - - Emit emit { }; - - using Map = String<8>; - Map map { }; - - unsigned min_ex = 0; - - bool small = false; - - Key(Id id) : _id(id) { } - - bool matches(Xml_node const &node) const { return _id == id_attr(node); } - - static bool type_matches(Xml_node const &node) { return node.type() == "key"; } - - void update(Xml_node const &key) { - - label = { }; - emit = { }; - map = key.attribute_value("map", Map()); - min_ex = key.attribute_value("min_ex", 0U); - small = key.attribute_value("small", false); - - if (key.has_attribute("char")) { - label = key.attribute_value("char", Label()); - emit = Emit(Xml_unquoted(label)); - } - - if (key.has_attribute("code")) { - Codepoint c { key.attribute_value("code", 0U) }; - emit = Emit(c); - label = emit; - } - - if (key.has_attribute("label")) - label = key.attribute_value("label", Label()); - } - }; - - struct Row : List_model::Element - { - Allocator &_alloc; - - using Id = String<8>; - Id const _id; - - static Id id_attr(Xml_node const &node) { - return node.attribute_value("id", Id()); } - - List_model keys { }; - - Row(Allocator &alloc, Id id) : _alloc(alloc), _id(id) { } - - bool matches(Xml_node const &node) const { return _id == id_attr(node); } - - static bool type_matches(Xml_node const &node) { return node.type() == "row"; } - - void update(Xml_node const &row) - { - keys.update_from_xml(row, - - /* create */ - [&] (Xml_node const &node) -> Key & { - return *new (_alloc) Key(Key::id_attr(node)); }, - - /* destroy */ - [&] (Key &key) { destroy(_alloc, &key); }, - - /* update */ - [&] (Key &key, Xml_node const &node) { key.update(node); }); - } - }; - - struct Map : List_model::Element - { - Allocator &_alloc; - - using Name = String<16>; - Name const name; - - static Name name_attr(Xml_node const &node) { - return node.attribute_value("name", Name()); } - - List_model rows { }; - - Map(Allocator &alloc, Name name) : _alloc(alloc), name(name) { } - - bool matches(Xml_node const &node) const { return name == name_attr(node); } - - static bool type_matches(Xml_node const &node) { return node.type() == "map"; } - - void update(Xml_node const &map) - { - rows.update_from_xml(map, - - /* create */ - [&] (Xml_node const &node) -> Row & { - return *new (_alloc) Row(_alloc, Row::id_attr(node)); }, - - /* destroy */ - [&] (Row &row) { destroy(_alloc, &row); }, - - /* update */ - [&] (Row &row, Xml_node const &node) { row.update(node); }); - } - }; - - List_model _maps { }; - - Map::Name _current_map = "lower"; - - Constructible _clicked_seq_number { }; - - Emit _emit_on_release { }; - - void produce_xml(Xml_generator &xml) override; - - public: - - Dialog(Entrypoint &, Ram_allocator &, Region_map &, Allocator &, - Event_emitter &); - - void configure(Xml_node const &config) - { - _default_key_min_ex = config.attribute_value("key_min_ex", 0U); - - _maps.update_from_xml(config, - - /* create */ - [&] (Xml_node const &node) -> Map & { - return *new (_alloc) Map(_alloc, Map::name_attr(node)); }, - - /* destroy */ - [&] (Map &map) { destroy(_alloc, &map); }, - - /* update */ - [&] (Map &map, Xml_node const &node) { map.update(node); }); - } - - void handle_input_event(Input::Seq_number curr_seq, Input::Event const &); - - void handle_hover(Input::Seq_number, Xml_node const &hover); -}; - -#endif /* _TOUCH_KEYBOARD_DIALOG_H_ */ diff --git a/repos/gems/src/app/touch_keyboard/touch_keyboard_widget.cc b/repos/gems/src/app/touch_keyboard/touch_keyboard_widget.cc new file mode 100644 index 0000000000..485e463edc --- /dev/null +++ b/repos/gems/src/app/touch_keyboard/touch_keyboard_widget.cc @@ -0,0 +1,77 @@ +/* + * \brief Touch-screen keyboard widget + * \author Norman Feske + * \date 2022-01-11 + */ + +/* + * Copyright (C) 2022-2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include + +using namespace Dialog; + + +void Touch_keyboard_widget::Key::view(Scope &s, Attr const &attr) const +{ + s.widget(_button, [&] (Scope