mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-08 11:55:24 +00:00
nitpicker: Support for global keys
This commit is contained in:
parent
afbd7ea50e
commit
20daeb6d16
@ -102,6 +102,15 @@ append config {
|
||||
<start name="nitpicker">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Nitpicker"/></provides>
|
||||
<config>
|
||||
<global-keys>
|
||||
<key name="KEY_SCROLLLOCK" operation="xray" />
|
||||
<key name="KEY_SYSRQ" operation="kill" />
|
||||
<key name="KEY_PRINT" operation="kill" />
|
||||
<key name="KEY_F11" operation="kill" />
|
||||
<key name="KEY_F12" operation="xray" />
|
||||
</global-keys>
|
||||
</config>
|
||||
</start>
|
||||
<start name="launchpad">
|
||||
<resource name="RAM" quantum="32M"/>
|
||||
|
@ -12,15 +12,56 @@ Configuration
|
||||
Nitpicker supports the following configuration options, supplied via
|
||||
Genode's config mechanism.
|
||||
|
||||
:Tinting of clients in X-Ray mode:
|
||||
Tinting of clients in X-Ray mode
|
||||
--------------------------------
|
||||
|
||||
Nitpicker allows for assigning a color to single clients or a groups
|
||||
of clients based on the client's label. The following configuration
|
||||
tints all views of the launchpad subsystem in blue except for those
|
||||
views that belong to the testnit child of launchpad.
|
||||
! <config>
|
||||
! <policy label="launchpad" color="#0000ff"/>
|
||||
! <policy label="launchpad -> testnit" color="#ff0000"/>
|
||||
! </config>
|
||||
Nitpicker allows for assigning a color to single clients or a groups
|
||||
of clients based on the client's label. The following configuration
|
||||
tints all views of the launchpad subsystem in blue except for those
|
||||
views that belong to the testnit child of launchpad.
|
||||
|
||||
! <config>
|
||||
! <policy label="launchpad" color="#0000ff"/>
|
||||
! <policy label="launchpad -> testnit" color="#ff0000"/>
|
||||
! </config>
|
||||
|
||||
Global key definitions
|
||||
----------------------
|
||||
|
||||
Nitpicker has a few built-in function that can be activated via global
|
||||
keyboard shortcuts, namely the X-ray mode and the kill mode. The keys
|
||||
for toggling those functions can be defined as follows:
|
||||
|
||||
! <config>
|
||||
! <global-keys>
|
||||
! <key name="KEY_SCROLLLOCK" operation="xray" />
|
||||
! <key name="KEY_PRINT" operation="kill" />
|
||||
! </global-keys>
|
||||
! </config>
|
||||
|
||||
The '<global-keys>' node contains the policy for handling global keys. Each
|
||||
'<key>' subnode expresses a rule for named key. The 'operation' attribute
|
||||
refers nitpicker's built-in operations. In the example above, the X-ray
|
||||
mode can be activated via the scroll-lock key and the kill mode can be
|
||||
activated via the print key.
|
||||
|
||||
Alternatively to specifying an 'operation' attribute, a key node can contain
|
||||
a 'label' attribute. If specified, all events regarding the key will be
|
||||
reported to the client with the specified label. This enables clients to
|
||||
handle global shortcuts. The client with the matching label will receive
|
||||
all events until the number of concurrently pressed keys reaches zero.
|
||||
This way, it is possible to handle chords of multiple keys starting with
|
||||
the key specified in the '<key>' node. For the routing of global keys to
|
||||
clients, the order of '<key>' nodes is important. If multiple nodes exists for
|
||||
different labels, the first match will take effect. For example:
|
||||
|
||||
! <global-keys>
|
||||
! <key name="KEY_F11" label="launchpad -> testnit" />
|
||||
! <key name="KEY_F11" label="launchpad" />
|
||||
! </global-keys>
|
||||
|
||||
The "launchpad" client will receive all key sequences starting with F11 unless
|
||||
the "launchpad -> testnit" program is running. As soon as testnit gets started
|
||||
by launchpad, testnit will receive the events. If the order was reversed,
|
||||
launchpad would always receive the events.
|
||||
|
||||
|
@ -13,26 +13,21 @@
|
||||
|
||||
#include <input/event.h>
|
||||
#include <input/keycodes.h>
|
||||
|
||||
#include "user_state.h"
|
||||
|
||||
using namespace Input;
|
||||
|
||||
/*
|
||||
* Definition of magic keys
|
||||
*/
|
||||
enum { KILL_KEY = KEY_PRINT };
|
||||
enum { XRAY_KEY = KEY_SCROLLLOCK };
|
||||
|
||||
|
||||
/***************
|
||||
** Utilities **
|
||||
***************/
|
||||
|
||||
static inline bool _masked_key(int keycode) {
|
||||
return keycode == KILL_KEY || keycode == XRAY_KEY; }
|
||||
static inline bool _masked_key(Global_keys &global_keys, Keycode keycode) {
|
||||
return global_keys.is_kill_key(keycode) || global_keys.is_xray_key(keycode); }
|
||||
|
||||
|
||||
static inline bool _mouse_button(int keycode) {
|
||||
static inline bool _mouse_button(Keycode keycode) {
|
||||
return keycode >= BTN_LEFT && keycode <= BTN_MIDDLE; }
|
||||
|
||||
|
||||
@ -40,27 +35,27 @@ static inline bool _mouse_button(int keycode) {
|
||||
** User state interface **
|
||||
**************************/
|
||||
|
||||
User_state::User_state(Canvas *canvas, Menubar *menubar):
|
||||
View_stack(canvas, this), _key_cnt(0), _menubar(menubar),
|
||||
_pointed_view(0) { }
|
||||
User_state::User_state(Global_keys &global_keys, Canvas *canvas, Menubar *menubar)
|
||||
:
|
||||
View_stack(canvas, this), _global_keys(global_keys), _key_cnt(0),
|
||||
_menubar(menubar), _pointed_view(0), _input_receiver(0),
|
||||
_global_key_sequence(false)
|
||||
{ }
|
||||
|
||||
|
||||
void User_state::handle_event(Input::Event ev)
|
||||
{
|
||||
Input::Keycode const keycode = ev.keycode();
|
||||
Input::Event::Type const type = ev.type();
|
||||
|
||||
/*
|
||||
* Mangle incoming events
|
||||
*/
|
||||
|
||||
int keycode = ev.code();
|
||||
int ax = _mouse_pos.x(), ay = _mouse_pos.y();
|
||||
int rx = 0, ry = 0; /* skip info about relative motion per default */
|
||||
|
||||
/* KEY_PRINT and KEY_SYSRQ both enter kill mode */
|
||||
if ((ev.type() == Event::PRESS) && (ev.code() == KEY_SYSRQ))
|
||||
keycode = KEY_PRINT;
|
||||
|
||||
/* transparently handle absolute and relative motion events */
|
||||
if (ev.type() == Event::MOTION) {
|
||||
if (type == Event::MOTION) {
|
||||
if ((ev.rx() || ev.ry()) && ev.ax() == 0 && ev.ay() == 0) {
|
||||
ax = max(0, min(size().w(), ax + ev.rx()));
|
||||
ay = max(0, min(size().h(), ay + ev.ry()));
|
||||
@ -71,17 +66,17 @@ void User_state::handle_event(Input::Event ev)
|
||||
}
|
||||
|
||||
/* propagate relative motion for wheel events */
|
||||
if (ev.type() == Event::WHEEL) {
|
||||
if (type == Event::WHEEL) {
|
||||
rx = ev.rx();
|
||||
ry = ev.ry();
|
||||
}
|
||||
|
||||
/* create the mangled event */
|
||||
ev = Input::Event(ev.type(), keycode, ax, ay, rx, ry);
|
||||
ev = Input::Event(type, keycode, ax, ay, rx, ry);
|
||||
|
||||
_mouse_pos = Point(ax, ay);
|
||||
|
||||
View *pointed_view = find_view(_mouse_pos);
|
||||
View * pointed_view = find_view(_mouse_pos);
|
||||
|
||||
/*
|
||||
* Deliver a leave event if pointed-to session changed
|
||||
@ -95,32 +90,54 @@ void User_state::handle_event(Input::Event ev)
|
||||
/* remember currently pointed-at view */
|
||||
_pointed_view = pointed_view;
|
||||
|
||||
/*
|
||||
* We expect pointed view to be always defined. In the worst case (with no
|
||||
* view at all), the pointed view is the background.
|
||||
/**
|
||||
* Guard that performs a whole-screen update when leaving the scope
|
||||
*/
|
||||
struct Update_all_guard
|
||||
{
|
||||
User_state &user_state;
|
||||
bool enabled;
|
||||
char const *menu_title;
|
||||
|
||||
bool update_all = false;
|
||||
Update_all_guard(User_state &user_state)
|
||||
: user_state(user_state), enabled(false), menu_title("") { }
|
||||
|
||||
~Update_all_guard()
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (user_state._input_receiver)
|
||||
user_state._menubar->state(user_state, user_state._input_receiver->label(),
|
||||
menu_title, user_state._input_receiver->color());
|
||||
else
|
||||
user_state._menubar->state(user_state, "", "", BLACK);
|
||||
|
||||
user_state.update_all_views();
|
||||
}
|
||||
} update_all_guard(*this);
|
||||
|
||||
/*
|
||||
* Detect mouse press event in kill mode, used to select the session
|
||||
* to lock out.
|
||||
*/
|
||||
if (kill() && ev.type() == Event::PRESS && ev.code() == Input::BTN_LEFT) {
|
||||
if (kill() && type == Event::PRESS && keycode == Input::BTN_LEFT) {
|
||||
if (pointed_view && pointed_view->session())
|
||||
lock_out_session(pointed_view->session());
|
||||
|
||||
/* leave kill mode */
|
||||
pointed_view = 0;
|
||||
Mode::_mode &= ~KILL;
|
||||
update_all = true;
|
||||
pointed_view = 0;
|
||||
Mode::_mode &= ~KILL;
|
||||
update_all_guard.enabled = true;
|
||||
}
|
||||
|
||||
if (ev.type() == Event::PRESS && _key_cnt == 0) {
|
||||
/*
|
||||
* Handle start of a key sequence
|
||||
*/
|
||||
if (type == Event::PRESS && _key_cnt == 0) {
|
||||
|
||||
/* update focused view */
|
||||
if (pointed_view != focused_view()
|
||||
&& _mouse_button(ev.code())) {
|
||||
if (pointed_view != focused_view() && _mouse_button(keycode)) {
|
||||
|
||||
bool const focus_stays_in_session =
|
||||
(_focused_view && pointed_view &&
|
||||
@ -131,7 +148,7 @@ void User_state::handle_event(Input::Event ev)
|
||||
* changing the focus to another session.
|
||||
*/
|
||||
if (flat() && !focus_stays_in_session)
|
||||
update_all = true;
|
||||
update_all_guard.enabled = true;
|
||||
|
||||
/*
|
||||
* Notify both the old focussed session and the new one.
|
||||
@ -150,43 +167,63 @@ void User_state::handle_event(Input::Event ev)
|
||||
}
|
||||
|
||||
if (!flat() || !_focused_view || !pointed_view)
|
||||
update_all = true;
|
||||
update_all_guard.enabled = true;
|
||||
|
||||
_focused_view = pointed_view;
|
||||
}
|
||||
|
||||
/* toggle kill and xray modes */
|
||||
if (ev.code() == KILL_KEY || ev.code() == XRAY_KEY) {
|
||||
/*
|
||||
* If there exists a global rule for the pressed key, set the
|
||||
* corresponding session as receiver of the input stream until the key
|
||||
* count reaches zero. Otherwise, the input stream is directed to the
|
||||
* pointed-at view.
|
||||
*
|
||||
* If we deliver a global key sequence, we temporarily change the focus
|
||||
* to the global receiver. To reflect that change, we need to update
|
||||
* the whole screen.
|
||||
*/
|
||||
Session * const global_receiver = _global_keys.global_receiver(keycode);
|
||||
if (global_receiver) {
|
||||
_global_key_sequence = true;
|
||||
_input_receiver = global_receiver;
|
||||
update_all_guard.menu_title = "";
|
||||
update_all_guard.enabled = true;
|
||||
}
|
||||
|
||||
Mode::_mode ^= ev.code() == KILL_KEY ? KILL : XRAY;
|
||||
update_all = true;
|
||||
/*
|
||||
* No global rule matched, so the input stream gets directed to the
|
||||
* focused view or refers to a built-in operation.
|
||||
*/
|
||||
if (!global_receiver && _focused_view) {
|
||||
_input_receiver = _focused_view->session();
|
||||
update_all_guard.menu_title = _focused_view->title();
|
||||
}
|
||||
|
||||
/*
|
||||
* Toggle kill and xray modes. If one of those keys is pressed,
|
||||
* suppress the delivery to clients.
|
||||
*/
|
||||
if (_global_keys.is_operation_key(keycode)) {
|
||||
|
||||
Mode::_mode ^= _global_keys.is_kill_key(keycode) ? KILL : 0
|
||||
| _global_keys.is_xray_key(keycode) ? XRAY : 0;
|
||||
|
||||
update_all_guard.enabled = true;
|
||||
_input_receiver = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (update_all) {
|
||||
|
||||
if (focused_view() && focused_view()->session())
|
||||
_menubar->state(*this, focused_view()->session()->label(),
|
||||
focused_view()->title(),
|
||||
focused_view()->session()->color());
|
||||
else
|
||||
_menubar->state(*this, "", "", BLACK);
|
||||
|
||||
update_all_views();
|
||||
}
|
||||
|
||||
/* count keys */
|
||||
if (ev.type() == Event::PRESS) _key_cnt++;
|
||||
if (ev.type() == Event::RELEASE && _key_cnt > 0) _key_cnt--;
|
||||
if (type == Event::PRESS) _key_cnt++;
|
||||
if (type == Event::RELEASE && _key_cnt > 0) _key_cnt--;
|
||||
|
||||
/*
|
||||
* Deliver event to Nitpicker session.
|
||||
* (except when kill mode is activated)
|
||||
* Deliver event to Nitpicker session except when kill mode is activated
|
||||
*/
|
||||
|
||||
if (kill()) return;
|
||||
|
||||
if (ev.type() == Event::MOTION || ev.type() == Event::WHEEL) {
|
||||
if (type == Event::MOTION || type == Event::WHEEL) {
|
||||
|
||||
if (_key_cnt == 0) {
|
||||
|
||||
@ -199,14 +236,24 @@ void User_state::handle_event(Input::Event ev)
|
||||
if (pointed_view)
|
||||
pointed_view->session()->submit_input_event(&ev);
|
||||
|
||||
} else if (focused_view())
|
||||
focused_view()->session()->submit_input_event(&ev);
|
||||
} else if (_input_receiver)
|
||||
_input_receiver->submit_input_event(&ev);
|
||||
}
|
||||
|
||||
/* deliver press/release event to session with focused view */
|
||||
if (ev.type() == Event::PRESS || ev.type() == Event::RELEASE)
|
||||
if (!_masked_key(ev.code()) && focused_view())
|
||||
focused_view()->session()->submit_input_event(&ev);
|
||||
if (type == Event::PRESS || type == Event::RELEASE)
|
||||
if (_input_receiver)
|
||||
_input_receiver->submit_input_event(&ev);
|
||||
|
||||
/*
|
||||
* Detect end of global key sequence
|
||||
*/
|
||||
if (ev.type() == Event::RELEASE && _key_cnt == 0 && _global_key_sequence) {
|
||||
_input_receiver = _focused_view ? _focused_view->session() : 0;
|
||||
update_all_guard.menu_title = _focused_view ? _focused_view->title() : "";
|
||||
update_all_guard.enabled = true;
|
||||
_global_key_sequence = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -221,6 +268,8 @@ void User_state::forget(View *v)
|
||||
_menubar->state(*this, "", "", BLACK);
|
||||
update_all_views();
|
||||
}
|
||||
if (_input_receiver == v->session())
|
||||
_input_receiver = 0;
|
||||
if (_pointed_view == v)
|
||||
_pointed_view = find_view(_mouse_pos);
|
||||
}
|
||||
|
@ -553,6 +553,8 @@ namespace Nitpicker {
|
||||
{
|
||||
private:
|
||||
|
||||
Session_list &_session_list;
|
||||
Global_keys &_global_keys;
|
||||
Area _scr_size;
|
||||
View_stack *_view_stack;
|
||||
Flush_merger *_flush_merger;
|
||||
@ -595,12 +597,17 @@ namespace Nitpicker {
|
||||
|
||||
bool provides_default_bg = (Genode::strcmp(label_buf, "backdrop") == 0);
|
||||
|
||||
return new (md_alloc())
|
||||
Session_component(label_buf, cdt, cdt, _view_stack, ep(),
|
||||
_flush_merger, _framebuffer, v_offset,
|
||||
cdt->input_mask_buffer(),
|
||||
provides_default_bg, session_color(args),
|
||||
stay_top);
|
||||
Session_component *session = new (md_alloc())
|
||||
Session_component(label_buf, cdt, cdt, _view_stack, ep(),
|
||||
_flush_merger, _framebuffer, v_offset,
|
||||
cdt->input_mask_buffer(),
|
||||
provides_default_bg, session_color(args),
|
||||
stay_top);
|
||||
|
||||
_session_list.insert(session);
|
||||
_global_keys.apply_config(_session_list);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
void _destroy_session(Session_component *session)
|
||||
@ -608,6 +615,9 @@ namespace Nitpicker {
|
||||
Chunky_dataspace_texture<PT> *cdt;
|
||||
cdt = static_cast<Chunky_dataspace_texture<PT> *>(session->texture());
|
||||
|
||||
_session_list.remove(session);
|
||||
_global_keys.apply_config(_session_list);
|
||||
|
||||
destroy(md_alloc(), session);
|
||||
destroy(md_alloc(), cdt);
|
||||
}
|
||||
@ -617,12 +627,14 @@ namespace Nitpicker {
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Root(Genode::Rpc_entrypoint *session_ep, Area scr_size,
|
||||
Root(Session_list &session_list, Global_keys &global_keys,
|
||||
Genode::Rpc_entrypoint *session_ep, Area scr_size,
|
||||
View_stack *view_stack, Genode::Allocator *md_alloc,
|
||||
Flush_merger *flush_merger,
|
||||
Framebuffer::Session *framebuffer, int default_v_offset)
|
||||
:
|
||||
Genode::Root_component<Session_component>(session_ep, md_alloc),
|
||||
_session_list(session_list), _global_keys(global_keys),
|
||||
_scr_size(scr_size), _view_stack(view_stack), _flush_merger(flush_merger),
|
||||
_framebuffer(framebuffer), _default_v_offset(default_v_offset) { }
|
||||
};
|
||||
@ -789,6 +801,85 @@ class Input_handler_component : public Genode::Rpc_object<Input_handler,
|
||||
typedef Pixel_rgb565 PT; /* physical pixel type */
|
||||
|
||||
|
||||
/*****************************
|
||||
** Handling of global keys **
|
||||
*****************************/
|
||||
|
||||
Global_keys::Policy *Global_keys::_lookup_policy(char const *key_name)
|
||||
{
|
||||
for (unsigned i = 0; i < NUM_POLICIES; i++)
|
||||
if (Genode::strcmp(key_name, Input::key_name((Input::Keycode)i)) == 0)
|
||||
return &_policies[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Global_keys::apply_config(Session_list &session_list)
|
||||
{
|
||||
for (unsigned i = 0; i < NUM_POLICIES; i++)
|
||||
_policies[i].undefine();
|
||||
|
||||
using Genode::Xml_node;
|
||||
try {
|
||||
Xml_node node = Genode::config()->xml_node().sub_node("global-keys").sub_node("key");
|
||||
|
||||
for (; ; node = node.next("key")) {
|
||||
|
||||
if (!node.has_attribute("name")) {
|
||||
PWRN("attribute 'name' missing in <key> config node");
|
||||
continue;
|
||||
}
|
||||
|
||||
char name[32]; name[0] = 0;
|
||||
node.attribute("name").value(name, sizeof(name));
|
||||
|
||||
Policy * policy = _lookup_policy(name);
|
||||
if (!policy) {
|
||||
PWRN("invalid key name \"%s\"", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if two policies match, give precedence to policy defined first */
|
||||
if (policy->defined())
|
||||
continue;
|
||||
|
||||
if (node.has_attribute("operation")) {
|
||||
Xml_node::Attribute operation = node.attribute("operation");
|
||||
|
||||
if (operation.has_value("kill")) {
|
||||
policy->operation_kill();
|
||||
continue;
|
||||
} else if (operation.has_value("xray")) {
|
||||
policy->operation_xray();
|
||||
continue;
|
||||
} else {
|
||||
char buf[32]; buf[0] = 0;
|
||||
operation.value(buf, sizeof(buf));
|
||||
PWRN("unknown operation \"%s\" for key %s", buf, name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!node.has_attribute("label")) {
|
||||
PWRN("missing 'label' attribute for key %s", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* assign policy to matching client session */
|
||||
for (Session *s = session_list.first(); s; s = s->next())
|
||||
if (node.attribute("label").has_value(s->label()))
|
||||
policy->client(s);
|
||||
}
|
||||
|
||||
} catch (Xml_node::Nonexistent_sub_node) { }
|
||||
}
|
||||
|
||||
|
||||
/******************
|
||||
** Main program **
|
||||
******************/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
using namespace Genode;
|
||||
@ -828,7 +919,18 @@ int main(int argc, char **argv)
|
||||
PT *menubar_pixels = (PT *)env()->heap()->alloc(sizeof(PT)*mode.width()*16);
|
||||
Chunky_menubar<PT> menubar(menubar_pixels, Area(mode.width(), MENUBAR_HEIGHT));
|
||||
|
||||
User_state user_state(&screen, &menubar);
|
||||
static Global_keys global_keys;
|
||||
|
||||
static Session_list session_list;
|
||||
|
||||
/*
|
||||
* Apply initial global-key policy to turn X-ray and kill keys into
|
||||
* effect. The policy will be updated each time the config changes,
|
||||
* or when a session appears or disappears.
|
||||
*/
|
||||
global_keys.apply_config(session_list);
|
||||
|
||||
static User_state user_state(global_keys, &screen, &menubar);
|
||||
|
||||
/*
|
||||
* Create view stack with default elements
|
||||
@ -852,7 +954,8 @@ int main(int argc, char **argv)
|
||||
|
||||
Sliced_heap sliced_heap(env()->ram_session(), env()->rm_session());
|
||||
|
||||
static Nitpicker::Root<PT> np_root(&ep, Area(mode.width(), mode.height()),
|
||||
static Nitpicker::Root<PT> np_root(session_list, global_keys,
|
||||
&ep, Area(mode.width(), mode.height()),
|
||||
&user_state, &sliced_heap,
|
||||
&screen, &framebuffer,
|
||||
MENUBAR_HEIGHT);
|
||||
|
96
os/src/server/nitpicker/include/global_keys.h
Normal file
96
os/src/server/nitpicker/include/global_keys.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* \brief Global keys policy
|
||||
* \author Norman Feske
|
||||
* \date 2013-09-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _GLOBAL_KEYS_H_
|
||||
#define _GLOBAL_KEYS_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <input/keycodes.h>
|
||||
|
||||
/* local includes */
|
||||
#include "session.h"
|
||||
|
||||
class Global_keys
|
||||
{
|
||||
private:
|
||||
|
||||
struct Policy
|
||||
{
|
||||
enum Type {
|
||||
|
||||
/**
|
||||
* Key is not global but should be propagated to focused client
|
||||
*/
|
||||
UNDEFINED,
|
||||
|
||||
/**
|
||||
* Key activates nitpicker's built-in kill mode
|
||||
*/
|
||||
KILL,
|
||||
|
||||
/**
|
||||
* Key activates nitpicker's built-in X-ray mode
|
||||
*/
|
||||
XRAY,
|
||||
|
||||
/**
|
||||
* Key should be propagated to client session
|
||||
*/
|
||||
CLIENT
|
||||
};
|
||||
|
||||
Type _type;
|
||||
Session *_session;
|
||||
|
||||
Policy() : _type(UNDEFINED), _session(0) { }
|
||||
|
||||
void undefine() { _type = UNDEFINED; _session = 0; }
|
||||
void operation_kill() { _type = KILL; _session = 0; }
|
||||
void operation_xray() { _type = XRAY; _session = 0; }
|
||||
void client(Session *s) { _type = CLIENT; _session = s; }
|
||||
|
||||
bool defined() const { return _type != UNDEFINED; }
|
||||
bool xray() const { return _type == XRAY; }
|
||||
bool kill() const { return _type == KILL; }
|
||||
};
|
||||
|
||||
enum { NUM_POLICIES = Input::KEY_MAX + 1 };
|
||||
|
||||
Policy _policies[NUM_POLICIES];
|
||||
|
||||
/**
|
||||
* Lookup policy that matches the specified key name
|
||||
*/
|
||||
Policy *_lookup_policy(char const *key_name);
|
||||
|
||||
bool _valid(Input::Keycode key) const {
|
||||
return key >= 0 && key <= Input::KEY_MAX; }
|
||||
|
||||
public:
|
||||
|
||||
Session *global_receiver(Input::Keycode key) {
|
||||
return _valid(key) ? _policies[key]._session : 0; }
|
||||
|
||||
void apply_config(Session_list &session_list);
|
||||
|
||||
bool is_operation_key(Input::Keycode key) const {
|
||||
return _valid(key) && (_policies[key].xray() || _policies[key].kill()); }
|
||||
|
||||
bool is_xray_key(Input::Keycode key) const {
|
||||
return _valid(key) && _policies[key].xray(); }
|
||||
|
||||
bool is_kill_key(Input::Keycode key) const {
|
||||
return _valid(key) && _policies[key].kill(); }
|
||||
};
|
||||
|
||||
#endif /* _GLOBAL_KEYS_H_ */
|
@ -14,13 +14,21 @@
|
||||
#ifndef _SESSION_H_
|
||||
#define _SESSION_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/list.h>
|
||||
|
||||
/* local includes */
|
||||
#include "string.h"
|
||||
|
||||
class Texture;
|
||||
class View;
|
||||
class Session;
|
||||
|
||||
namespace Input { class Event; }
|
||||
|
||||
class Session
|
||||
typedef Genode::List<Session> Session_list;
|
||||
|
||||
class Session : public Session_list::Element
|
||||
{
|
||||
public:
|
||||
|
||||
|
@ -23,11 +23,17 @@
|
||||
#include "mode.h"
|
||||
#include "menubar.h"
|
||||
#include "view_stack.h"
|
||||
#include "global_keys.h"
|
||||
|
||||
class User_state : public Mode, public View_stack
|
||||
{
|
||||
private:
|
||||
|
||||
/*
|
||||
* Policy for the routing of global keys
|
||||
*/
|
||||
Global_keys &_global_keys;
|
||||
|
||||
/*
|
||||
* Number of currently pressed keys.
|
||||
* This counter is used to determine if the user
|
||||
@ -52,12 +58,22 @@ class User_state : public Mode, public View_stack
|
||||
*/
|
||||
View *_pointed_view;
|
||||
|
||||
/*
|
||||
* Session that receives the current stream of input events
|
||||
*/
|
||||
Session *_input_receiver;
|
||||
|
||||
/*
|
||||
* True while a global key sequence is processed
|
||||
*/
|
||||
bool _global_key_sequence;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
User_state(Canvas *canvas, Menubar *menubar);
|
||||
User_state(Global_keys &global_keys, Canvas *canvas, Menubar *menubar);
|
||||
|
||||
/**
|
||||
* Handle input event
|
||||
|
Loading…
x
Reference in New Issue
Block a user