From fa167bcdc4633d216dc65edededb6cc37b29ab7d Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Sun, 29 Jan 2023 18:01:05 +0100 Subject: [PATCH] gems: screenshot trigger for virtual print button The screenshot trigger displays a little red dot at the upper-left corner of the screen. When touched or clicked-on, it generates an artificial key-press-release sequence for the print key and disappears for one second. In this time, a separate screenshot component can handle the print key by capturing the screen without the red dot appearing in the saved picture. --- .../recipes/pkg/screenshot_trigger/README | 2 + .../recipes/pkg/screenshot_trigger/archives | 1 + .../gems/recipes/pkg/screenshot_trigger/hash | 1 + .../recipes/pkg/screenshot_trigger/runtime | 12 ++ .../recipes/src/screenshot_trigger/content.mk | 2 + .../gems/recipes/src/screenshot_trigger/hash | 1 + .../recipes/src/screenshot_trigger/used_apis | 10 + repos/gems/run/screenshot_trigger.run | 94 +++++++++ repos/gems/sculpt/launcher/screenshot_trigger | 7 + repos/gems/src/app/screenshot_trigger/main.cc | 178 ++++++++++++++++++ .../gems/src/app/screenshot_trigger/target.mk | 3 + 11 files changed, 311 insertions(+) create mode 100644 repos/gems/recipes/pkg/screenshot_trigger/README create mode 100644 repos/gems/recipes/pkg/screenshot_trigger/archives create mode 100644 repos/gems/recipes/pkg/screenshot_trigger/hash create mode 100644 repos/gems/recipes/pkg/screenshot_trigger/runtime create mode 100644 repos/gems/recipes/src/screenshot_trigger/content.mk create mode 100644 repos/gems/recipes/src/screenshot_trigger/hash create mode 100644 repos/gems/recipes/src/screenshot_trigger/used_apis create mode 100644 repos/gems/run/screenshot_trigger.run create mode 100644 repos/gems/sculpt/launcher/screenshot_trigger create mode 100644 repos/gems/src/app/screenshot_trigger/main.cc create mode 100644 repos/gems/src/app/screenshot_trigger/target.mk diff --git a/repos/gems/recipes/pkg/screenshot_trigger/README b/repos/gems/recipes/pkg/screenshot_trigger/README new file mode 100644 index 0000000000..3f9fae42c5 --- /dev/null +++ b/repos/gems/recipes/pkg/screenshot_trigger/README @@ -0,0 +1,2 @@ + + Virtual print button for a touch-screen device diff --git a/repos/gems/recipes/pkg/screenshot_trigger/archives b/repos/gems/recipes/pkg/screenshot_trigger/archives new file mode 100644 index 0000000000..bcf70a4ae6 --- /dev/null +++ b/repos/gems/recipes/pkg/screenshot_trigger/archives @@ -0,0 +1 @@ +_/src/screenshot_trigger diff --git a/repos/gems/recipes/pkg/screenshot_trigger/hash b/repos/gems/recipes/pkg/screenshot_trigger/hash new file mode 100644 index 0000000000..9fc0713931 --- /dev/null +++ b/repos/gems/recipes/pkg/screenshot_trigger/hash @@ -0,0 +1 @@ +2023-01-29 a87e1719fd98401958f47ff3ae9f0c641b4c6094 diff --git a/repos/gems/recipes/pkg/screenshot_trigger/runtime b/repos/gems/recipes/pkg/screenshot_trigger/runtime new file mode 100644 index 0000000000..e57ee6334f --- /dev/null +++ b/repos/gems/recipes/pkg/screenshot_trigger/runtime @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/repos/gems/recipes/src/screenshot_trigger/content.mk b/repos/gems/recipes/src/screenshot_trigger/content.mk new file mode 100644 index 0000000000..06909396ad --- /dev/null +++ b/repos/gems/recipes/src/screenshot_trigger/content.mk @@ -0,0 +1,2 @@ +SRC_DIR = src/app/screenshot_trigger +include $(GENODE_DIR)/repos/base/recipes/src/content.inc diff --git a/repos/gems/recipes/src/screenshot_trigger/hash b/repos/gems/recipes/src/screenshot_trigger/hash new file mode 100644 index 0000000000..f2470cffe5 --- /dev/null +++ b/repos/gems/recipes/src/screenshot_trigger/hash @@ -0,0 +1 @@ +2023-01-29-a a4f24340626a9eb891f8de5061d2e1bb38ba56dc diff --git a/repos/gems/recipes/src/screenshot_trigger/used_apis b/repos/gems/recipes/src/screenshot_trigger/used_apis new file mode 100644 index 0000000000..6e9b9cd67c --- /dev/null +++ b/repos/gems/recipes/src/screenshot_trigger/used_apis @@ -0,0 +1,10 @@ +base +os +blit +gems +framebuffer_session +input_session +gui_session +event_session +timer_session +nitpicker_gfx diff --git a/repos/gems/run/screenshot_trigger.run b/repos/gems/run/screenshot_trigger.run new file mode 100644 index 0000000000..3c1004d7e1 --- /dev/null +++ b/repos/gems/run/screenshot_trigger.run @@ -0,0 +1,94 @@ +create_boot_directory + +import_from_depot [depot_user]/src/[base_src] \ + [depot_user]/pkg/[drivers_interactive_pkg] \ + [depot_user]/src/report_rom \ + [depot_user]/src/nitpicker \ + [depot_user]/src/init + +install_config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +set fd [open [run_dir]/genode/focus w] +puts $fd " \"/>" +close $fd + +build { app/screenshot_trigger } + +build_boot_image [build_artifacts] + +run_genode_until forever diff --git a/repos/gems/sculpt/launcher/screenshot_trigger b/repos/gems/sculpt/launcher/screenshot_trigger new file mode 100644 index 0000000000..e1ce470041 --- /dev/null +++ b/repos/gems/sculpt/launcher/screenshot_trigger @@ -0,0 +1,7 @@ + + + + + + + diff --git a/repos/gems/src/app/screenshot_trigger/main.cc b/repos/gems/src/app/screenshot_trigger/main.cc new file mode 100644 index 0000000000..5bd6b8b3c0 --- /dev/null +++ b/repos/gems/src/app/screenshot_trigger/main.cc @@ -0,0 +1,178 @@ +/* + * \brief Virtual print button + * \author Norman Feske + * \date 2023-01-29 + */ + +/* + * Copyright (C) 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Screenshot_trigger { + using namespace Genode; + struct Main; +} + + +struct Screenshot_trigger::Main +{ + Env &_env; + + using Point = Gui_buffer::Point; + using Area = Gui_buffer::Area; + using Rect = Gui_buffer::Rect; + + unsigned _size { }; + Point _position { }; + Area _area { }; + + Color const _color { 200, 0, 0 }; + + Input::Keycode const _keycode = Input::KEY_PRINT; + + uint64_t const _timeout_us = 1*1000*1000; + + Gui ::Connection _gui { _env }; + Event::Connection _event { _env }; + Timer::Connection _timer { _env }; + + Constructible _gui_buffer { }; + + struct View + { + Gui::Connection &_gui; + + Gui::Session::View_handle _handle { _gui.create_view() }; + + View(Gui::Connection &gui, Point position, Area size) : _gui(gui) + { + using Command = Gui::Session::Command; + _gui.enqueue(_handle, Rect(position, size)); + _gui.enqueue(_handle, Gui::Session::View_handle()); + _gui.execute(); + } + + ~View() { _gui.destroy_view(_handle); } + }; + + Constructible _view { }; + + Signal_handler
_timer_handler { _env.ep(), *this, &Main::_handle_timer }; + Signal_handler
_input_handler { _env.ep(), *this, &Main::_handle_input }; + + /* used for hiding the view for a second after triggering */ + bool _visible = true; + + void visible(bool visible) + { + _visible = visible; + _view.conditional(visible, _gui, _position, _area); + } + + void _handle_input() + { + _gui.input()->for_each_event([&] (Input::Event const &ev) { + + if (!_visible) /* ignore events while the view is invisble */ + return; + + bool const triggered = ev.key_release(Input::BTN_LEFT) + || ev.touch_release(); + if (!triggered) + return; + + /* hide trigger for some time */ + visible(false); + _timer.trigger_once(_timeout_us); + + /* generate synthetic key-press-release sequence */ + _event.with_batch([&] (Event::Connection::Batch &batch) { + batch.submit(Input::Press { _keycode }); + batch.submit(Input::Release { _keycode }); + }); + }); + } + + void _handle_timer() + { + if (!_visible) + visible(true); + } + + void _render(Gui_buffer::Pixel_surface &pixel, Gui_buffer::Alpha_surface &alpha) + { + Box_painter::paint(pixel, Rect(Point(0, 0), _area), _color); + + long const half = _size/2; + long const max_sq = half*half; + + auto intensity = [&] (long x, long y) + { + x -= half, + y -= half; + + long const r_sq = x*x + y*y; + + return 255 - min(255l, (r_sq*255)/max_sq); + }; + + /* fill alpha channel */ + Pixel_alpha8 *base = alpha.addr(); + for (unsigned y = 0; y < _area.h(); y++) + for (unsigned x = 0; x < _area.w(); x++) + *base++ = Pixel_alpha8 { 0, 0, 0, int(intensity(x, y)) }; + } + + Attached_rom_dataspace _config { _env, "config" }; + + Signal_handler
_config_handler { _env.ep(), *this, &Main::_handle_config }; + + void _handle_config() + { + _config.update(); + + Xml_node const config = _config.xml(); + + _size = config.attribute_value("size", 50u); + _position = Point::from_xml(config); + _area = Area(_size, _size); + + _gui_buffer.construct(_gui, _area, _env.ram(), _env.rm()); + + _gui_buffer->apply_to_surface([&] (auto &pixel, auto &alpha) { + _render(pixel, alpha); }); + + _gui_buffer->flush_surface(); + } + + Main(Env &env) : _env(env) + { + _config.sigh(_config_handler); + _handle_config(); + + _gui.input()->sigh(_input_handler); + _timer.sigh(_timer_handler); + + visible(true); + } +}; + + +void Component::construct(Genode::Env &env) +{ + static Screenshot_trigger::Main main(env); +} diff --git a/repos/gems/src/app/screenshot_trigger/target.mk b/repos/gems/src/app/screenshot_trigger/target.mk new file mode 100644 index 0000000000..18793b1204 --- /dev/null +++ b/repos/gems/src/app/screenshot_trigger/target.mk @@ -0,0 +1,3 @@ +TARGET = screenshot_trigger +SRC_CC = main.cc +LIBS = base blit