mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-02 08:42:52 +00:00
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.
This commit is contained in:
parent
d26770eb40
commit
fa167bcdc4
2
repos/gems/recipes/pkg/screenshot_trigger/README
Normal file
2
repos/gems/recipes/pkg/screenshot_trigger/README
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
Virtual print button for a touch-screen device
|
1
repos/gems/recipes/pkg/screenshot_trigger/archives
Normal file
1
repos/gems/recipes/pkg/screenshot_trigger/archives
Normal file
@ -0,0 +1 @@
|
||||
_/src/screenshot_trigger
|
1
repos/gems/recipes/pkg/screenshot_trigger/hash
Normal file
1
repos/gems/recipes/pkg/screenshot_trigger/hash
Normal file
@ -0,0 +1 @@
|
||||
2023-01-29 a87e1719fd98401958f47ff3ae9f0c641b4c6094
|
12
repos/gems/recipes/pkg/screenshot_trigger/runtime
Normal file
12
repos/gems/recipes/pkg/screenshot_trigger/runtime
Normal file
@ -0,0 +1,12 @@
|
||||
<runtime ram="1M" caps="100" binary="screenshot_trigger">
|
||||
|
||||
<requires> <gui/> <event/> </requires>
|
||||
|
||||
<config size="50"/>
|
||||
|
||||
<content>
|
||||
<rom label="ld.lib.so"/>
|
||||
<rom label="screenshot_trigger"/>
|
||||
</content>
|
||||
|
||||
</runtime>
|
2
repos/gems/recipes/src/screenshot_trigger/content.mk
Normal file
2
repos/gems/recipes/src/screenshot_trigger/content.mk
Normal file
@ -0,0 +1,2 @@
|
||||
SRC_DIR = src/app/screenshot_trigger
|
||||
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
|
1
repos/gems/recipes/src/screenshot_trigger/hash
Normal file
1
repos/gems/recipes/src/screenshot_trigger/hash
Normal file
@ -0,0 +1 @@
|
||||
2023-01-29-a a4f24340626a9eb891f8de5061d2e1bb38ba56dc
|
10
repos/gems/recipes/src/screenshot_trigger/used_apis
Normal file
10
repos/gems/recipes/src/screenshot_trigger/used_apis
Normal file
@ -0,0 +1,10 @@
|
||||
base
|
||||
os
|
||||
blit
|
||||
gems
|
||||
framebuffer_session
|
||||
input_session
|
||||
gui_session
|
||||
event_session
|
||||
timer_session
|
||||
nitpicker_gfx
|
94
repos/gems/run/screenshot_trigger.run
Normal file
94
repos/gems/run/screenshot_trigger.run
Normal file
@ -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 {
|
||||
<config prio_levels="2">
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<default caps="100"/>
|
||||
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="Timer"/> </provides>
|
||||
</start>
|
||||
|
||||
<start name="drivers" caps="1500" managing_system="yes">
|
||||
<resource name="RAM" quantum="64M"/>
|
||||
<binary name="init"/>
|
||||
<route>
|
||||
<service name="ROM" label="config"> <parent label="drivers.config"/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
<service name="Capture"> <child name="nitpicker"/> </service>
|
||||
<service name="Event"> <child name="nitpicker"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="report_rom">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||
<config verbose="yes"/>
|
||||
</start>
|
||||
|
||||
<start name="nitpicker">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides>
|
||||
<service name="Gui"/> <service name="Capture"/> <service name="Event"/>
|
||||
</provides>
|
||||
<config focus="rom">
|
||||
<capture/> <event/>
|
||||
<report keystate="yes"/>
|
||||
|
||||
<domain name="pointer" layer="1" content="client" label="no" origin="pointer" />
|
||||
<domain name="default" layer="2" content="client" label="no" hover="always"/>
|
||||
|
||||
<policy label_prefix="pointer" domain="pointer"/>
|
||||
<default-policy domain="default"/>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="pointer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<route>
|
||||
<service name="Gui"> <child name="nitpicker"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="screenshot_trigger">
|
||||
<resource name="RAM" quantum="8M"/>
|
||||
<binary name="screenshot_trigger"/>
|
||||
<config size="200"/>
|
||||
<route>
|
||||
<service name="Gui"> <child name="nitpicker"/> </service>
|
||||
<service name="Event"> <child name="nitpicker"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
set fd [open [run_dir]/genode/focus w]
|
||||
puts $fd "<focus label=\"screenshot_trigger -> \"/>"
|
||||
close $fd
|
||||
|
||||
build { app/screenshot_trigger }
|
||||
|
||||
build_boot_image [build_artifacts]
|
||||
|
||||
run_genode_until forever
|
7
repos/gems/sculpt/launcher/screenshot_trigger
Normal file
7
repos/gems/sculpt/launcher/screenshot_trigger
Normal file
@ -0,0 +1,7 @@
|
||||
<launcher pkg="screenshot_trigger">
|
||||
<route>
|
||||
<service name="Gui"> <parent label="overlay"/> </service>
|
||||
<service name="Event"> <parent label="global"/> </service>
|
||||
</route>
|
||||
<config size="80"/>
|
||||
</launcher>
|
178
repos/gems/src/app/screenshot_trigger/main.cc
Normal file
178
repos/gems/src/app/screenshot_trigger/main.cc
Normal file
@ -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 <base/env.h>
|
||||
#include <base/component.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <gui_session/connection.h>
|
||||
#include <event_session/connection.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <input/event.h>
|
||||
#include <os/pixel_rgb888.h>
|
||||
#include <nitpicker_gfx/box_painter.h>
|
||||
#include <gems/gui_buffer.h>
|
||||
|
||||
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> _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<Command::Geometry>(_handle, Rect(position, size));
|
||||
_gui.enqueue<Command::To_front>(_handle, Gui::Session::View_handle());
|
||||
_gui.execute();
|
||||
}
|
||||
|
||||
~View() { _gui.destroy_view(_handle); }
|
||||
};
|
||||
|
||||
Constructible<View> _view { };
|
||||
|
||||
Signal_handler<Main> _timer_handler { _env.ep(), *this, &Main::_handle_timer };
|
||||
Signal_handler<Main> _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<Main> _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);
|
||||
}
|
3
repos/gems/src/app/screenshot_trigger/target.mk
Normal file
3
repos/gems/src/app/screenshot_trigger/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = screenshot_trigger
|
||||
SRC_CC = main.cc
|
||||
LIBS = base blit
|
Loading…
x
Reference in New Issue
Block a user