os: new Input::Event representation

This commit changes the 'Input::Event' type to be more safe and to
deliver symbolic character information along with press events.

Issue #2761
Fixes #2786
This commit is contained in:
Norman Feske 2018-04-20 14:27:45 +02:00 committed by Christian Helmuth
parent df3ceda052
commit afcad2a968
46 changed files with 1170 additions and 1209 deletions

View File

@ -200,12 +200,12 @@ if { [have_include "power_on/qemu"] || ![get_cmd_switch --autopilot] } { run_gen
# autopilot test # autopilot test
run_genode_until {\[init -\> test-input\] Input event #1\t} 60 run_genode_until {\[init -\> test-input\] Input event #0\t} 60
# remove everything before the first interesting line # remove everything before the first interesting line
regexp {(\[init -\> test-input\] Input event #1\t.*)} $output all output regexp {(\[init -\> test-input\] Input event #0\t.*)} $output all output
run_genode_until {\[init -\> test-input\] Input event #12.*\n} 40 [output_spawn_id] run_genode_until {\[init -\> test-input\] Input event #11.*\n} 40 [output_spawn_id]
# pay only attention to the output of init and its children # pay only attention to the output of init and its children
grep_output {^\[init } grep_output {^\[init }
@ -220,22 +220,22 @@ filter_out_color_escape_sequences
trim_lines trim_lines
compare_output_to { compare_output_to {
[init -> test-input] Input event #1 type=PRESS code=45 rx=0 ry=0 ax=0 ay=0 key_cnt=1 KEY_X [init -> test-input] Input event #0 PRESS KEY_X 0
[init -> test-input] Input event #2 type=RELEASE code=45 rx=0 ry=0 ax=0 ay=0 key_cnt=0 KEY_X [init -> test-input] Input event #1 RELEASE KEY_X
[init -> test-input] Input event #3 type=PRESS code=272 rx=0 ry=0 ax=0 ay=0 key_cnt=1 BTN_LEFT [init -> test-input] Input event #2 PRESS BTN_LEFT 0
[init -> test-input] Input event #4 type=MOTION code=0 rx=-1 ry=0 ax=0 ay=0 key_cnt=1 [init -> test-input] Input event #3 REL_MOTION -1+0
[init -> test-input] Input event #5 type=MOTION code=0 rx=0 ry=1 ax=0 ay=0 key_cnt=1 [init -> test-input] Input event #4 REL_MOTION +0+1
[init -> test-input] Input event #6 type=RELEASE code=272 rx=0 ry=0 ax=0 ay=0 key_cnt=0 BTN_LEFT [init -> test-input] Input event #5 RELEASE BTN_LEFT
[init -> usb_drv] dev_info: USB disconnect, device [init -> usb_drv] dev_info: USB disconnect, device
[init -> usb_drv] dev_info: new full-speed USB device [init -> usb_drv] dev_info: new full-speed USB device
[init -> usb_drv] dev_info: D L [init -> usb_drv] dev_info: D L
[init -> usb_drv] dev_info: input: USB HID v1.11 Keyboard [D L] [init -> usb_drv] dev_info: input: USB HID v1.11 Keyboard [D L]
[init -> usb_drv] dev_info: D L [init -> usb_drv] dev_info: D L
[init -> usb_drv] dev_info: input: USB HID v1.11 Mouse [D L] [init -> usb_drv] dev_info: input: USB HID v1.11 Mouse [D L]
[init -> test-input] Input event #7 type=PRESS code=45 rx=0 ry=0 ax=0 ay=0 key_cnt=1 KEY_X [init -> test-input] Input event #6 PRESS KEY_X 0
[init -> test-input] Input event #8 type=RELEASE code=45 rx=0 ry=0 ax=0 ay=0 key_cnt=0 KEY_X [init -> test-input] Input event #7 RELEASE KEY_X
[init -> test-input] Input event #9 type=PRESS code=272 rx=0 ry=0 ax=0 ay=0 key_cnt=1 BTN_LEFT [init -> test-input] Input event #8 PRESS BTN_LEFT 0
[init -> test-input] Input event #10 type=MOTION code=0 rx=-1 ry=0 ax=0 ay=0 key_cnt=1 [init -> test-input] Input event #9 REL_MOTION -1+0
[init -> test-input] Input event #11 type=MOTION code=0 rx=0 ry=1 ax=0 ay=0 key_cnt=1 [init -> test-input] Input event #10 REL_MOTION +0+1
[init -> test-input] Input event #12 type=RELEASE code=272 rx=0 ry=0 ax=0 ay=0 key_cnt=0 BTN_LEFT [init -> test-input] Input event #11 RELEASE BTN_LEFT
} }

View File

@ -41,22 +41,33 @@ static Genode::Constructible<Input::Root_component> _input_root;
* Input event call-back function * Input event call-back function
*/ */
static void input_callback(enum input_event_type type, static void input_callback(enum input_event_type type,
unsigned code, unsigned code, int ax, int ay, int rx, int ry)
int absolute_x, int absolute_y,
int relative_x, int relative_y)
{ {
Input::Event::Type t = Input::Event::INVALID; using namespace Input;
switch (type) {
case EVENT_TYPE_PRESS: t = Input::Event::PRESS; break;
case EVENT_TYPE_RELEASE: t = Input::Event::RELEASE; break;
case EVENT_TYPE_MOTION: t = Input::Event::MOTION; break;
case EVENT_TYPE_WHEEL: t = Input::Event::WHEEL; break;
case EVENT_TYPE_TOUCH: t = Input::Event::TOUCH; break;
}
_input_session->submit(Input::Event(t, code, auto submit = [&] (Event const &ev) { _input_session->submit(ev); };
absolute_x, absolute_y,
relative_x, relative_y)); switch (type) {
case EVENT_TYPE_PRESS: submit(Press{Keycode(code)}); break;
case EVENT_TYPE_RELEASE: submit(Release{Keycode(code)}); break;
case EVENT_TYPE_MOTION:
if (rx == 0 && ry == 0)
submit(Absolute_motion{ax, ay});
else
submit(Relative_motion{rx, ry});
break;
case EVENT_TYPE_WHEEL: submit(Wheel{rx, ry}); break;
case EVENT_TYPE_TOUCH:
{
Touch_id const id { (int)code };
if (rx == -1 && ry == -1)
submit(Touch_release{id});
else
submit(Touch{id, (float)ax, (float)ay});
break;
}
}
} }

View File

@ -95,28 +95,25 @@ class Scout::Platform
{ {
if (_input.pending() == false) return; if (_input.pending() == false) return;
for (int i = 0, num = _input.flush(); i < num; i++) for (int i = 0, num = _input.flush(); i < num; i++) {
{
Event ev; Event ev;
Input::Event e = _ev_buf[i]; Input::Event e = _ev_buf[i];
_event_pending = i + 1 < num; _event_pending = i + 1 < num;
if (e.type() == Input::Event::RELEASE e.handle_press([&] (Input::Keycode key, Genode::Codepoint) {
|| e.type() == Input::Event::PRESS) { ev.assign(Event::PRESS, _mx, _my, key); });
_mx = e.ax();
_my = e.ay();
ev.assign(e.type() == Input::Event::PRESS ? Event::PRESS : Event::RELEASE,
e.ax(), e.ay(), e.code());
_handle_event(ev);
}
if (e.type() == Input::Event::MOTION) { e.handle_release([&] (Input::Keycode key) {
_mx = e.ax(); ev.assign(Event::RELEASE, _mx, _my, key); });
_my = e.ay();
ev.assign(Event::MOTION, e.ax(), e.ay(), e.code()); e.handle_absolute_motion([&] (int x, int y) {
_mx = x; _my = y;
ev.assign(Event::MOTION, _mx, _my, 0);
});
if (ev.type != Event::UNDEFINED)
_handle_event(ev); _handle_event(ev);
}
} }
} }

View File

@ -61,23 +61,16 @@ class Window_content : public Scout::Element
Point mouse_position = ev.mouse_position - _element->abs_position(); Point mouse_position = ev.mouse_position - _element->abs_position();
int code = 0; auto motion = [&] (Point p) { return Input::Absolute_motion{p.x(), p.y()}; };
if (ev.type == Event::PRESS || ev.type == Event::RELEASE) if (ev.type == Event::MOTION)
code = ev.code; _input_session.submit(motion(mouse_position));
Input::Event::Type type; if (ev.type == Event::PRESS)
_input_session.submit(Input::Press{Input::Keycode(ev.code)});
type = (ev.type == Event::MOTION) ? Input::Event::MOTION if (ev.type == Event::RELEASE)
: (ev.type == Event::PRESS) ? Input::Event::PRESS _input_session.submit(Input::Release{Input::Keycode(ev.code)});
: (ev.type == Event::RELEASE) ? Input::Event::RELEASE
: Input::Event::INVALID;
if (type != Input::Event::INVALID)
_input_session.submit(Input::Event(type, code, mouse_position.x(),
mouse_position.y(),
mouse_position.x() - _old_mouse_position.x(),
mouse_position.y() - _old_mouse_position.y()));
_old_mouse_position = mouse_position; _old_mouse_position = mouse_position;
} }

View File

@ -448,7 +448,9 @@ struct Nitlog::Main
Attached_dataspace _ev_ds { _env.rm(), _nitpicker.input()->dataspace() }; Attached_dataspace _ev_ds { _env.rm(), _nitpicker.input()->dataspace() };
Nitpicker::Point _old_mouse_pos { }; Nitpicker::Point const _initial_mouse_pos { -1, -1 };
Nitpicker::Point _old_mouse_pos = _initial_mouse_pos;
unsigned _key_cnt = 0; unsigned _key_cnt = 0;
@ -463,20 +465,24 @@ struct Nitlog::Main
Input::Event const &ev = ev_buf[i]; Input::Event const &ev = ev_buf[i];
if (ev.type() == Input::Event::PRESS) _key_cnt++; if (ev.press()) _key_cnt++;
if (ev.type() == Input::Event::RELEASE) _key_cnt--; if (ev.release()) _key_cnt--;
Nitpicker::Point mouse_pos(ev.ax(), ev.ay());
/* move view */ /* move view */
if (ev.type() == Input::Event::MOTION && _key_cnt > 0) ev.handle_absolute_motion([&] (int x, int y) {
_view.move(_view.pos() + mouse_pos - _old_mouse_pos);
Nitpicker::Point const mouse_pos(x, y);
if (_key_cnt && _old_mouse_pos != _initial_mouse_pos)
_view.move(_view.pos() + mouse_pos - _old_mouse_pos);
_old_mouse_pos = mouse_pos;
});
/* find selected view and bring it to front */ /* find selected view and bring it to front */
if (ev.type() == Input::Event::PRESS && _key_cnt == 1) if (ev.press() && _key_cnt == 1)
_view.top(); _view.top();
_old_mouse_pos = mouse_pos;
} }
} }

View File

@ -206,24 +206,24 @@ class Floating_window_layouter::Key_sequence_tracker
* to preserver the invariant that each key is present only * to preserver the invariant that each key is present only
* once. * once.
*/ */
if (ev.type() == Input::Event::PRESS) { ev.handle_press([&] (Input::Keycode key, Codepoint) {
_stack.flush(Stack::Entry(Stack::Entry::PRESS, ev.keycode())); _stack.flush(Stack::Entry(Stack::Entry::PRESS, key));
_stack.flush(Stack::Entry(Stack::Entry::RELEASE, ev.keycode())); _stack.flush(Stack::Entry(Stack::Entry::RELEASE, key));
} });
Xml_node curr_node = _xml_by_path(config); Xml_node curr_node = _xml_by_path(config);
if (ev.type() == Input::Event::PRESS) { ev.handle_press([&] (Input::Keycode key, Codepoint) {
Stack::Entry const entry(Stack::Entry::PRESS, ev.keycode()); Stack::Entry const entry(Stack::Entry::PRESS, key);
_execute_action(_matching_sub_node(curr_node, entry), func); _execute_action(_matching_sub_node(curr_node, entry), func);
_stack.push(entry); _stack.push(entry);
} });
if (ev.type() == Input::Event::RELEASE) { ev.handle_release([&] (Input::Keycode key) {
Stack::Entry const entry(Stack::Entry::RELEASE, ev.keycode()); Stack::Entry const entry(Stack::Entry::RELEASE, key);
Xml_node const next_node = _matching_sub_node(curr_node, entry); Xml_node const next_node = _matching_sub_node(curr_node, entry);
@ -239,10 +239,10 @@ class Floating_window_layouter::Key_sequence_tracker
} else { } else {
Stack::Entry entry(Stack::Entry::PRESS, ev.keycode()); Stack::Entry entry(Stack::Entry::PRESS, key);
_stack.flush(entry); _stack.flush(entry);
} }
} });
} }
}; };

View File

@ -75,13 +75,22 @@ class Floating_window_layouter::User_state
Focus_history &_focus_history; Focus_history &_focus_history;
/*
* Return true if key is potentially part of a key sequence
*/
static bool _key(Input::Keycode key) { return key != Input::BTN_LEFT; }
bool _key(Input::Event const &ev) const bool _key(Input::Event const &ev) const
{ {
if (ev.type() != Input::Event::PRESS bool relevant = false;
&& ev.type() != Input::Event::RELEASE)
return false;
return ev.keycode() != Input::BTN_LEFT; ev.handle_press([&] (Input::Keycode key, Codepoint) {
relevant |= _key(key); });
ev.handle_release([&] (Input::Keycode key) {
relevant |= _key(key); });
return relevant;
} }
inline void _handle_event(Input::Event const &, Xml_node); inline void _handle_event(Input::Event const &, Xml_node);
@ -214,10 +223,10 @@ class Floating_window_layouter::User_state
void Floating_window_layouter::User_state::_handle_event(Input::Event const &e, void Floating_window_layouter::User_state::_handle_event(Input::Event const &e,
Xml_node config) Xml_node config)
{ {
if (e.type() == Input::Event::MOTION e.handle_absolute_motion([&] (int x, int y) {
|| e.type() == Input::Event::FOCUS) { _pointer_curr = Point(x, y); });
_pointer_curr = Point(e.ax(), e.ay()); if (e.absolute_motion() || e.focus_enter()) {
if (_drag_state && _drag_init_done) if (_drag_state && _drag_init_done)
_operations.drag(_dragged_window_id, _dragged_element, _operations.drag(_dragged_window_id, _dragged_element,
@ -225,13 +234,11 @@ void Floating_window_layouter::User_state::_handle_event(Input::Event const &e,
} }
/* track number of pressed buttons/keys */ /* track number of pressed buttons/keys */
if (e.type() == Input::Event::PRESS) _key_cnt++; if (e.press()) _key_cnt++;
if (e.type() == Input::Event::RELEASE) _key_cnt--; if (e.release()) _key_cnt--;
/* handle pointer click */ /* handle pointer click */
if (e.type() == Input::Event::PRESS if (e.key_press(Input::BTN_LEFT) && _key_cnt == 1) {
&& e.keycode() == Input::BTN_LEFT
&& _key_cnt == 1) {
/* /*
* Initiate drag operation if possible * Initiate drag operation if possible
@ -266,9 +273,7 @@ void Floating_window_layouter::User_state::_handle_event(Input::Event const &e,
} }
/* detect end of drag operation */ /* detect end of drag operation */
if (e.type() == Input::Event::RELEASE if (e.release() && _key_cnt == 0 && _dragged_window_id.valid()) {
&& _key_cnt == 0
&& _dragged_window_id.valid()) {
_drag_state = false; _drag_state = false;
@ -288,7 +293,7 @@ void Floating_window_layouter::User_state::_handle_event(Input::Event const &e,
/* handle key sequences */ /* handle key sequences */
if (_key(e)) { if (_key(e)) {
if (e.type() == Input::Event::PRESS && _key_cnt == 1) if (e.press() && _key_cnt == 1)
_key_sequence_tracker.reset(); _key_sequence_tracker.reset();
_key_sequence_tracker.apply(e, config, [&] (Action action) { _key_sequence_tracker.apply(e, config, [&] (Action action) {
@ -320,7 +325,7 @@ void Floating_window_layouter::User_state::_handle_event(Input::Event const &e,
} }
/* update focus history after key/button action is completed */ /* update focus history after key/button action is completed */
if (e.type() == Input::Event::RELEASE && _key_cnt == 0) if (e.release() && _key_cnt == 0)
_focus_history.focus(_focused_window_id); _focus_history.focus(_focused_window_id);
} }

View File

@ -169,7 +169,7 @@ class Launcher::Context_dialog : Input_event_handler, Dialog_generator,
*/ */
bool handle_input_event(Input::Event const &ev) override bool handle_input_event(Input::Event const &ev) override
{ {
if (ev.type() == Input::Event::MOTION) { if (ev.absolute_motion()) {
/* /*
* Re-enable the visibility of the menu if we detect motion * Re-enable the visibility of the menu if we detect motion
@ -182,17 +182,15 @@ class Launcher::Context_dialog : Input_event_handler, Dialog_generator,
return true; return true;
} }
if (ev.type() == Input::Event::LEAVE) { if (ev.hover_leave()) {
visible(false); visible(false);
return true; return true;
} }
if (ev.type() == Input::Event::PRESS) _key_cnt++; if (ev.press()) _key_cnt++;
if (ev.type() == Input::Event::RELEASE) _key_cnt--; if (ev.release()) _key_cnt--;
if (ev.type() == Input::Event::PRESS if (ev.key_press(Input::BTN_LEFT) && _key_cnt == 1) {
&& ev.keycode() == Input::BTN_LEFT
&& _key_cnt == 1) {
Label const hovered = _hovered(); Label const hovered = _hovered();
@ -202,8 +200,7 @@ class Launcher::Context_dialog : Input_event_handler, Dialog_generator,
dialog_changed(); dialog_changed();
} }
if (ev.type() == Input::Event::RELEASE if (ev.release() && _click_in_progress && _key_cnt == 0) {
&& _click_in_progress && _key_cnt == 0) {
Label const hovered = _hovered(); Label const hovered = _hovered();

View File

@ -137,8 +137,8 @@ void Launcher::Main::_handle_config()
void Launcher::Main::_handle_input() void Launcher::Main::_handle_input()
{ {
_nitpicker.input()->for_each_event([&] (Input::Event const &e) { _nitpicker.input()->for_each_event([&] (Input::Event const &e) {
if (e.type() == Input::Event::PRESS) _key_cnt++; if (e.press()) _key_cnt++;
if (e.type() == Input::Event::RELEASE) _key_cnt--; if (e.release()) _key_cnt--;
/* /*
* The _key_cnt can become 2 only when the global key (as configured * The _key_cnt can become 2 only when the global key (as configured
@ -146,11 +146,8 @@ void Launcher::Main::_handle_input()
* Hence, the following condition triggers on key combinations with * Hence, the following condition triggers on key combinations with
* the global modifier key, whatever the global modifier key is. * the global modifier key, whatever the global modifier key is.
*/ */
if (e.type() == Input::Event::PRESS && _key_cnt == 2) { if (e.key_press(Input::KEY_TAB) && _key_cnt == 2)
_panel_dialog.focus_next();
if (e.keycode() == Input::KEY_TAB)
_panel_dialog.focus_next();
}
}); });
} }

View File

@ -185,12 +185,12 @@ class Launcher::Menu_dialog : Input_event_handler, Dialog_generator,
*/ */
bool handle_input_event(Input::Event const &ev) override bool handle_input_event(Input::Event const &ev) override
{ {
if (ev.type() == Input::Event::LEAVE) { if (ev.hover_leave()) {
_response_handler.handle_menu_leave(); _response_handler.handle_menu_leave();
return false; return false;
} }
if (ev.type() == Input::Event::MOTION) { if (ev.absolute_motion()) {
_response_handler.handle_menu_motion(); _response_handler.handle_menu_motion();
@ -205,15 +205,11 @@ class Launcher::Menu_dialog : Input_event_handler, Dialog_generator,
return true; return true;
} }
if (ev.type() == Input::Event::PRESS) _key_cnt++; if (ev.press()) _key_cnt++;
if (ev.type() == Input::Event::RELEASE) _key_cnt--; if (ev.release()) _key_cnt--;
if (ev.type() == Input::Event::PRESS if (ev.key_press(Input::BTN_LEFT) && _key_cnt == 1)
&& ev.keycode() == Input::BTN_LEFT _response_handler.handle_selection(_hovered());
&& _key_cnt == 1) {
_response_handler.handle_selection(_hovered());
}
return false; return false;
} }

View File

@ -345,7 +345,7 @@ class Launcher::Panel_dialog : Input_event_handler, Dialog_generator,
*/ */
bool handle_input_event(Input::Event const &ev) override bool handle_input_event(Input::Event const &ev) override
{ {
if (ev.type() == Input::Event::LEAVE) { if (ev.hover_leave()) {
/* /*
* Let menu dialog disappear when the panel is unhovered. One * Let menu dialog disappear when the panel is unhovered. One
@ -362,15 +362,13 @@ class Launcher::Panel_dialog : Input_event_handler, Dialog_generator,
return true; return true;
} }
if (ev.type() == Input::Event::MOTION) if (ev.absolute_motion())
return true; return true;
if (ev.type() == Input::Event::PRESS) _key_cnt++; if (ev.press()) _key_cnt++;
if (ev.type() == Input::Event::RELEASE) _key_cnt--; if (ev.release()) _key_cnt--;
if (ev.type() == Input::Event::PRESS if (ev.key_press(Input::BTN_LEFT) && _key_cnt == 1) {
&& ev.keycode() == Input::BTN_LEFT
&& _key_cnt == 1) {
_context_dialog.visible(false); _context_dialog.visible(false);
@ -412,9 +410,7 @@ class Launcher::Panel_dialog : Input_event_handler, Dialog_generator,
/* /*
* Open context dialog on right click * Open context dialog on right click
*/ */
if (ev.type() == Input::Event::PRESS if (ev.key_press(Input::BTN_RIGHT) && _key_cnt == 1) {
&& ev.keycode() == Input::BTN_RIGHT
&& _key_cnt == 1) {
Element *hovered = _hovered(); Element *hovered = _hovered();
@ -422,8 +418,7 @@ class Launcher::Panel_dialog : Input_event_handler, Dialog_generator,
_open_context_dialog(hovered->label); _open_context_dialog(hovered->label);
} }
if (ev.type() == Input::Event::RELEASE if (ev.release() && _click_in_progress && _key_cnt == 0) {
&& _click_in_progress && _key_cnt == 0) {
Element *hovered = _hovered(); Element *hovered = _hovered();

View File

@ -234,9 +234,9 @@ void Menu_view::Main::_handle_config()
void Menu_view::Main::_handle_input() void Menu_view::Main::_handle_input()
{ {
_nitpicker.input()->for_each_event([&] (Input::Event const &ev) { _nitpicker.input()->for_each_event([&] (Input::Event const &ev) {
if (ev.absolute_motion()) { ev.handle_absolute_motion([&] (int x, int y) {
Point const at = Point(ev.ax(), ev.ay()) - _position; Point const at = Point(x, y) - _position;
Widget::Unique_id const new_hovered = _root_widget.hovered(at); Widget::Unique_id const new_hovered = _root_widget.hovered(at);
if (_hovered != new_hovered) { if (_hovered != new_hovered) {
@ -249,14 +249,12 @@ void Menu_view::Main::_handle_input()
_hovered = new_hovered; _hovered = new_hovered;
} }
} });
/* /*
* Reset hover model when losing the focus * Reset hover model when losing the focus
*/ */
if ((ev.type() == Input::Event::FOCUS && ev.code() == 0) if (ev.focus_leave() || ev.hover_leave()) {
|| (ev.type() == Input::Event::LEAVE)) {
_hovered = Widget::Unique_id(); _hovered = Widget::Unique_id();
if (_hover_reporter.enabled()) { if (_hover_reporter.enabled()) {

View File

@ -220,11 +220,30 @@ void Terminal::Main::_handle_input()
{ {
_input.for_each_event([&] (Input::Event const &event) { _input.for_each_event([&] (Input::Event const &event) {
if (event.type() == Input::Event::CHARACTER) { event.handle_press([&] (Input::Keycode, Codepoint codepoint) {
Input::Event::Utf8 const utf8 = event.utf8();
char const sequence[] { (char)utf8.b0, (char)utf8.b1, struct Utf8 { char b0, b1, b2, b3, b4; };
(char)utf8.b2, (char)utf8.b3, 0 };
auto utf8_from_codepoint = [] (unsigned c) {
/* extract 'n' bits 'at' bit position of value 'c' */
auto bits = [c] (unsigned at, unsigned n) {
return (c >> at) & ((1 << n) - 1); };
return (c < 2<<7) ? Utf8 { char(bits( 0, 7)), 0, 0, 0, 0 }
: (c < 2<<11) ? Utf8 { char(bits( 6, 5) | 0xc0),
char(bits( 0, 6) | 0x80), 0, 0, 0 }
: (c < 2<<16) ? Utf8 { char(bits(12, 4) | 0xe0),
char(bits( 6, 6) | 0x80),
char(bits( 0, 6) | 0x80), 0, 0 }
: (c < 2<<21) ? Utf8 { char(bits(18, 3) | 0xf0),
char(bits(12, 6) | 0x80),
char(bits( 6, 6) | 0x80),
char(bits( 0, 6) | 0x80), 0 }
: Utf8 { };
};
Utf8 const sequence = utf8_from_codepoint(codepoint.value);
/* function-key unicodes */ /* function-key unicodes */
enum { enum {
@ -241,8 +260,6 @@ void Terminal::Main::_handle_input()
CODEPOINT_PAGEUP = 0xf72c, CODEPOINT_PAGEDOWN = 0xf72d, CODEPOINT_PAGEUP = 0xf72c, CODEPOINT_PAGEDOWN = 0xf72d,
}; };
Codepoint const codepoint = Utf8_ptr(sequence).codepoint();
char const *special_sequence = nullptr; char const *special_sequence = nullptr;
switch (codepoint.value) { switch (codepoint.value) {
case CODEPOINT_UP: special_sequence = "\EOA"; break; case CODEPOINT_UP: special_sequence = "\EOA"; break;
@ -272,8 +289,8 @@ void Terminal::Main::_handle_input()
if (special_sequence) if (special_sequence)
_read_buffer.add(special_sequence); _read_buffer.add(special_sequence);
else else
_read_buffer.add(sequence); _read_buffer.add(&sequence.b0);
} });
}); });
} }

View File

@ -225,18 +225,18 @@ struct Wm::Decorator_nitpicker_session : Genode::Rpc_object<Nitpicker::Session>,
while (_nitpicker_session.input()->pending()) while (_nitpicker_session.input()->pending())
_nitpicker_session.input()->for_each_event([&] (Input::Event const &ev) { _nitpicker_session.input()->for_each_event([&] (Input::Event const &ev) {
if (ev.type() == Input::Event::MOTION) { ev.handle_absolute_motion([&] (int x, int y) {
_last_motion = LAST_MOTION_DECORATOR; _last_motion = LAST_MOTION_DECORATOR;
Reporter::Xml_generator xml(_pointer_reporter, [&] () Reporter::Xml_generator xml(_pointer_reporter, [&] ()
{ {
xml.attribute("xpos", ev.ax()); xml.attribute("xpos", x);
xml.attribute("ypos", ev.ay()); xml.attribute("ypos", y);
}); });
} });
if (ev.type() == Input::Event::LEAVE) { if (ev.hover_leave()) {
/* /*
* Invalidate pointer as reported to the decorator if the * Invalidate pointer as reported to the decorator if the

View File

@ -451,6 +451,8 @@ class Wm::Nitpicker::Session_component : public Rpc_object<Nitpicker::Session>,
Area _requested_size; Area _requested_size;
bool _resize_requested = false; bool _resize_requested = false;
bool _has_alpha = false; bool _has_alpha = false;
Point const _initial_pointer_pos { -1, -1 };
Point _pointer_pos = _initial_pointer_pos;
/* /*
* Command buffer * Command buffer
@ -492,34 +494,14 @@ class Wm::Nitpicker::Session_component : public Rpc_object<Nitpicker::Session>,
/** /**
* Translate input event to the client's coordinate system * Translate input event to the client's coordinate system
*/ */
Input::Event _translate_event(Input::Event const ev, Point const input_origin) Input::Event _translate_event(Input::Event ev, Point const origin)
{ {
switch (ev.type()) { ev.handle_absolute_motion([&] (int x, int y) {
Point p = Point(x, y) + origin;
ev = Input::Absolute_motion{p.x(), p.y()};
});
case Input::Event::MOTION: return ev;
case Input::Event::PRESS:
case Input::Event::RELEASE:
case Input::Event::FOCUS:
case Input::Event::LEAVE:
{
Point abs_pos = Point(ev.ax(), ev.ay()) + input_origin;
return Input::Event(ev.type(), ev.code(),
abs_pos.x(), abs_pos.y(), 0, 0);
}
case Input::Event::TOUCH:
case Input::Event::CHARACTER:
case Input::Event::WHEEL:
{
Point abs_pos = Point(ev.ax(), ev.ay()) + input_origin;
return Input::Event(ev.type(), ev.code(),
abs_pos.x(), abs_pos.y(), ev.rx(), ev.ry());
}
case Input::Event::INVALID:
return ev;
}
return Input::Event();
} }
bool _click_into_unfocused_view(Input::Event const ev) bool _click_into_unfocused_view(Input::Event const ev)
@ -530,7 +512,7 @@ class Wm::Nitpicker::Session_component : public Rpc_object<Nitpicker::Session>,
* Right now, we report more butten events to the layouter * Right now, we report more butten events to the layouter
* than the layouter really needs. * than the layouter really needs.
*/ */
if (ev.type() == Input::Event::PRESS && ev.keycode() == Input::BTN_LEFT) if (ev.key_press(Input::BTN_LEFT))
return true; return true;
return false; return false;
@ -555,20 +537,24 @@ class Wm::Nitpicker::Session_component : public Rpc_object<Nitpicker::Session>,
Input::Event const ev = events[i]; Input::Event const ev = events[i];
/* keep track of pointer position */
ev.handle_absolute_motion([&] (int x, int y) {
_pointer_pos = Point(x, y); });
/* propagate layout-affecting events to the layouter */ /* propagate layout-affecting events to the layouter */
if (_click_into_unfocused_view(ev)) if (_click_into_unfocused_view(ev))
_click_handler.handle_click(Point(ev.ax(), ev.ay())); _click_handler.handle_click(_pointer_pos);
/* /*
* Reset pointer model for the decorator once the pointer * Reset pointer model for the decorator once the pointer
* enters the application area of a window. * enters the application area of a window.
*/ */
if (ev.type() == Input::Event::MOTION && _first_motion) { if (ev.absolute_motion() && _first_motion) {
_click_handler.handle_enter(Point(ev.ax(), ev.ay())); _click_handler.handle_enter(_pointer_pos);
_first_motion = false; _first_motion = false;
} }
if (ev.type() == Input::Event::LEAVE) if (ev.hover_leave())
_first_motion = true; _first_motion = true;
/* submit event to the client */ /* submit event to the client */
@ -1016,12 +1002,6 @@ class Wm::Nitpicker::Root : public Genode::Rpc_object<Genode::Typed_root<Session
Reporter &pointer_reporter; Reporter &pointer_reporter;
Last_motion &last_motion; Last_motion &last_motion;
void _submit_button_event(Input::Event::Type type, Nitpicker::Point pos)
{
window_layouter_input.submit(Input::Event(type, Input::BTN_LEFT,
pos.x(), pos.y(), 0, 0));
}
void handle_enter(Nitpicker::Point pos) override void handle_enter(Nitpicker::Point pos) override
{ {
last_motion = LAST_MOTION_NITPICKER; last_motion = LAST_MOTION_NITPICKER;
@ -1049,8 +1029,9 @@ class Wm::Nitpicker::Root : public Genode::Rpc_object<Genode::Typed_root<Session
* Supply artificial mouse click to the decorator's input session * Supply artificial mouse click to the decorator's input session
* (which is routed to the layouter). * (which is routed to the layouter).
*/ */
_submit_button_event(Input::Event::PRESS, pos); window_layouter_input.submit(Input::Absolute_motion{pos.x(), pos.y()});
_submit_button_event(Input::Event::RELEASE, pos); window_layouter_input.submit(Input::Press{Input::BTN_LEFT});
window_layouter_input.submit(Input::Release{Input::BTN_LEFT});
} }
Click_handler(Input::Session_component &window_layouter_input, Click_handler(Input::Session_component &window_layouter_input,

View File

@ -185,6 +185,7 @@ proc drivers_start_nodes { feature_arg } {
if { [use_input_filter feature] } { if { [use_input_filter feature] } {
exec cp -f [genode_dir]/repos/os/src/server/input_filter/[language_chargen].chargen bin/ exec cp -f [genode_dir]/repos/os/src/server/input_filter/[language_chargen].chargen bin/
exec cp -f [genode_dir]/repos/os/src/server/input_filter/special.chargen bin/
append start_nodes { append start_nodes {
<start name="input_filter"> <start name="input_filter">
@ -222,6 +223,7 @@ proc drivers_start_nodes { feature_arg } {
append start_nodes " append start_nodes "
<include rom=\"[language_chargen].chargen\"/>" <include rom=\"[language_chargen].chargen\"/>"
append start_nodes { append start_nodes {
<include rom="special.chargen"/>
</chargen> </chargen>
</output> </output>
</config> </config>
@ -310,6 +312,7 @@ proc drivers_boot_modules { feature_arg } {
lappend_if [use_gpio_drv feature] boot_modules [gpio_drv] lappend_if [use_gpio_drv feature] boot_modules [gpio_drv]
lappend_if [use_input_filter feature] boot_modules input_filter lappend_if [use_input_filter feature] boot_modules input_filter
lappend_if [use_input_filter feature] boot_modules [language_chargen].chargen lappend_if [use_input_filter feature] boot_modules [language_chargen].chargen
lappend_if [use_input_filter feature] boot_modules special.chargen
lappend_if [use_nic_drv feature] boot_modules [nic_drv_binary] lappend_if [use_nic_drv feature] boot_modules [nic_drv_binary]
lappend_if [use_ps2_drv feature] boot_modules ps2_drv lappend_if [use_ps2_drv feature] boot_modules ps2_drv
lappend_if [use_timer feature] boot_modules timer lappend_if [use_timer feature] boot_modules timer

View File

@ -377,12 +377,10 @@ struct Main
void _handle_input() void _handle_input()
{ {
_input.for_each_event([&] (Input::Event const &ev) { _input.for_each_event([&] (Input::Event const &ev) {
ev.handle_press([&] (Input::Keycode key, Genode::Codepoint) {
if (ev.type() == Input::Event::PRESS) { int const ascii = keycode_to_ascii(key);
int const ascii = keycode_to_ascii(ev.code());
if (ascii) { _pdf_view.handle_key(ascii); } if (ascii) { _pdf_view.handle_key(ascii); }
} });
}); });
} }

View File

@ -24,15 +24,15 @@
void Control_bar::_rewind() void Control_bar::_rewind()
{ {
/* mouse click at horizontal position 0 */ /* mouse click at horizontal position 0 */
_input.submit(Input::Event(Input::Event::PRESS, Input::BTN_LEFT, 0, 0, 0, 0)); _input.submit(Input::Press {Input::BTN_LEFT});
_input.submit(Input::Event(Input::Event::RELEASE, Input::BTN_LEFT, 0, 0, 0, 0)); _input.submit(Input::Release{Input::BTN_LEFT});
} }
void Control_bar::_pause_resume() void Control_bar::_pause_resume()
{ {
_input.submit(Input::Event(Input::Event::PRESS, Input::KEY_SPACE, 0, 0, 0, 0)); _input.submit(Input::Press {Input::KEY_SPACE});
_input.submit(Input::Event(Input::Event::RELEASE, Input::KEY_SPACE, 0, 0, 0, 0)); _input.submit(Input::Release{Input::KEY_SPACE});
_playing = !_playing; _playing = !_playing;
if (_playing) if (_playing)

View File

@ -53,130 +53,133 @@ void QNitpickerPlatformWindow::_process_touch_events(QList<Input::Event> const &
QList<QWindowSystemInterface::TouchPoint> touch_points; QList<QWindowSystemInterface::TouchPoint> touch_points;
for (QList<Input::Event>::const_iterator i = events.begin(); i != events.end(); ++i) { for (QList<Input::Event>::const_iterator i = events.begin(); i != events.end(); ++i) {
/* i->handle_touch([&] (Input::Touch_id id, int x, int y) {
* Coordinates must be normalized to positions of the platform window.
* We lack information about the value ranges (min and max) of touch
* coordinates to normalize ourselves.
*/
QPointF const pos((qreal)i->ax(), (qreal)i->ay() );
QWindowSystemInterface::TouchPoint &otp = _touch_points[i->code()]; if (id.value >= _touch_points.size()) {
QWindowSystemInterface::TouchPoint tp; Genode::warning("drop touch input, out of bounds");
return;
}
tp.id = i->code(); QWindowSystemInterface::TouchPoint &otp = _touch_points[id.value];
tp.area = QRectF(QPointF(0, 0), QSize(1, 1)); QWindowSystemInterface::TouchPoint tp;
/* report 1x1 rectangular area centered at screen coordinates */ tp.id = id.value;
tp.area.moveCenter(QPointF(i->ax(), i->ay())); tp.area = QRectF(QPointF(0, 0), QSize(1, 1));
/* report 1x1 rectangular area centered at screen coordinates */
tp.area.moveCenter(QPointF(x, y));
if (i->rx() == -1 && i->ry() == -1) {
tp.state = Qt::TouchPointReleased;
tp.pressure = 0;
} else {
tp.state = otp.state == Qt::TouchPointReleased tp.state = otp.state == Qt::TouchPointReleased
? Qt::TouchPointPressed : Qt::TouchPointMoved; ? Qt::TouchPointPressed : Qt::TouchPointMoved;
tp.pressure = 1; tp.pressure = 1;
}
otp = tp; otp = tp;
touch_points.push_back(tp); touch_points.push_back(tp);
});
i->handle_touch_release([&] (Input::Touch_id id) {
if (id.value >= _touch_points.size()) {
Genode::warning("drop touch input, out of bounds");
return;
}
QWindowSystemInterface::TouchPoint &otp = _touch_points[id.value];
QWindowSystemInterface::TouchPoint tp;
tp.id = id.value;
tp.area = QRectF(QPointF(0, 0), QSize(1, 1));
tp.state = Qt::TouchPointReleased;
tp.pressure = 0;
otp = tp;
touch_points.push_back(tp);
});
} }
QWindowSystemInterface::handleTouchEvent(0, _touch_device, touch_points); QWindowSystemInterface::handleTouchEvent(0, _touch_device, touch_points);
} }
void QNitpickerPlatformWindow::_process_mouse_event(Input::Event const &ev)
static Qt::Key translate_keycode(Input::Keycode key)
{ {
QPoint global_position(ev.ax(), ev.ay()); switch (key) {
QPoint local_position(global_position.x() - geometry().x(), case Input::KEY_ENTER: return Qt::Key_Return;
global_position.y() - geometry().y()); case Input::KEY_ESC: return Qt::Key_Escape;
case Input::KEY_TAB: return Qt::Key_Tab;
switch (ev.type()) { case Input::KEY_BACKSPACE: return Qt::Key_Backspace;
case Input::KEY_INSERT: return Qt::Key_Insert;
case Input::Event::PRESS: case Input::KEY_DELETE: return Qt::Key_Delete;
case Input::KEY_PRINT: return Qt::Key_Print;
/* make this window the focused window */ case Input::KEY_CLEAR: return Qt::Key_Clear;
requestActivateWindow(); case Input::KEY_HOME: return Qt::Key_Home;
case Input::KEY_END: return Qt::Key_End;
switch (ev.code()) { case Input::KEY_LEFT: return Qt::Key_Left;
case Input::BTN_LEFT: case Input::KEY_UP: return Qt::Key_Up;
_mouse_button_state |= Qt::LeftButton; case Input::KEY_RIGHT: return Qt::Key_Right;
break; case Input::KEY_DOWN: return Qt::Key_Down;
case Input::BTN_RIGHT: case Input::KEY_PAGEUP: return Qt::Key_PageUp;
_mouse_button_state |= Qt::RightButton; case Input::KEY_PAGEDOWN: return Qt::Key_PageDown;
break; case Input::KEY_LEFTSHIFT: return Qt::Key_Shift;
case Input::BTN_MIDDLE: case Input::KEY_LEFTCTRL: return Qt::Key_Control;
_mouse_button_state |= Qt::MidButton; case Input::KEY_LEFTMETA: return Qt::Key_Meta;
break; case Input::KEY_LEFTALT: return Qt::Key_Alt;
case Input::BTN_SIDE: case Input::KEY_RIGHTALT: return Qt::Key_AltGr;
_mouse_button_state |= Qt::XButton1; case Input::KEY_CAPSLOCK: return Qt::Key_CapsLock;
break; case Input::KEY_F1: return Qt::Key_F1;
case Input::BTN_EXTRA: case Input::KEY_F2: return Qt::Key_F2;
_mouse_button_state |= Qt::XButton2; case Input::KEY_F3: return Qt::Key_F3;
break; case Input::KEY_F4: return Qt::Key_F4;
} case Input::KEY_F5: return Qt::Key_F5;
break; case Input::KEY_F6: return Qt::Key_F6;
case Input::KEY_F7: return Qt::Key_F7;
case Input::Event::RELEASE: case Input::KEY_F8: return Qt::Key_F8;
case Input::KEY_F9: return Qt::Key_F9;
switch (ev.code()) { case Input::KEY_F10: return Qt::Key_F10;
case Input::BTN_LEFT: case Input::KEY_F11: return Qt::Key_F11;
_mouse_button_state &= ~Qt::LeftButton; case Input::KEY_F12: return Qt::Key_F12;
break; case Input::KEY_SPACE: return Qt::Key_Space;
case Input::BTN_RIGHT: case Input::KEY_0: return Qt::Key_0;
_mouse_button_state &= ~Qt::RightButton; case Input::KEY_1: return Qt::Key_1;
break; case Input::KEY_2: return Qt::Key_2;
case Input::BTN_MIDDLE: case Input::KEY_3: return Qt::Key_3;
_mouse_button_state &= ~Qt::MidButton; case Input::KEY_4: return Qt::Key_4;
break; case Input::KEY_5: return Qt::Key_5;
case Input::BTN_SIDE: case Input::KEY_6: return Qt::Key_6;
_mouse_button_state &= ~Qt::XButton1; case Input::KEY_7: return Qt::Key_7;
break; case Input::KEY_8: return Qt::Key_8;
case Input::BTN_EXTRA: case Input::KEY_9: return Qt::Key_9;
_mouse_button_state &= ~Qt::XButton2; case Input::KEY_A: return Qt::Key_A;
break; case Input::KEY_B: return Qt::Key_B;
} case Input::KEY_C: return Qt::Key_C;
break; case Input::KEY_D: return Qt::Key_D;
case Input::KEY_E: return Qt::Key_E;
case Input::Event::WHEEL: case Input::KEY_F: return Qt::Key_F;
case Input::KEY_G: return Qt::Key_G;
QWindowSystemInterface::handleWheelEvent(window(), case Input::KEY_H: return Qt::Key_H;
local_position, case Input::KEY_I: return Qt::Key_I;
local_position, case Input::KEY_J: return Qt::Key_J;
ev.ry() * 120, case Input::KEY_K: return Qt::Key_K;
Qt::Vertical); case Input::KEY_L: return Qt::Key_L;
return; case Input::KEY_M: return Qt::Key_M;
case Input::KEY_N: return Qt::Key_N;
default: case Input::KEY_O: return Qt::Key_O;
break; case Input::KEY_P: return Qt::Key_P;
} case Input::KEY_Q: return Qt::Key_Q;
case Input::KEY_R: return Qt::Key_R;
QWindowSystemInterface::handleMouseEvent(window(), case Input::KEY_S: return Qt::Key_S;
local_position, case Input::KEY_T: return Qt::Key_T;
global_position, case Input::KEY_U: return Qt::Key_U;
_mouse_button_state); case Input::KEY_V: return Qt::Key_V;
} case Input::KEY_W: return Qt::Key_W;
case Input::KEY_X: return Qt::Key_X;
case Input::KEY_Y: return Qt::Key_Y;
void QNitpickerPlatformWindow::_process_key_event(Input::Event const &ev) case Input::KEY_Z: return Qt::Key_Z;
{ case Input::KEY_BACK: return Qt::Key_Back;
const bool pressed = (ev.type() == Input::Event::PRESS); case Input::KEY_FORWARD: return Qt::Key_Forward;
const int keycode = ev.code(); default: break;
};
if (pressed) { return Qt::Key_unknown;
_last_keycode = keycode;
_key_repeat_timer->start(KEY_REPEAT_DELAY_MS);
} else
_key_repeat_timer->stop();
_keyboard_handler.processKeycode(keycode, pressed, false);
}
void QNitpickerPlatformWindow::_key_repeat()
{
_key_repeat_timer->start(KEY_REPEAT_RATE_MS);
_keyboard_handler.processKeycode(_last_keycode, true, true);
} }
@ -186,55 +189,106 @@ void QNitpickerPlatformWindow::_handle_input(unsigned int)
_input_session.for_each_event([&] (Input::Event const &event) { _input_session.for_each_event([&] (Input::Event const &event) {
bool const is_key_event = event.type() == Input::Event::PRESS || QPoint const orig_mouse_position = _mouse_position;
event.type() == Input::Event::RELEASE; Qt::MouseButtons const orig_mouse_button_state = _mouse_button_state;
bool const is_mouse_button_event = event.handle_absolute_motion([&] (int x, int y) {
is_key_event && (event.code() == Input::BTN_LEFT || _mouse_position = QPoint(x, y); });
event.code() == Input::BTN_MIDDLE ||
event.code() == Input::BTN_RIGHT);
if (event.type() == Input::Event::MOTION || event.handle_press([&] (Input::Keycode key, Genode::Codepoint codepoint) {
event.type() == Input::Event::WHEEL ||
is_mouse_button_event) {
_process_mouse_event(event); switch (key) {
case Input::BTN_LEFT: _mouse_button_state |= Qt::LeftButton; break;
} else if (event.type() == Input::Event::TOUCH) { case Input::BTN_RIGHT: _mouse_button_state |= Qt::RightButton; break;
case Input::BTN_MIDDLE: _mouse_button_state |= Qt::MidButton; break;
touch_events.push_back(event); case Input::BTN_SIDE: _mouse_button_state |= Qt::XButton1; break;
case Input::BTN_EXTRA: _mouse_button_state |= Qt::XButton2; break;
} else if (event.type() == Input::Event::CHARACTER) { default: break;
Input::Event::Utf8 const utf8 = event.utf8();
if ((utf8.b0 >= 1) && (utf8.b0 <= 26)) {
/* Ctrl-A .. Ctrl-Z */
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress,
Qt::Key_A + (utf8.b0 - 1),
Qt::ControlModifier);
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease,
Qt::Key_A + (utf8.b0 - 1),
Qt::ControlModifier);
} else {
char const utf8_string[] = { (char)utf8.b0, (char)utf8.b1,
(char)utf8.b2, (char)utf8.b3,
'\0' };
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, 0, 0,
QString::fromUtf8(utf8_string));
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease, 0, 0,
QString::fromUtf8(utf8_string));
} }
} else if (is_key_event && (event.code() < 128)) { /* on mouse click, make this window the focused window */
if (_mouse_button_state != orig_mouse_button_state)
requestActivateWindow();
_process_key_event(event); QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress,
translate_keycode(key), 0,
QString() + QChar(codepoint.value));
});
/* handle repeat of special keys */
event.handle_repeat([&] (Genode::Codepoint codepoint) {
/* function-key unicodes */
enum {
CODEPOINT_UP = 0xf700, CODEPOINT_DOWN = 0xf701,
CODEPOINT_LEFT = 0xf702, CODEPOINT_RIGHT = 0xf703,
CODEPOINT_HOME = 0xf729, CODEPOINT_INSERT = 0xf727,
CODEPOINT_DELETE = 0xf728, CODEPOINT_END = 0xf72b,
CODEPOINT_PAGEUP = 0xf72c, CODEPOINT_PAGEDOWN = 0xf72d,
CODEPOINT_BACKSPACE = 8, CODEPOINT_LINEFEED = 10,
};
Qt::Key repeated_key = Qt::Key_unknown;
switch (codepoint.value) {
case CODEPOINT_UP: repeated_key = Qt::Key_Up; break;
case CODEPOINT_DOWN: repeated_key = Qt::Key_Down; break;
case CODEPOINT_LEFT: repeated_key = Qt::Key_Left; break;
case CODEPOINT_RIGHT: repeated_key = Qt::Key_Right; break;
case CODEPOINT_HOME: repeated_key = Qt::Key_Home; break;
case CODEPOINT_INSERT: repeated_key = Qt::Key_Insert; break;
case CODEPOINT_DELETE: repeated_key = Qt::Key_Delete; break;
case CODEPOINT_END: repeated_key = Qt::Key_End; break;
case CODEPOINT_PAGEUP: repeated_key = Qt::Key_PageUp; break;
case CODEPOINT_PAGEDOWN: repeated_key = Qt::Key_PageDown; break;
case CODEPOINT_BACKSPACE: repeated_key = Qt::Key_Backspace; break;
case CODEPOINT_LINEFEED: repeated_key = Qt::Key_Return; break;
default: return /* from lambda */;
};
/*
* A key repeat is triggered while a key is already pressed. We
* respond to it by simulating a tempoary release of the key.
*/
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease,
repeated_key, 0, QString());
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress,
repeated_key, 0, QString());
});
event.handle_release([&] (Input::Keycode key) {
switch (key) {
case Input::BTN_LEFT: _mouse_button_state &= ~Qt::LeftButton; break;
case Input::BTN_RIGHT: _mouse_button_state &= ~Qt::RightButton; break;
case Input::BTN_MIDDLE: _mouse_button_state &= ~Qt::MidButton; break;
case Input::BTN_SIDE: _mouse_button_state &= ~Qt::XButton1; break;
case Input::BTN_EXTRA: _mouse_button_state &= ~Qt::XButton2; break;
default: break;
}
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease,
translate_keycode(key),
0, QString());
});
event.handle_wheel([&] (int x, int y) {
QWindowSystemInterface::handleWheelEvent(window(),
_local_position(),
_local_position(),
y * 120,
Qt::Vertical); });
if (_mouse_button_state != orig_mouse_button_state
|| _mouse_position != orig_mouse_position) {
QWindowSystemInterface::handleMouseEvent(window(),
_local_position(),
_mouse_position,
_mouse_button_state);
} }
if (event.touch() || event.touch_release())
touch_events.push_back(event);
}); });
/* process all gathered touch events */ /* process all gathered touch events */
@ -338,12 +392,9 @@ QNitpickerPlatformWindow::QNitpickerPlatformWindow(Genode::Env &env, QWindow *wi
_view_handle(_create_view()), _view_handle(_create_view()),
_input_session(env.rm(), _nitpicker_session.input_session()), _input_session(env.rm(), _nitpicker_session.input_session()),
_ev_buf(env.rm(), _input_session.dataspace()), _ev_buf(env.rm(), _input_session.dataspace()),
_keyboard_handler("", _evdevkeyboard_fd, false, false, ""),
_resize_handle(!window->flags().testFlag(Qt::Popup)), _resize_handle(!window->flags().testFlag(Qt::Popup)),
_decoration(!window->flags().testFlag(Qt::Popup)), _decoration(!window->flags().testFlag(Qt::Popup)),
_egl_surface(EGL_NO_SURFACE), _egl_surface(EGL_NO_SURFACE),
_key_repeat_timer(this),
_last_keycode(0),
_input_signal_dispatcher(_signal_receiver, *this, _input_signal_dispatcher(_signal_receiver, *this,
&QNitpickerPlatformWindow::_input), &QNitpickerPlatformWindow::_input),
_mode_changed_signal_dispatcher(_signal_receiver, *this, _mode_changed_signal_dispatcher(_signal_receiver, *this,
@ -375,9 +426,6 @@ QNitpickerPlatformWindow::QNitpickerPlatformWindow(Genode::Env &env, QWindow *wi
connect(this, SIGNAL(_mode_changed(unsigned int)), connect(this, SIGNAL(_mode_changed(unsigned int)),
this, SLOT(_handle_mode_changed(unsigned int)), this, SLOT(_handle_mode_changed(unsigned int)),
Qt::QueuedConnection); Qt::QueuedConnection);
connect(_key_repeat_timer, SIGNAL(timeout()),
this, SLOT(_key_repeat()));
} }
QWindow *QNitpickerPlatformWindow::window() const QWindow *QNitpickerPlatformWindow::window() const

View File

@ -39,11 +39,6 @@ class QNitpickerPlatformWindow : public QObject, public QPlatformWindow
private: private:
enum {
KEY_REPEAT_DELAY_MS = 500, /* 500 ms delay before first repetition */
KEY_REPEAT_RATE_MS = 50 /* 50 ms delay between repetitions */
};
Genode::Env &_env; Genode::Env &_env;
Nitpicker::Connection _nitpicker_session; Nitpicker::Connection _nitpicker_session;
Framebuffer::Session_client _framebuffer_session; Framebuffer::Session_client _framebuffer_session;
@ -55,15 +50,18 @@ class QNitpickerPlatformWindow : public QObject, public QPlatformWindow
Nitpicker::Session::View_handle _view_handle; Nitpicker::Session::View_handle _view_handle;
Input::Session_client _input_session; Input::Session_client _input_session;
Genode::Attached_dataspace _ev_buf; Genode::Attached_dataspace _ev_buf;
QPoint _mouse_position;
Qt::MouseButtons _mouse_button_state; Qt::MouseButtons _mouse_button_state;
QFdContainer _evdevkeyboard_fd { -1 };
QEvdevKeyboardHandler _keyboard_handler;
QByteArray _title; QByteArray _title;
bool _resize_handle; bool _resize_handle;
bool _decoration; bool _decoration;
EGLSurface _egl_surface; EGLSurface _egl_surface;
QMember<QTimer> _key_repeat_timer;
int _last_keycode; QPoint _local_position() const
{
return QPoint(_mouse_position.x() - geometry().x(),
_mouse_position.y() - geometry().y());
}
Genode::Signal_dispatcher<QNitpickerPlatformWindow> _input_signal_dispatcher; Genode::Signal_dispatcher<QNitpickerPlatformWindow> _input_signal_dispatcher;
Genode::Signal_dispatcher<QNitpickerPlatformWindow> _mode_changed_signal_dispatcher; Genode::Signal_dispatcher<QNitpickerPlatformWindow> _mode_changed_signal_dispatcher;
@ -72,8 +70,6 @@ class QNitpickerPlatformWindow : public QObject, public QPlatformWindow
QTouchDevice *_touch_device; QTouchDevice *_touch_device;
QTouchDevice * _init_touch_device(); QTouchDevice * _init_touch_device();
void _process_mouse_event(Input::Event const &ev);
void _process_key_event(Input::Event const &ev);
void _process_touch_events(QList<Input::Event> const &events); void _process_touch_events(QList<Input::Event> const &events);
Nitpicker::Session::View_handle _create_view(); Nitpicker::Session::View_handle _create_view();
@ -83,7 +79,6 @@ class QNitpickerPlatformWindow : public QObject, public QPlatformWindow
void _handle_input(unsigned int); void _handle_input(unsigned int);
void _handle_mode_changed(unsigned int); void _handle_mode_changed(unsigned int);
void _key_repeat();
Q_SIGNALS: Q_SIGNALS:

View File

@ -77,13 +77,13 @@ extern "C" {
static int buttonmap[KEYNUM_MAX]; static int buttonmap[KEYNUM_MAX];
inline SDL_keysym *Genode_Fb_TranslateKey(int keycode, SDL_keysym *k) inline SDL_keysym Genode_Fb_TranslateKey(Input::Keycode keycode,
Genode::Codepoint codepoint)
{ {
k->scancode = keycode; return SDL_keysym { .scancode = (uint8_t)keycode,
k->sym = keymap[keycode]; .sym = keymap[keycode],
k->mod = SDL_GetModState(); .mod = SDL_GetModState(),
k->unicode = keymap[keycode]; .unicode = (uint16_t)codepoint.value };
return k;
} }
@ -101,43 +101,39 @@ extern "C" {
return; return;
input->for_each_event([&] (Input::Event const &curr) { input->for_each_event([&] (Input::Event const &curr) {
SDL_keysym ksym;
switch(curr.type()) curr.handle_absolute_motion([&] (int x, int y) {
{ SDL_PrivateMouseMotion(0, 0, x, y); });
case Input::Event::MOTION:
if (curr.absolute_motion()) curr.handle_relative_motion([&] (int x, int y) {
SDL_PrivateMouseMotion(0, 0, curr.ax(), curr.ay()); SDL_PrivateMouseMotion(0, 1, x, y); });
else
SDL_PrivateMouseMotion(0, 1, curr.rx(), curr.ry()); /* return true if keycode refers to a button */
break; auto mouse_button = [] (Input::Keycode key) {
case Input::Event::PRESS: return key >= Input::BTN_MISC && key <= Input::BTN_GEAR_UP; };
if(curr.code() >= Input::BTN_MISC &&
curr.code() <= Input::BTN_GEAR_UP) curr.handle_press([&] (Input::Keycode key, Genode::Codepoint codepoint) {
SDL_PrivateMouseButton(SDL_PRESSED,
buttonmap[curr.code()], if (mouse_button(key))
0, 0); SDL_PrivateMouseButton(SDL_PRESSED, buttonmap[key], 0, 0);
else
SDL_PrivateKeyboard(SDL_PRESSED, else {
Genode_Fb_TranslateKey(curr.code(), SDL_keysym ksym = Genode_Fb_TranslateKey(key, codepoint);
&ksym)); SDL_PrivateKeyboard(SDL_PRESSED, &ksym);
break; }
case Input::Event::RELEASE: });
if(curr.code() >= Input::BTN_MISC &&
curr.code() <= Input::BTN_GEAR_UP) curr.handle_release([&] (Input::Keycode key) {
SDL_PrivateMouseButton(SDL_RELEASED,
buttonmap[curr.code()], if (mouse_button(key))
0, 0); SDL_PrivateMouseButton(SDL_RELEASED, buttonmap[key], 0, 0);
else
SDL_PrivateKeyboard(SDL_RELEASED, else {
Genode_Fb_TranslateKey(curr.code(), Genode::Codepoint const invalid { Genode::Codepoint::INVALID };
&ksym)); SDL_keysym ksym = Genode_Fb_TranslateKey(key, invalid);
break; SDL_PrivateKeyboard(SDL_RELEASED, &ksym);
case Input::Event::WHEEL: }
Genode::warning("mouse wheel, not implemented yet"); });
break;
default:
break;
}
}); });
} }

View File

@ -298,12 +298,11 @@ struct Transform::Main {
if (key->type() == Keys::Type::PRESS_RELEASE || if (key->type() == Keys::Type::PRESS_RELEASE ||
key->type() == Keys::Type::PRESS) key->type() == Keys::Type::PRESS)
_session.submit(Input::Event(Input::Event::PRESS, key->key_code(), _session.submit(Input::Press{key->key_code()});
0, 0, 0, 0));
if (key->type() == Keys::Type::PRESS_RELEASE || if (key->type() == Keys::Type::PRESS_RELEASE ||
key->type() == Keys::Type::RELEASE) key->type() == Keys::Type::RELEASE)
_session.submit(Input::Event(Input::Event::RELEASE, _session.submit(Input::Release{key->key_code()});
key->key_code(), 0, 0, 0, 0));
} }
void check_acpi_fixed() void check_acpi_fixed()

View File

@ -14,127 +14,198 @@
#ifndef _INCLUDE__INPUT__EVENT_H_ #ifndef _INCLUDE__INPUT__EVENT_H_
#define _INCLUDE__INPUT__EVENT_H_ #define _INCLUDE__INPUT__EVENT_H_
#include <base/output.h>
#include <input/keycodes.h> #include <input/keycodes.h>
#include <util/geometry.h>
#include <util/utf8.h>
namespace Input { class Event; } namespace Input {
typedef Genode::Codepoint Codepoint;
struct Touch_id { int value; };
/*
* Event attributes
*/
struct Press { Keycode key; };
struct Press_char { Keycode key; Codepoint codepoint; };
struct Release { Keycode key; };
struct Wheel { int x, y; };
struct Focus_enter { };
struct Focus_leave { };
struct Hover_leave { };
struct Absolute_motion { int x, y; };
struct Relative_motion { int x, y; };
struct Touch { Touch_id id; float x, y; };
struct Touch_release { Touch_id id; };
class Event;
}
class Input::Event class Input::Event
{ {
public:
enum Type { INVALID, MOTION, PRESS, RELEASE, WHEEL, FOCUS, LEAVE, TOUCH,
CHARACTER };
private: private:
enum Type { INVALID, PRESS, RELEASE, REL_MOTION, ABS_MOTION, WHEEL,
FOCUS_ENTER, FOCUS_LEAVE, HOVER_LEAVE, TOUCH, TOUCH_RELEASE };
Type _type = INVALID; Type _type = INVALID;
/* struct Attr
* For PRESS and RELEASE events, '_code' contains the key code. {
* For FOCUS events, '_code' is set to 1 (focus) or 0 (unfocus). union {
*/ Press_char press;
int _code = 0; Release release;
Wheel wheel;
Absolute_motion abs_motion;
Relative_motion rel_motion;
Touch touch;
Touch_release touch_release;
};
} _attr { };
/* static bool _valid(Keycode key) { return key > KEY_RESERVED && key < KEY_MAX; }
* Absolute pointer position coordinates
*/
int _ax = 0, _ay = 0;
/* /**
* Relative pointer motion vector * Return point representation of attribute 'a'
*/ */
int _rx = 0, _ry = 0; template <typename R, typename T>
static Genode::Point<R> _xy(T const &a) { return Genode::Point<R>(a.x, a.y); }
public: public:
/**
* UTF8-encoded symbolic character
*/
struct Utf8
{
typedef unsigned char byte;
byte b0, b1, b2, b3;
Utf8(byte b0, byte b1 = 0, byte b2 = 0, byte b3 = 0)
: b0(b0), b1(b1), b2(b2), b3(b3) { }
};
/** /**
* Default constructor creates an invalid event * Default constructor creates an invalid event
*
* This constructor can be used for creating an array of events.
*/ */
Event() { } Event() { }
/**
* Constructor creates a low-level event
*/
Event(Type type, int code, int ax, int ay, int rx, int ry):
_type(type), _code(code),
_ax(ax), _ay(ay), _rx(rx), _ry(ry) { }
/**
* Constructor creates a symbolic character event
*/
Event(Utf8 const &utf8)
:
_type(CHARACTER),
_code(((unsigned)utf8.b3 << 24) | ((unsigned)utf8.b2 << 16) |
((unsigned)utf8.b1 << 8) | ((unsigned)utf8.b0 << 0))
{ }
/**
* Return event type
*/
Type type() const
{
/* prevent obnoxious events from being processed by clients */
if ((_type == PRESS || _type == RELEASE)
&& (_code <= KEY_RESERVED || _code >= KEY_UNKNOWN))
return INVALID;
return _type;
}
/**
* Accessors
*/
int code() const { return _code; }
int ax() const { return _ax; }
int ay() const { return _ay; }
int rx() const { return _rx; }
int ry() const { return _ry; }
/**
* Return symbolic character encoded as UTF8 byte sequence
*
* This method must only be called if type is CHARACTER.
*/
Utf8 utf8() const { return Utf8(_code, _code >> 8, _code >> 16, _code >> 24); }
/**
* Return key code for press/release events
*/
Keycode keycode() const
{
return _type == PRESS || _type == RELEASE ? (Keycode)_code : KEY_UNKNOWN;
}
bool absolute_motion() const { return _type == MOTION && !_rx && !_ry; }
bool relative_motion() const { return _type == MOTION && (_rx || _ry); }
bool touch_release() const { return _type == TOUCH && (_rx == -1) && (_ry == -1); }
/* /*
* \deprecated use methods without the 'is_' prefix instead * Constructors for creating input events of various types
*
* These constructors can be used implicitly for the given attribute
* types for assignments or for passing an event as return value.
*/ */
bool is_absolute_motion() const { return absolute_motion(); } Event(Press_char arg) : _type(PRESS) { _attr.press = arg; }
bool is_relative_motion() const { return relative_motion(); } Event(Press arg) : Event(Press_char{arg.key, Codepoint{INVALID}}) { }
bool is_touch_release() const { return touch_release(); } Event(Release arg) : _type(RELEASE) { _attr.release = arg; }
Event(Relative_motion arg) : _type(REL_MOTION) { _attr.rel_motion = arg; }
Event(Absolute_motion arg) : _type(ABS_MOTION) { _attr.abs_motion = arg; }
Event(Wheel arg) : _type(WHEEL) { _attr.wheel = arg; }
Event(Focus_enter) : _type(FOCUS_ENTER) { }
Event(Focus_leave) : _type(FOCUS_LEAVE) { }
Event(Hover_leave) : _type(HOVER_LEAVE) { }
Event(Touch arg) : _type(TOUCH) { _attr.touch = arg; }
Event(Touch_release arg) : _type(TOUCH_RELEASE) { _attr.touch_release = arg; }
static Event create_touch_event(int ax, int ay, int id, bool last = false)
/************************************
** Methods for handling the event **
************************************/
bool valid() const { return _type != INVALID; }
bool press() const { return _type == PRESS; }
bool release() const { return _type == RELEASE; }
bool absolute_motion() const { return _type == ABS_MOTION; }
bool relative_motion() const { return _type == REL_MOTION; }
bool wheel() const { return _type == WHEEL; }
bool focus_enter() const { return _type == FOCUS_ENTER; }
bool focus_leave() const { return _type == FOCUS_LEAVE; }
bool hover_leave() const { return _type == HOVER_LEAVE; }
bool touch() const { return _type == TOUCH; }
bool touch_release() const { return _type == TOUCH_RELEASE; }
bool key_press(Keycode key) const
{ {
return Event(Type::TOUCH, id, ax, ay, last ? -1 : 0, last ? -1 : 0); return press() && _attr.press.key == key;
} }
bool key_release(Keycode key) const
{
return release() && _attr.release.key == key;
}
template <typename FN>
void handle_press(FN const &fn) const
{
if (press() && _valid(_attr.press.key))
fn(_attr.press.key, _attr.press.codepoint);
}
template <typename FN>
void handle_repeat(FN const &fn) const
{
if (key_press(KEY_UNKNOWN) && _attr.press.codepoint.value)
fn(_attr.press.codepoint);
}
template <typename FN>
void handle_release(FN const &fn) const
{
if (release() && _valid(_attr.release.key))
fn(_attr.release.key);
}
template <typename FN>
void handle_relative_motion(FN const &fn) const
{
if (relative_motion())
fn(_attr.rel_motion.x, _attr.rel_motion.y);
}
template <typename FN>
void handle_absolute_motion(FN const &fn) const
{
if (absolute_motion())
fn(_attr.abs_motion.x, _attr.abs_motion.y);
}
template <typename FN>
void handle_wheel(FN const &fn) const
{
if (wheel())
fn(_attr.wheel.x, _attr.wheel.y);
}
template <typename FN>
void handle_touch(FN const &fn) const
{
if (touch())
fn(_attr.touch.id, _attr.touch.x, _attr.touch.y);
}
template <typename FN>
void handle_touch_release(FN const &fn) const
{
if (touch_release())
fn(_attr.touch_release.id);
}
inline void print(Genode::Output &out) const;
}; };
void Input::Event::print(Genode::Output &out) const
{
using Genode::print;
switch (_type) {
case INVALID: print(out, "INVALID"); break;
case PRESS: print(out, "PRESS ", key_name(_attr.press.key),
" ", _attr.press.codepoint.value); break;
case RELEASE: print(out, "RELEASE ", key_name(_attr.release.key)); break;
case REL_MOTION: print(out, "REL_MOTION ", _xy<int>(_attr.rel_motion)); break;
case ABS_MOTION: print(out, "ABS_MOTION ", _xy<int>(_attr.abs_motion)); break;
case WHEEL: print(out, "WHEEL ", _xy<int>(_attr.wheel)); break;
case FOCUS_ENTER: print(out, "FOCUS_ENTER"); break;
case FOCUS_LEAVE: print(out, "FOCUS_LEAVE"); break;
case HOVER_LEAVE: print(out, "HOVER_LEAVE"); break;
case TOUCH_RELEASE: print(out, "TOUCH_RELEASE ", _attr.touch.id.value); break;
case TOUCH: print(out, "TOUCH ", _attr.touch.id.value, " ",
_xy<float>(_attr.touch)); break;
};
}
#endif /* _INCLUDE__INPUT__EVENT_H_ */ #endif /* _INCLUDE__INPUT__EVENT_H_ */

View File

@ -184,17 +184,14 @@ append config {
<press code="KEY_A"/> <release code="KEY_A"/> <press code="KEY_A"/> <release code="KEY_A"/>
<release code="KEY_RIGHTSHIFT"/> <release code="KEY_RIGHTSHIFT"/>
</usb> </usb>
<expect_press code="KEY_A"/> <expect_press code="KEY_A" char="a"/>
<expect_char char="a"/>
<expect_release code="KEY_A"/> <expect_release code="KEY_A"/>
<expect_press code="KEY_LEFTSHIFT"/> <expect_press code="KEY_LEFTSHIFT"/>
<expect_press code="KEY_A"/> <expect_press code="KEY_A" char="A"/>
<expect_char char="A"/>
<expect_release code="KEY_A"/> <expect_release code="KEY_A"/>
<expect_release code="KEY_LEFTSHIFT"/> <expect_release code="KEY_LEFTSHIFT"/>
<expect_press code="KEY_RIGHTSHIFT"/> <expect_press code="KEY_RIGHTSHIFT"/>
<expect_press code="KEY_A"/> <expect_press code="KEY_A" char="A"/>
<expect_char char="A"/>
<expect_release code="KEY_A"/> <expect_release code="KEY_A"/>
<expect_release code="KEY_RIGHTSHIFT"/>} <expect_release code="KEY_RIGHTSHIFT"/>}
@ -219,13 +216,12 @@ append_if [test_char_repeat] config {
<!-- periodic characters should stop now --> <!-- periodic characters should stop now -->
<sleep ms="1000"/> <sleep ms="1000"/>
<usb> <press code="KEY_B"/> <release code="KEY_B"/> </usb> <usb> <press code="KEY_B"/> <release code="KEY_B"/> </usb>
<expect_press code="KEY_A"/> <expect_press code="KEY_A" char="a"/> <!-- original press (0 ms) -->
<expect_char char="a"/> <!-- original press (0 ms) --> <expect_press code="KEY_UNKNOWN" char="a"/> <!-- character after delay (600 ms) -->
<expect_char char="a"/> <!-- character after delay (600 ms) --> <expect_press code="KEY_UNKNOWN" char="a"/> <!-- periodic character (800 ms) -->
<expect_char char="a"/> <!-- periodic character (800 ms) --> <expect_press code="KEY_UNKNOWN" char="a"/> <!-- periodic character (1000 ms) -->
<expect_char char="a"/> <!-- periodic character (1000 ms) --> <expect_press code="KEY_UNKNOWN" char="a"/> <!-- periodic character (1200 ms) -->
<expect_char char="a"/> <!-- periodic character (1200 ms) --> <expect_press code="KEY_UNKNOWN" char="a"/> <!-- periodic character (1400 ms) -->
<expect_char char="a"/> <!-- periodic character (1400 ms) -->
<expect_release code="KEY_A"/> <expect_release code="KEY_A"/>
<expect_press code="KEY_B"/> <expect_press code="KEY_B"/>
<expect_release code="KEY_B"/>} <expect_release code="KEY_B"/>}
@ -257,15 +253,15 @@ append config {
<capslock enabled="no"/> <capslock enabled="no"/>
<sleep ms="250"/> <sleep ms="250"/>
<usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb> <usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb>
<expect_press code="KEY_A"/> <expect_char char="a"/> <expect_release code="KEY_A"/> <expect_press code="KEY_A" char="a"/> <expect_release code="KEY_A"/>
<capslock enabled="yes"/> <capslock enabled="yes"/>
<sleep ms="250"/> <sleep ms="250"/>
<usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb> <usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb>
<expect_press code="KEY_A"/> <expect_char char="A"/> <expect_release code="KEY_A"/> <expect_press code="KEY_A" char="A"/> <expect_release code="KEY_A"/>
<capslock enabled="no"/> <capslock enabled="no"/>
<sleep ms="250"/> <sleep ms="250"/>
<usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb> <usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb>
<expect_press code="KEY_A"/> <expect_char char="a"/> <expect_release code="KEY_A"/> <expect_press code="KEY_A" char="a"/> <expect_release code="KEY_A"/>
<message string="button-scroll feature"/> <message string="button-scroll feature"/>
@ -418,7 +414,7 @@ append config {
</filter_config> </filter_config>
<sleep ms="100"/> <sleep ms="100"/>
<usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb> <usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb>
<expect_press code="KEY_A"/> <expect_char char="a"/> <expect_release code="KEY_A"/> <expect_press code="KEY_A" char="a"/> <expect_release code="KEY_A"/>
<message string="update included chargen ROM"/> <message string="update included chargen ROM"/>
@ -428,7 +424,7 @@ append config {
</chargen_include> </chargen_include>
<sleep ms="100"/> <sleep ms="100"/>
<usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb> <usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb>
<expect_press code="KEY_A"/> <expect_char char="b"/> <expect_release code="KEY_A"/> <expect_press code="KEY_A" char="b"/> <expect_release code="KEY_A"/>
</config> </config>
<route> <route>

View File

@ -292,19 +292,15 @@ void Global_keys_handler::Main::_apply_input_events(unsigned num_ev,
Input::Event const &ev = events[i]; Input::Event const &ev = events[i];
if (ev.type() != Input::Event::PRESS if (!ev.press() && !ev.release())
&& ev.type() != Input::Event::RELEASE)
continue; continue;
if (ev.type() == Input::Event::PRESS) _key_cnt++; if (ev.press()) _key_cnt++;
if (ev.type() == Input::Event::RELEASE) _key_cnt--; if (ev.release()) _key_cnt--;
/* ignore key combinations */ /* ignore key combinations */
if (_key_cnt > 1) continue; if (_key_cnt > 1) continue;
typedef String<32> Key_name;
Key_name const ev_key_name(Input::key_name(ev.keycode()));
typedef Xml_node Xml_node; typedef Xml_node Xml_node;
auto lambda = [&] (Xml_node node) { auto lambda = [&] (Xml_node node) {
@ -312,17 +308,24 @@ void Global_keys_handler::Main::_apply_input_events(unsigned num_ev,
if (!node.has_type("press") && !node.has_type("release")) if (!node.has_type("press") && !node.has_type("release"))
return; return;
if (node.has_type("press") && ev.type() != Input::Event::PRESS)
return;
if (node.has_type("release") && ev.type() != Input::Event::RELEASE)
return;
/* /*
* XML node applies for current event type, check if the key * XML node applies for current event type, check if the key
* matches. * matches.
*/ */
if (node.attribute_value("name", Key_name()) != ev_key_name) typedef String<32> Key_name;
Key_name const expected = node.attribute_value("name", Key_name());
bool key_matches = false;
if (node.has_type("press"))
ev.handle_press([&] (Input::Keycode key, Codepoint) {
key_matches = (expected == Input::key_name(key)); });
if (node.has_type("release"))
ev.handle_release([&] (Input::Keycode key) {
key_matches = (expected == Input::key_name(key)); });
if (!key_matches)
return; return;
/* /*

View File

@ -26,7 +26,7 @@
/** /**
* Convert SDL keycode to Genode keycode * Convert SDL keycode to Genode keycode
*/ */
static long convert_keycode(int sdl_keycode) static Input::Keycode convert_keycode(int sdl_keycode)
{ {
using namespace Input; using namespace Input;
@ -135,7 +135,7 @@ static long convert_keycode(int sdl_keycode)
case SDLK_RMETA: return KEY_RIGHTMETA; case SDLK_RMETA: return KEY_RIGHTMETA;
case SDLK_LMETA: return KEY_LEFTMETA; case SDLK_LMETA: return KEY_LEFTMETA;
default: return 0; default: return KEY_UNKNOWN;
} }
}; };
@ -158,11 +158,11 @@ static Input::Event wait_for_sdl_event()
if (ox == mx && oy == my) if (ox == mx && oy == my)
return Event(); return Event();
return Event(Event::MOTION, 0, mx, my, mx - ox, my - oy); return Absolute_motion{mx, my};
} }
/* determine keycode */ /* determine key code */
long keycode = 0; Keycode keycode = KEY_UNKNOWN;
switch (event.type) { switch (event.type) {
case SDL_KEYUP: case SDL_KEYUP:
case SDL_KEYDOWN: case SDL_KEYDOWN:
@ -177,12 +177,11 @@ static Input::Event wait_for_sdl_event()
case SDL_BUTTON_LEFT: keycode = BTN_LEFT; break; case SDL_BUTTON_LEFT: keycode = BTN_LEFT; break;
case SDL_BUTTON_MIDDLE: keycode = BTN_MIDDLE; break; case SDL_BUTTON_MIDDLE: keycode = BTN_MIDDLE; break;
case SDL_BUTTON_RIGHT: keycode = BTN_RIGHT; break; case SDL_BUTTON_RIGHT: keycode = BTN_RIGHT; break;
default: keycode = 0; default: break;
} }
} }
/* determine event type */ /* determine event type */
Event::Type type = Event::INVALID;
switch (event.type) { switch (event.type) {
case SDL_KEYUP: case SDL_KEYUP:
@ -192,32 +191,27 @@ static Input::Event wait_for_sdl_event()
/* ignore */ /* ignore */
return Event(); return Event();
type = Event::RELEASE; return Release{keycode};
break;
case SDL_KEYDOWN: case SDL_KEYDOWN:
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
if (event.button.button == SDL_BUTTON_WHEELUP) {
type = Event::WHEEL; if (event.button.button == SDL_BUTTON_WHEELUP)
return Event(type, 0, 0, 0, 0, 1); return Wheel{0, 1};
} else if (event.button.button == SDL_BUTTON_WHEELDOWN) {
type = Event::WHEEL; else if (event.button.button == SDL_BUTTON_WHEELDOWN)
return Event(type, 0, 0, 0, 0, -1); return Wheel{0, -1};
}
type = Event::PRESS; return Press{keycode};
break;
default: default:
return Event(); break;
} }
return Event();
return Event(type, keycode, 0, 0, 0, 0);
} }
namespace Input { namespace Input { struct Backend; }
struct Backend;
}
struct Input::Backend : Genode::Thread struct Input::Backend : Genode::Thread
{ {
@ -237,9 +231,7 @@ struct Input::Backend : Genode::Thread
Input::Event e; Input::Event e;
/* prevent flooding of client with invalid events */ /* prevent flooding of client with invalid events */
do { do { e = wait_for_sdl_event(); } while (!e.valid());
e = wait_for_sdl_event();
} while (e.type() == Input::Event::INVALID);
handler.event(e); handler.event(e);
} }

View File

@ -81,14 +81,14 @@ class Input::Touchscreen {
y = 76800 / (3276700 / y); y = 76800 / (3276700 / y);
/* motion event */ /* motion event */
ev_queue.add(Input::Event(Input::Event::MOTION, 0, x, y, 0, 0)); ev_queue.add(Input::Absolute_motion{x, y});
/* button event */ /* button event */
if ((down && (_state == RELEASED)) || if ((down && (_state == RELEASED)) || (!down && (_state == PRESSED))) {
(!down && (_state == PRESSED))) {
ev_queue.add(Input::Event(down ? Input::Event::PRESS if (down) ev_queue.add(Input::Press {Input::BTN_LEFT});
: Input::Event::RELEASE, else ev_queue.add(Input::Release{Input::BTN_LEFT});
Input::BTN_LEFT, 0, 0, 0, 0));
_state = down ? PRESSED : RELEASED; _state = down ? PRESSED : RELEASED;
} }
} }

View File

@ -95,9 +95,11 @@ class Input::Buttons {
for (unsigned i = 0; i < (sizeof(buttons)/sizeof(int)); i++) { for (unsigned i = 0; i < (sizeof(buttons)/sizeof(int)); i++) {
if ((_state & buttons[i]) == (buf & buttons[i])) if ((_state & buttons[i]) == (buf & buttons[i]))
continue; continue;
Input::Event::Type event = (buf & buttons[i]) ?
Input::Event::PRESS : Input::Event::RELEASE; Input::Keycode const key = Input::Keycode(codes[i]);
ev_queue.add(Input::Event(event, codes[i], 0, 0, 0, 0));
if (buf & buttons[i]) ev_queue.add(Input::Press {key});
else ev_queue.add(Input::Release{key});
}; };
_state = buf; _state = buf;
} }

View File

@ -467,8 +467,8 @@ class Ps2::Keyboard : public Input_driver
if (!_state_machine->ready()) if (!_state_machine->ready())
return; return;
bool press = _state_machine->press(); bool press = _state_machine->press();
unsigned key_code = _state_machine->key_code(); Input::Keycode key_code = Input::Keycode(_state_machine->key_code());
/* /*
* The old key state should not equal the state after the event. * The old key state should not equal the state after the event.
@ -484,7 +484,7 @@ class Ps2::Keyboard : public Input_driver
if (_verbose.keyboard) if (_verbose.keyboard)
Genode::log("post ", press ? "PRESS" : "RELEASE", ", " Genode::log("post ", press ? "PRESS" : "RELEASE", ", "
"key_code = ", key_code); "key_code = ", Input::key_name(key_code));
if (_ev_queue.avail_capacity() == 0) { if (_ev_queue.avail_capacity() == 0) {
Genode::warning("event queue overflow - dropping events"); Genode::warning("event queue overflow - dropping events");
@ -492,9 +492,10 @@ class Ps2::Keyboard : public Input_driver
} }
/* post event to event queue */ /* post event to event queue */
_ev_queue.add(Input::Event(press ? Input::Event::PRESS if (press)
: Input::Event::RELEASE, _ev_queue.add(Input::Press{key_code});
key_code, 0, 0, 0, 0)); else
_ev_queue.add(Input::Release{key_code});
/* start with new packet */ /* start with new packet */
_state_machine->reset(); _state_machine->reset();

View File

@ -111,9 +111,11 @@ class Ps2::Mouse : public Input_driver
_check_for_event_queue_overflow(); _check_for_event_queue_overflow();
_ev_queue.add(Input::Event(new_state ? Input::Event::PRESS if (new_state)
: Input::Event::RELEASE, _ev_queue.add(Input::Press{Input::Keycode(key_code)});
key_code, 0, 0, 0, 0)); else
_ev_queue.add(Input::Release{Input::Keycode(key_code)});
*old_state = new_state; *old_state = new_state;
} }
@ -242,8 +244,7 @@ class Ps2::Mouse : public Input_driver
_check_for_event_queue_overflow(); _check_for_event_queue_overflow();
_ev_queue.add(Input::Event(Input::Event::MOTION, _ev_queue.add(Input::Relative_motion{rel_x, rel_y});
0, 0, 0, rel_x, rel_y));
} }
/* generate wheel event */ /* generate wheel event */
@ -264,8 +265,7 @@ class Ps2::Mouse : public Input_driver
_check_for_event_queue_overflow(); _check_for_event_queue_overflow();
_ev_queue.add(Input::Event(Input::Event::WHEEL, _ev_queue.add(Input::Wheel{0, rel_z});
0, 0, 0, 0, rel_z));
} }
/* detect changes of mouse-button state and post corresponding events */ /* detect changes of mouse-button state and post corresponding events */

View File

@ -74,11 +74,11 @@ class Input_filter::Accelerate_source : public Source, Source::Sink
*/ */
long const _max; long const _max;
long _apply_acceleration(long v) const int _apply_acceleration(int v) const
{ {
long const sign = (v < 0) ? -1 : 1, int const sign = (v < 0) ? -1 : 1,
index = max(0, min(255, (sign*v*_sensitivity_percent)/100)), index = max(0, min(255, (sign*v*_sensitivity_percent)/100)),
accel = (_lut.values[index]*_max)/256; accel = (_lut.values[index]*_max)/256;
return v + sign*accel; return v + sign*accel;
} }
@ -88,15 +88,14 @@ class Input_filter::Accelerate_source : public Source, Source::Sink
*/ */
void submit_event(Input::Event const &event) override void submit_event(Input::Event const &event) override
{ {
/* forward unrelated events */ using namespace Input;
if (!event.relative_motion()) {
_destination.submit_event(event);
return;
}
_destination.submit_event(Input::Event(Input::Event::MOTION, 0, 0, 0, Event ev = event;
_apply_acceleration(event.rx()),
_apply_acceleration(event.ry()))); ev.handle_relative_motion([&] (int x, int y) {
ev = Relative_motion{_apply_acceleration(x),
_apply_acceleration(y)}; });
_destination.submit_event(ev);
} }
public: public:

View File

@ -56,18 +56,6 @@ class Input_filter::Button_scroll_source : public Source, Source::Sink
*/ */
int _accumulated_motion = 0; int _accumulated_motion = 0;
bool _magic_button_press_event(Input::Event const &event) const
{
return (event.type() == Input::Event::PRESS)
&& (event.keycode() == _button);
}
bool _magic_button_release_event(Input::Event const &event) const
{
return (event.type() == Input::Event::RELEASE)
&& (event.keycode() == _button);
}
Wheel(Xml_node config) Wheel(Xml_node config)
: :
_button(key_code_by_name(_button_attribute(config).string())), _button(key_code_by_name(_button_attribute(config).string())),
@ -78,7 +66,7 @@ class Input_filter::Button_scroll_source : public Source, Source::Sink
{ {
switch (_state) { switch (_state) {
case IDLE: case IDLE:
if (_magic_button_press_event(event)) { if (event.key_press(_button)) {
_state = BUTTON_PRESSED; _state = BUTTON_PRESSED;
_accumulated_motion = 0; _accumulated_motion = 0;
} }
@ -103,7 +91,7 @@ class Input_filter::Button_scroll_source : public Source, Source::Sink
*/ */
bool handle_deactivation(Input::Event const &event) bool handle_deactivation(Input::Event const &event)
{ {
if (_magic_button_release_event(event)) { if (event.key_release(_button)) {
bool const emit_press_release = (_state == BUTTON_PRESSED); bool const emit_press_release = (_state == BUTTON_PRESSED);
_state = IDLE; _state = IDLE;
_accumulated_motion = 0; _accumulated_motion = 0;
@ -144,8 +132,7 @@ class Input_filter::Button_scroll_source : public Source, Source::Sink
bool suppressed(Input::Event const event) bool suppressed(Input::Event const event)
{ {
return (_state == ACTIVE && event.relative_motion()) return (_state == ACTIVE && event.relative_motion())
|| _magic_button_press_event(event) || event.key_press(_button);
|| _magic_button_release_event(event);
} }
}; };
@ -167,18 +154,17 @@ class Input_filter::Button_scroll_source : public Source, Source::Sink
_vertical_wheel .handle_activation(event); _vertical_wheel .handle_activation(event);
_horizontal_wheel.handle_activation(event); _horizontal_wheel.handle_activation(event);
if (event.relative_motion()) { event.handle_relative_motion([&] (int x, int y) {
_vertical_wheel .apply_relative_motion(event.ry()); _vertical_wheel .apply_relative_motion(y);
_horizontal_wheel.apply_relative_motion(event.rx()); _horizontal_wheel.apply_relative_motion(x);
} });
/* emit artificial wheel event */ /* emit artificial wheel event */
int const wheel_x = _horizontal_wheel.pending_motion(), int const wheel_x = _horizontal_wheel.pending_motion(),
wheel_y = _vertical_wheel .pending_motion(); wheel_y = _vertical_wheel .pending_motion();
if (wheel_x || wheel_y) if (wheel_x || wheel_y)
_destination.submit_event(Event(Event::WHEEL, 0, 0, 0, _destination.submit_event(Input::Wheel{wheel_x, wheel_y});
wheel_x, wheel_y));
/* /*
* Submit both press event and release event of magic button at * Submit both press event and release event of magic button at
@ -188,19 +174,18 @@ class Input_filter::Button_scroll_source : public Source, Source::Sink
* both conditions regardless of the result of the first call of * both conditions regardless of the result of the first call of
* 'handle_activation'. * 'handle_activation'.
*/ */
if (_vertical_wheel .handle_deactivation(event) event.handle_release([&] (Input::Keycode key) {
| _horizontal_wheel.handle_deactivation(event)) { if (_vertical_wheel .handle_deactivation(event)
| _horizontal_wheel.handle_deactivation(event)) {
_destination.submit_event(Event(Event::PRESS, event.code(), 0, 0, 0, 0)); _destination.submit_event(Input::Press{key});
_destination.submit_event(event); }
return; });
}
/* hide consumed relative motion and magic-button press events */ /* hide consumed relative motion and magic-button press events */
if (_vertical_wheel .suppressed(event)) return; if (_vertical_wheel .suppressed(event)) return;
if (_horizontal_wheel.suppressed(event)) return; if (_horizontal_wheel.suppressed(event)) return;
/* forward unrelated events */
_destination.submit_event(event); _destination.submit_event(event);
} }

View File

@ -29,6 +29,8 @@ class Input_filter::Chargen_source : public Source, Source::Sink
{ {
private: private:
typedef Input::Event Event;
Allocator &_alloc; Allocator &_alloc;
Timer_accessor &_timer_accessor; Timer_accessor &_timer_accessor;
Include_accessor &_include_accessor; Include_accessor &_include_accessor;
@ -179,11 +181,11 @@ class Input_filter::Chargen_source : public Source, Source::Sink
Conditions const _conditions; Conditions const _conditions;
Input::Event::Utf8 const _character; Codepoint const _character;
Rule(Registry<Rule> &registry, Rule(Registry<Rule> &registry,
Conditions conditions, Conditions conditions,
Input::Event::Utf8 character) Codepoint character)
: :
_reg_elem(registry, *this), _reg_elem(registry, *this),
_conditions(conditions), _conditions(conditions),
@ -205,19 +207,19 @@ class Input_filter::Chargen_source : public Source, Source::Sink
return 1 + _conditions.num_modifier_constraints(); return 1 + _conditions.num_modifier_constraints();
} }
Input::Event::Utf8 character() const { return _character; } Codepoint character() const { return _character; }
}; };
Registry<Rule> rules { }; Registry<Rule> rules { };
/** /**
* Call functor 'fn' with the 'Input::Event::Utf8' character * Call functor 'fn' with the codepoint of the character defined
* defined for the best matching rule * for the best matching rule
*/ */
template <typename FN> template <typename FN>
void apply_best_matching_rule(Modifier_map const &mod_map, FN const &fn) const void apply_best_matching_rule(Modifier_map const &mod_map, FN const &fn) const
{ {
Input::Event::Utf8 best_match { 0 }; Codepoint best_match { Codepoint::INVALID };
unsigned max_score = 0; unsigned max_score = 0;
@ -291,10 +293,13 @@ class Input_filter::Chargen_source : public Source, Source::Sink
* *
* \throw Missing_character_definition * \throw Missing_character_definition
*/ */
static Input::Event::Utf8 _utf8_from_xml_node(Xml_node node) static Codepoint _codepoint_from_xml_node(Xml_node node)
{ {
if (node.has_attribute("ascii")) if (node.has_attribute("ascii"))
return Input::Event::Utf8(node.attribute_value("ascii", 0UL)); return Codepoint { node.attribute_value<uint32_t>("ascii", 0) };
if (node.has_attribute("code"))
return Codepoint { node.attribute_value<uint32_t>("code", 0) };
if (node.has_attribute("char")) { if (node.has_attribute("char")) {
@ -304,7 +309,7 @@ class Input_filter::Chargen_source : public Source, Source::Sink
unsigned char const ascii = value.string()[0]; unsigned char const ascii = value.string()[0];
if (ascii < 128) if (ascii < 128)
return Input::Event::Utf8(ascii); return Codepoint { ascii };
warning("char attribute with non-ascii character " warning("char attribute with non-ascii character "
"'", value, "'"); "'", value, "'");
@ -312,12 +317,13 @@ class Input_filter::Chargen_source : public Source, Source::Sink
} }
if (node.has_attribute("b0")) { if (node.has_attribute("b0")) {
unsigned char const b0 = node.attribute_value("b0", 0UL), char const b0 = node.attribute_value("b0", 0L),
b1 = node.attribute_value("b1", 0UL), b1 = node.attribute_value("b1", 0L),
b2 = node.attribute_value("b2", 0UL), b2 = node.attribute_value("b2", 0L),
b3 = node.attribute_value("b3", 0UL); b3 = node.attribute_value("b3", 0L);
return Input::Event::Utf8(b0, b1, b2, b3); char const buf[5] { b0, b1, b2, b3, 0 };
return Utf8_ptr(buf).codepoint();
} }
throw Missing_character_definition(); throw Missing_character_definition();
@ -340,7 +346,7 @@ class Input_filter::Chargen_source : public Source, Source::Sink
Input::Keycode const code = key_code_by_name(name); Input::Keycode const code = key_code_by_name(name);
new (_alloc) Key::Rule(key(code).rules, cond, new (_alloc) Key::Rule(key(code).rules, cond,
_utf8_from_xml_node(key_node)); _codepoint_from_xml_node(key_node));
}); });
} }
@ -377,14 +383,16 @@ class Input_filter::Chargen_source : public Source, Source::Sink
Microseconds const _delay; Microseconds const _delay;
Microseconds const _rate; Microseconds const _rate;
Input::Event::Utf8 _curr_character { 0 }; Codepoint _curr_character { Codepoint::INVALID };
enum State { IDLE, REPEAT } _state { IDLE }; enum State { IDLE, REPEAT } _state { IDLE };
void _handle_timeout(Duration) void _handle_timeout(Duration)
{ {
if (_state == REPEAT) { if (_state == REPEAT) {
_destination.submit_event(Input::Event(_curr_character)); _destination.submit_event(Input::Press_char{Input::KEY_UNKNOWN,
_curr_character});
_destination.submit_event(Input::Release{Input::KEY_UNKNOWN});
_timeout.schedule(_rate); _timeout.schedule(_rate);
} }
} }
@ -400,7 +408,7 @@ class Input_filter::Chargen_source : public Source, Source::Sink
_rate (node.attribute_value("rate_ms", 0UL)*1000) _rate (node.attribute_value("rate_ms", 0UL)*1000)
{ } { }
void schedule_repeat(Input::Event::Utf8 character) void schedule_repeat(Codepoint character)
{ {
_curr_character = character; _curr_character = character;
_state = REPEAT; _state = REPEAT;
@ -410,7 +418,7 @@ class Input_filter::Chargen_source : public Source, Source::Sink
void cancel() void cancel()
{ {
_curr_character = Input::Event::Utf8(0); _curr_character = Codepoint { Codepoint::INVALID };
_state = IDLE; _state = IDLE;
} }
}; };
@ -420,43 +428,40 @@ class Input_filter::Chargen_source : public Source, Source::Sink
/** /**
* Sink interface (called from our child node) * Sink interface (called from our child node)
*/ */
void submit_event(Input::Event const &event) override void submit_event(Event const &event) override
{ {
using Input::Event; Event ev = event;
/* forward event as is */ ev.handle_press([&] (Input::Keycode keycode, Codepoint /* ignored */) {
_destination.submit_event(event);
/* don't do anything for non-press/release events */ Key &key = _key_map.key(keycode);
if (event.type() != Event::PRESS && event.type() != Event::RELEASE) key.state = Key::PRESSED;
return;
Key &key = _key_map.key(event.keycode()); if (key.type == Key::MODIFIER) _update_modifier_state();
/* track key state */ /* supplement codepoint information to press event */
if (event.type() == Event::PRESS) key.state = Key::PRESSED; key.apply_best_matching_rule(_mod_map, [&] (Codepoint codepoint) {
if (event.type() == Event::RELEASE) key.state = Key::RELEASED;
if (key.type == Key::MODIFIER) { ev = Event(Input::Press_char{keycode, codepoint});
_update_modifier_state();
/* never emit a character when pressing a modifier key */
return;
}
if (event.type() == Event::PRESS) {
key.apply_best_matching_rule(_mod_map, [&] (Event::Utf8 utf8) {
_destination.submit_event(Event(utf8));
if (_char_repeater.constructed()) if (_char_repeater.constructed())
_char_repeater->schedule_repeat(utf8); _char_repeater->schedule_repeat(codepoint);
}); });
} });
ev.handle_release([&] (Input::Keycode keycode) {
Key &key = _key_map.key(keycode);
key.state = Key::RELEASED;
if (key.type == Key::MODIFIER) _update_modifier_state();
if (event.type() == Event::RELEASE)
if (_char_repeater.constructed()) if (_char_repeater.constructed())
_char_repeater->cancel(); _char_repeater->cancel();
});
/* forward filtered event */
_destination.submit_event(ev);
} }
Source &_source; Source &_source;

View File

@ -82,8 +82,8 @@ class Input_filter::Input_connection
auto update_key_cnt = [&] (Input::Event const &event) auto update_key_cnt = [&] (Input::Event const &event)
{ {
if (event.type() == Input::Event::PRESS) _key_cnt++; if (event.press()) _key_cnt++;
if (event.type() == Input::Event::RELEASE) _key_cnt--; if (event.release()) _key_cnt--;
}; };
for_each_event(update_key_cnt); for_each_event(update_key_cnt);

View File

@ -51,22 +51,25 @@ class Input_filter::Remap_source : public Source, Source::Sink
{ {
using Input::Event; using Input::Event;
bool const key_event =
event.type() == Event::PRESS || event.type() == Event::RELEASE;
bool const code_valid =
event.keycode() >= 0 && event.keycode() < Input::KEY_MAX;
/* forward events that are unrelated to the remapper */ /* forward events that are unrelated to the remapper */
if (!key_event || !code_valid) { if (!event.press() && !event.release()) {
_destination.submit_event(event); _destination.submit_event(event);
return; return;
} }
/* remap the key code */ /*
Key &key = _keys[event.keycode()]; * remap the key code for press and release events
*
* The range of the 'key' is checked by the 'Event' handle methods,
* so it is safe to use as array index.
*/
auto remap = [&] (Input::Keycode key) { return _keys[key].code; };
_destination.submit_event(Event(event.type(), key.code, 0, 0, 0, 0)); event.handle_press([&] (Input::Keycode key, Codepoint codepoint) {
_destination.submit_event(Input::Press_char{remap(key), codepoint}); });
event.handle_release([&] (Input::Keycode key) {
_destination.submit_event(Input::Release{remap(key)}); });
} }
void _apply_config(Xml_node const config, unsigned const max_recursion = 4) void _apply_config(Xml_node const config, unsigned const max_recursion = 4)

View File

@ -85,19 +85,10 @@ class Input::Session_component : public Rpc_object<Session>
Input::Event &ev = _ev_buf[i]; Input::Event &ev = _ev_buf[i];
if ((ev.type() == Input::Event::MOTION) ev.handle_absolute_motion([&] (int x, int y) {
|| (ev.type() == Input::Event::WHEEL) Point<> p = Point<>(x, y) + delta;
|| (ev.code() == Input::BTN_LEFT) ev = Input::Absolute_motion{p.x(), p.y()};
|| (ev.code() == Input::BTN_RIGHT) });
|| (ev.code() == Input::BTN_MIDDLE)) {
ev = Input::Event(ev.type(),
ev.code(),
ev.ax() + delta.x(),
ev.ay() + delta.y(),
ev.rx(),
ev.ry());
}
} }
return num_ev; return num_ev;

View File

@ -42,42 +42,31 @@ namespace Nit_fb {
/** /**
* Translate input event * Translate input event
*/ */
static Input::Event translate_event(Input::Event const ev, static Input::Event translate_event(Input::Event ev,
Nit_fb::Point const input_origin, Nit_fb::Point const input_origin,
Nit_fb::Area const boundary) Nit_fb::Area const boundary)
{ {
switch (ev.type()) { using Nit_fb::Point;
case Input::Event::MOTION: /* function to clamp point to bounday */
case Input::Event::PRESS: auto clamp = [boundary] (Point p) {
case Input::Event::RELEASE: return Point(Genode::min((int)boundary.w() - 1, Genode::max(0, p.x())),
case Input::Event::FOCUS: Genode::min((int)boundary.h() - 1, Genode::max(0, p.y()))); };
case Input::Event::LEAVE:
case Input::Event::TOUCH:
{
Nit_fb::Point abs_pos = Nit_fb::Point(ev.ax(), ev.ay()) -
input_origin;
using Genode::min; /* function to translate point to 'input_origin' */
using Genode::max; auto translate = [input_origin] (Point p) { return p - input_origin; };
using Input::Event;
int const ax = min((int)boundary.w() - 1, max(0, abs_pos.x())); ev.handle_absolute_motion([&] (int x, int y) {
int const ay = min((int)boundary.h() - 1, max(0, abs_pos.y())); Point p = clamp(translate(Point(x, y)));
ev = Input::Absolute_motion{p.x(), p.y()};
});
if (ev.type() == Event::TOUCH) ev.handle_touch([&] (Input::Touch_id id, float x, float y) {
return Event::create_touch_event(ax, ay, ev.code(), Point p = clamp(translate(Point(x, y)));
ev.is_touch_release()); ev = Input::Touch{id, (float)p.x(), (float)p.y()};
});
return Event(ev.type(), ev.code(), ax, ay, 0, 0); return ev;
}
case Input::Event::INVALID:
case Input::Event::WHEEL:
case Input::Event::CHARACTER:
return ev;
}
return Input::Event();
} }
@ -424,9 +413,7 @@ struct Nit_fb::Main : View_updater
bool update = false; bool update = false;
for (unsigned i = 0; i < num; i++) { for (unsigned i = 0; i < num; i++) {
if (events[i].type() == Input::Event::FOCUS) update |= events[i].focus_enter();
update = events[i].code();
input_session.submit(translate_event(events[i], position, fb_session.size())); input_session.submit(translate_event(events[i], position, fb_session.size()));
} }

View File

@ -238,14 +238,14 @@ void Session_component::submit_input_event(Input::Event e)
Point const origin_offset = _phys_pos(Point(0, 0), _view_stack.size()); Point const origin_offset = _phys_pos(Point(0, 0), _view_stack.size());
/* /*
* Transpose absolute coordinates by session-specific vertical * Transpose absolute coordinates by session-specific vertical offset.
* offset.
*/ */
if (e.ax() || e.ay()) e.handle_absolute_motion([&] (int x, int y) {
e = Event(e.type(), e.code(), e = Absolute_motion{max(0, x - origin_offset.x()),
max(0, e.ax() - origin_offset.x()), max(0, y - origin_offset.y())}; });
max(0, e.ay() - origin_offset.y()), e.handle_touch([&] (Touch_id id, float x, float y) {
e.rx(), e.ry()); e = Touch{ id, max(0.0f, x - origin_offset.x()),
max(0.0f, y - origin_offset.y())}; });
_input_session_component.submit(&e); _input_session_component.submit(&e);
} }

View File

@ -37,16 +37,16 @@ static inline bool _mouse_button(Keycode keycode) {
static unsigned num_consecutive_events(Input::Event const *ev, unsigned max) static unsigned num_consecutive_events(Input::Event const *ev, unsigned max)
{ {
if (max < 1) return 0; if (max < 1) return 0;
if (ev->type() != Input::Event::MOTION) return 1;
bool const first_absolute = ev->absolute_motion(); bool const first_is_absolute_motion = ev->absolute_motion();
bool const first_is_relative_motion = ev->relative_motion();
/* iterate until we get a different event type, start at second */
unsigned cnt = 1; unsigned cnt = 1;
for (ev++ ; cnt < max; cnt++, ev++) { for (ev++ ; cnt < max; cnt++, ev++) {
if (ev->type() != Input::Event::MOTION) break; if (first_is_absolute_motion && ev->absolute_motion()) continue;
if (first_absolute != ev->absolute_motion()) break; if (first_is_relative_motion && ev->relative_motion()) continue;
} break;
};
return cnt; return cnt;
} }
@ -60,11 +60,26 @@ static unsigned num_consecutive_events(Input::Event const *ev, unsigned max)
*/ */
static Input::Event merge_motion_events(Input::Event const *ev, unsigned n) static Input::Event merge_motion_events(Input::Event const *ev, unsigned n)
{ {
Input::Event res; if (n == 0) return Event();
for (unsigned i = 0; i < n; i++, ev++)
res = Input::Event(Input::Event::MOTION, 0, ev->ax(), ev->ay(), if (ev->relative_motion()) {
res.rx() + ev->rx(), res.ry() + ev->ry()); int rx = 0, ry = 0;
return res; for (unsigned i = 0; i < n; i++, ev++)
ev->handle_relative_motion([&] (int x, int y) { rx += x; ry += y; });
if (rx || ry)
return Relative_motion{rx, ry};
}
if (ev->absolute_motion()) {
int ax = 0, ay = 0;
for (unsigned i = 0; i < n; i++, ev++)
ev->handle_absolute_motion([&] (int x, int y) { ax = x; ay = y; });
return Absolute_motion{ax, ay};
}
return Event();
} }
@ -74,62 +89,40 @@ static Input::Event merge_motion_events(Input::Event const *ev, unsigned n)
void User_state::_handle_input_event(Input::Event ev) void User_state::_handle_input_event(Input::Event ev)
{ {
Input::Keycode const keycode = ev.keycode(); /* transparently convert relative into absolute motion event */
Input::Event::Type const type = ev.type(); ev.handle_relative_motion([&] (int x, int y) {
/* int const ox = _pointer_pos.x(),
* Mangle incoming events oy = _pointer_pos.y();
*/
int ax = _pointer_pos.x(), ay = _pointer_pos.y();
int rx = 0, ry = 0; /* skip info about relative motion by default */
/* transparently handle absolute and relative motion events */ int const ax = max(0, min((int)_view_stack.size().w() - 1, ox + x)),
if (type == Event::MOTION) { ay = max(0, min((int)_view_stack.size().h() - 1, oy + y));
if ((ev.rx() || ev.ry()) && ev.ax() == 0 && ev.ay() == 0) {
ax = max(0, min((int)_view_stack.size().w() - 1, ax + ev.rx()));
ay = max(0, min((int)_view_stack.size().h() - 1, ay + ev.ry()));
} else {
ax = ev.ax();
ay = ev.ay();
}
}
/* propagate relative motion for wheel events */ ev = Absolute_motion{ax, ay};
if (type == Event::WHEEL) { });
rx = ev.rx();
ry = ev.ry();
}
if (type == Event::TOUCH) { /* respond to motion events by updating the pointer position */
ax = ev.ax(); ev.handle_absolute_motion([&] (int x, int y) {
ay = ev.ay(); _pointer_pos = Point(x, y); });
ev = Input::Event::create_touch_event(ax, ay, ev.code(),
ev.touch_release());
} else if (type == Event::CHARACTER) {
ev = Input::Event(type, ev.code(), ax, ay, rx, ry);
} else
ev = Input::Event(type, keycode, ax, ay, rx, ry);
_pointer_pos = Point(ax, ay);
bool const drag = _key_cnt > 0; bool const drag = _key_cnt > 0;
/* count keys */ /* count keys */
if (type == Event::PRESS) _key_cnt++; if (ev.press()) _key_cnt++;
if (type == Event::RELEASE && drag) _key_cnt--; if (ev.release() && drag) _key_cnt--;
/* track key states */ /* track key states */
if (type == Event::PRESS) { ev.handle_press([&] (Keycode key, Codepoint) {
if (_key_array.pressed(keycode)) if (_key_array.pressed(key))
Genode::warning("suspicious double press of ", Input::key_name(keycode)); Genode::warning("suspicious double press of ", Input::key_name(key));
_key_array.pressed(keycode, true); _key_array.pressed(key, true);
} });
if (type == Event::RELEASE) { ev.handle_release([&] (Keycode key) {
if (!_key_array.pressed(keycode)) if (!_key_array.pressed(key))
Genode::warning("suspicious double release of ", Input::key_name(keycode)); Genode::warning("suspicious double release of ", Input::key_name(key));
_key_array.pressed(keycode, false); _key_array.pressed(key, false);
} });
View_component const * const pointed_view = _view_stack.find_view(_pointer_pos); View_component const * const pointed_view = _view_stack.find_view(_pointer_pos);
@ -138,18 +131,18 @@ void User_state::_handle_input_event(Input::Event ev)
/* /*
* Deliver a leave event if pointed-to session changed * Deliver a leave event if pointed-to session changed
*/ */
if (_hovered && (hovered != _hovered)) { if (_hovered && (hovered != _hovered))
_hovered->submit_input_event(Hover_leave());
Input::Event leave_ev(Input::Event::LEAVE, 0, ax, ay, 0, 0);
_hovered->submit_input_event(leave_ev);
}
_hovered = hovered; _hovered = hovered;
/* /*
* Handle start of a key sequence * Handle start of a key sequence
*/ */
if (type == Event::PRESS && (_key_cnt == 1)) { ev.handle_press([&] (Keycode keycode, Codepoint) {
if (_key_cnt != 1)
return;
View_owner *global_receiver = nullptr; View_owner *global_receiver = nullptr;
@ -163,14 +156,13 @@ void User_state::_handle_input_event(Input::Event ev)
/* /*
* Notify both the old focused session and the new one. * Notify both the old focused session and the new one.
*/ */
if (_focused) { if (_focused)
Input::Event unfocus_ev(Input::Event::FOCUS, 0, ax, ay, 0, 0); _focused->submit_input_event(Focus_leave());
_focused->submit_input_event(unfocus_ev);
}
if (_hovered) { if (_hovered) {
Input::Event focus_ev(Input::Event::FOCUS, 1, ax, ay, 0, 0); _hovered->submit_input_event(Absolute_motion{_pointer_pos.x(),
_hovered->submit_input_event(focus_ev); _pointer_pos.y()});
_hovered->submit_input_event(Focus_enter());
} }
if (_hovered->has_transient_focusable_domain()) { if (_hovered->has_transient_focusable_domain()) {
@ -219,12 +211,12 @@ void User_state::_handle_input_event(Input::Event ev)
*/ */
if (!global_receiver) if (!global_receiver)
_input_receiver = _focused; _input_receiver = _focused;
} });
/* /*
* Deliver event to session * Deliver event to session
*/ */
if (type == Event::MOTION || type == Event::WHEEL || type == Event::TOUCH) { if (ev.absolute_motion() || ev.wheel() || ev.touch() || ev.touch_release()) {
if (_key_cnt == 0) { if (_key_cnt == 0) {
@ -248,30 +240,28 @@ void User_state::_handle_input_event(Input::Event ev)
* Deliver press/release event to focused session or the receiver of global * Deliver press/release event to focused session or the receiver of global
* key. * key.
*/ */
if ((type == Event::PRESS) && _input_receiver) { ev.handle_press([&] (Keycode key, Codepoint) {
if (!_mouse_button(ev.keycode())
if (!_input_receiver)
return;
if (!_mouse_button(key)
|| (_hovered || (_hovered
&& (_hovered->has_focusable_domain() && (_hovered->has_focusable_domain()
|| _hovered->has_same_domain(_focused)))) || _hovered->has_same_domain(_focused))))
_input_receiver->submit_input_event(ev); _input_receiver->submit_input_event(ev);
else else
_input_receiver = nullptr; _input_receiver = nullptr;
} });
if ((type == Event::RELEASE) && _input_receiver) if (ev.release() && _input_receiver)
_input_receiver->submit_input_event(ev);
/*
* Forward character events
*/
if (type == Event::CHARACTER && _input_receiver)
_input_receiver->submit_input_event(ev); _input_receiver->submit_input_event(ev);
/* /*
* Detect end of global key sequence * Detect end of global key sequence
*/ */
if (ev.type() == Event::RELEASE && (_key_cnt == 0) && _global_key_sequence) { if (ev.release() && (_key_cnt == 0) && _global_key_sequence) {
_input_receiver = _focused; _input_receiver = _focused;
_global_key_sequence = false; _global_key_sequence = false;
} }
} }
@ -299,22 +289,14 @@ User_state::handle_input_events(Input::Event const * const ev_buf,
Input::Event const *e = &ev_buf[src_ev_cnt]; Input::Event const *e = &ev_buf[src_ev_cnt];
Input::Event curr = *e; Input::Event curr = *e;
if (e->type() == Input::Event::MOTION) { if (e->absolute_motion() || e->relative_motion()) {
unsigned n = num_consecutive_events(e, num_ev - src_ev_cnt); unsigned const n = num_consecutive_events(e, num_ev - src_ev_cnt);
curr = merge_motion_events(e, n); curr = merge_motion_events(e, n);
/* skip merged events */ /* skip merged events */
src_ev_cnt += n - 1; src_ev_cnt += n - 1;
} }
/*
* If subsequential relative motion events are merged to
* a zero-motion event, drop it. Otherwise, it would be
* misinterpreted as absolute event pointing to (0, 0).
*/
if (e->relative_motion() && curr.rx() == 0 && curr.ry() == 0)
continue;
/* /*
* If we detect a pressed key sometime during the event processing, * If we detect a pressed key sometime during the event processing,
* we regard the user as active. This check captures the presence * we regard the user as active. This check captures the presence
@ -331,7 +313,7 @@ User_state::handle_input_events(Input::Event const * const ev_buf,
* updates the pointed session, which might have changed by other * updates the pointed session, which might have changed by other
* means, for example view movement. * means, for example view movement.
*/ */
_handle_input_event(Input::Event()); _handle_input_event(Event());
} }
/* /*
@ -341,8 +323,7 @@ User_state::handle_input_events(Input::Event const * const ev_buf,
bool key_state_affected = false; bool key_state_affected = false;
for (unsigned i = 0; i < num_ev; i++) for (unsigned i = 0; i < num_ev; i++)
key_state_affected |= (ev_buf[i].type() == Input::Event::PRESS) || key_state_affected |= (ev_buf[i].press() || ev_buf[i].release());
(ev_buf[i].type() == Input::Event::RELEASE);
_apply_pending_focus_change(); _apply_pending_focus_change();

View File

@ -133,13 +133,9 @@ struct Main
void _handle() void _handle()
{ {
for (int i = 0, num_ev = _input.flush(); i < num_ev; ++i) { _input.for_each_event([&] (Input::Event const &ev) {
Input::Event const ev = _ev_ds.local_addr<Input::Event const>()[i]; if (ev.press())
if (ev.type() == Input::Event::PRESS) { _click.play(); });
_click.play();
break;
}
}
} }
Main(Env & env) : _env(env) Main(Env & env) : _env(env)

View File

@ -19,69 +19,25 @@
using namespace Genode; using namespace Genode;
static char const * ev_type(Input::Event::Type type)
{
switch (type) {
case Input::Event::INVALID: return "INVALID";
case Input::Event::MOTION: return "MOTION ";
case Input::Event::PRESS: return "PRESS ";
case Input::Event::RELEASE: return "RELEASE";
case Input::Event::WHEEL: return "WHEEL ";
case Input::Event::FOCUS: return "FOCUS ";
case Input::Event::LEAVE: return "LEAVE ";
case Input::Event::TOUCH: return "TOUCH ";
case Input::Event::CHARACTER: return "CHARACTER";
}
return "";
}
static char const * key_name(Input::Event const &ev)
{
if (ev.type() == Input::Event::MOTION)
return "";
return Input::key_name(static_cast<Input::Keycode>(ev.code()));
}
struct Main struct Main
{ {
Env &env; Env &_env;
Input::Connection input { env }; Input::Connection _input { _env };
Signal_handler<Main> input_sigh { env.ep(), *this, &Main::handle_input }; Signal_handler<Main> _input_sigh { _env.ep(), *this, &Main::_handle_input };
int key_cnt { 0 }; unsigned _event_cnt { 0 };
unsigned event_cnt { 0 };
void handle_input(); void _handle_input()
{
_input.for_each_event([&] (Input::Event const &ev) {
log("Input event #", _event_cnt++, "\t", ev); });
}
Main(Env &env) : env(env) Main(Env &env) : _env(env)
{ {
log("--- Input test ---"); log("--- Input test ---");
input.sigh(input_sigh); _input.sigh(_input_sigh);
} }
}; };
void Main::handle_input()
{
input.for_each_event([&] (Input::Event const &ev) {
event_cnt++;
if (ev.type() == Input::Event::PRESS) key_cnt++;
if (ev.type() == Input::Event::RELEASE) key_cnt--;
log("Input event #", event_cnt, "\t"
"type=", ev_type(ev.type()), "\t"
"code=", ev.code(), "\t"
"rx=", ev.rx(), "\t"
"ry=", ev.ry(), "\t"
"ax=", ev.ax(), "\t"
"ay=", ev.ay(), "\t"
"key_cnt=", key_cnt, "\t", key_name(ev));
});
}
void Component::construct(Env &env) { static Main main(env); } void Component::construct(Env &env) { static Main main(env); }

View File

@ -31,28 +31,7 @@ namespace Test {
class Input_root; class Input_root;
class Main; class Main;
using namespace Genode; using namespace Genode;
} using Input::Event;
namespace Genode {
static inline void print(Output &output, Input::Event const &ev)
{
switch (ev.type()) {
case Input::Event::INVALID: print(output, "INVALID"); break;
case Input::Event::MOTION: print(output, "MOTION"); break;
case Input::Event::PRESS: print(output, "PRESS"); break;
case Input::Event::RELEASE: print(output, "RELEASE"); break;
case Input::Event::WHEEL: print(output, "WHEEL"); break;
case Input::Event::FOCUS: print(output, "FOCUS"); break;
case Input::Event::LEAVE: print(output, "LEAVE"); break;
case Input::Event::TOUCH: print(output, "TOUCH"); break;
case Input::Event::CHARACTER: print(output, "CHARACTER"); break;
};
if (ev.type() == Input::Event::PRESS || ev.type() == Input::Event::RELEASE)
print(output, " (", Input::key_name(ev.keycode()), ")");
}
} }
@ -62,7 +41,7 @@ class Test::Input_from_filter
struct Event_handler : Interface struct Event_handler : Interface
{ {
virtual void handle_event_from_filter(Input::Event const &) = 0; virtual void handle_event_from_filter(Event const &) = 0;
}; };
private: private:
@ -82,7 +61,7 @@ class Test::Input_from_filter
_handle_input_in_progress = true; _handle_input_in_progress = true;
if (_input_expected) if (_input_expected)
_connection.for_each_event([&] (Input::Event const &event) { _connection.for_each_event([&] (Event const &event) {
_event_handler.handle_event_from_filter(event); }); _event_handler.handle_event_from_filter(event); });
_handle_input_in_progress = false; _handle_input_in_progress = false;
@ -211,24 +190,28 @@ class Test::Input_to_filter
step.for_each_sub_node([&] (Xml_node node) { step.for_each_sub_node([&] (Xml_node node) {
Input::Event::Type const type = bool const press = node.has_type("press"),
node.type() == "press" ? Input::Event::PRESS : release = node.has_type("release");
node.type() == "release" ? Input::Event::RELEASE :
node.type() == "motion" ? Input::Event::MOTION : if (press || release) {
Input::Event::INVALID;
if (type == Input::Event::PRESS || type == Input::Event::RELEASE) {
Key_name const key_name = node.attribute_value("code", Key_name()); Key_name const key_name = node.attribute_value("code", Key_name());
dst.submit(Input::Event(type, _code(key_name), 0, 0, 0, 0));
if (press) dst.submit(Input::Press {_code(key_name)});
if (release) dst.submit(Input::Release{_code(key_name)});
} }
if (type == Input::Event::MOTION) { bool const motion = node.has_type("motion");
dst.submit(Input::Event(type, 0, bool const rel = node.has_attribute("rx") || node.has_attribute("ry");
node.attribute_value("ax", 0L), bool const abs = node.has_attribute("ax") || node.has_attribute("ay");
node.attribute_value("ay", 0L),
node.attribute_value("rx", 0L), if (motion && abs)
node.attribute_value("ry", 0L))); dst.submit(Input::Absolute_motion{(int)node.attribute_value("ax", 0L),
} (int)node.attribute_value("ay", 0L)});
if (motion && rel)
dst.submit(Input::Relative_motion{(int)node.attribute_value("rx", 0L),
(int)node.attribute_value("ry", 0L)});
}); });
} }
}; };
@ -379,52 +362,53 @@ struct Test::Main : Input_from_filter::Event_handler
/** /**
* Input_to_filter::Event_handler interface * Input_to_filter::Event_handler interface
*/ */
void handle_event_from_filter(Input::Event const &ev) override void handle_event_from_filter(Event const &ev) override
{ {
typedef Genode::String<20> Value; typedef Genode::String<20> Value;
Xml_node const step = _curr_step_xml(); Xml_node const step = _curr_step_xml();
switch (ev.type()) { bool step_succeeded = false;
case Input::Event::PRESS:
ev.handle_press([&] (Input::Keycode key, Codepoint codepoint) {
auto codepoint_of_step = [] (Xml_node step) {
return Utf8_ptr(step.attribute_value("char", Value()).string()).codepoint(); };
if (step.type() == "expect_press" if (step.type() == "expect_press"
&& step.attribute_value("code", Value()) == Input::key_name(ev.keycode())) && step.attribute_value("code", Value()) == Input::key_name(key)
break; && (!step.has_attribute("char") ||
codepoint_of_step(step).value == codepoint.value))
step_succeeded = true;
});
case Input::Event::RELEASE: ev.handle_release([&] (Input::Keycode key) {
if (step.type() == "expect_release" if (step.type() == "expect_release"
&& step.attribute_value("code", Value()) == Input::key_name(ev.keycode())) && step.attribute_value("code", Value()) == Input::key_name(key))
break; step_succeeded = true; });
case Input::Event::WHEEL: ev.handle_wheel([&] (int x, int y) {
if (step.type() == "expect_wheel" if (step.type() == "expect_wheel"
&& step.attribute_value("rx", 0L) == ev.rx() && step.attribute_value("rx", 0L) == x
&& step.attribute_value("ry", 0L) == ev.ry()) && step.attribute_value("ry", 0L) == y)
break; step_succeeded = true; });
case Input::Event::MOTION: ev.handle_relative_motion([&] (int x, int y) {
if (step.type() == "expect_motion" if (step.type() == "expect_motion"
&& (!step.has_attribute("rx") || step.attribute_value("rx", 0L) == ev.rx()) && (!step.has_attribute("rx") || step.attribute_value("rx", 0L) == x)
&& (!step.has_attribute("ry") || step.attribute_value("ry", 0L) == ev.ry()) && (!step.has_attribute("ry") || step.attribute_value("ry", 0L) == y))
&& (!step.has_attribute("ax") || step.attribute_value("ax", 0L) == ev.ax()) step_succeeded = true; });
&& (!step.has_attribute("ay") || step.attribute_value("ay", 0L) == ev.ay()))
break;
case Input::Event::CHARACTER: ev.handle_absolute_motion([&] (int x, int y) {
if (step.type() == "expect_char" if (step.type() == "expect_motion"
&& step.attribute_value("char", Value()) == Value(Char(ev.utf8().b0))) && (!step.has_attribute("ax") || step.attribute_value("ax", 0L) == x)
break; && (!step.has_attribute("ay") || step.attribute_value("ay", 0L) == y))
step_succeeded = true; });
case Input::Event::INVALID: if (step_succeeded) {
case Input::Event::FOCUS: _advance_step();
case Input::Event::LEAVE: _execute_curr_step();
case Input::Event::TOUCH: }
error("unexpected event: ", ev);
throw Exception();
};
_advance_step();
_execute_curr_step();
} }
void _handle_timer() void _handle_timer()

View File

@ -203,30 +203,32 @@ void Component::construct(Genode::Env &env)
/* /*
* Handle input events * Handle input events
*/ */
int omx = 0, omy = 0, key_cnt = 0; int mx = 0, my = 0, key_cnt = 0;
Test_view *tv = 0; Test_view *tv = nullptr;
while (1) { while (1) {
while (!nitpicker.input()->pending()) timer.msleep(20); while (!nitpicker.input()->pending()) timer.msleep(20);
nitpicker.input()->for_each_event([&] (Input::Event const &ev) { nitpicker.input()->for_each_event([&] (Input::Event const &ev) {
if (ev.type() == Input::Event::PRESS) key_cnt++;
if (ev.type() == Input::Event::RELEASE) key_cnt--;
/* move selected view */ if (ev.press()) key_cnt++;
if (ev.type() == Input::Event::MOTION && key_cnt > 0 && tv) if (ev.release()) key_cnt--;
tv->move(tv->x() + ev.ax() - omx, tv->y() + ev.ay() - omy);
ev.handle_absolute_motion([&] (int x, int y) {
/* move selected view */
if (key_cnt > 0 && tv)
tv->move(tv->x() + x - mx, tv->y() + y - my);
mx = x; my = y;
});
/* find selected view and bring it to front */ /* find selected view and bring it to front */
if (ev.type() == Input::Event::PRESS && key_cnt == 1) { if (ev.press() && key_cnt == 1) {
tv = tvs.find(mx, my);
tv = tvs.find(ev.ax(), ev.ay());
if (tv) if (tv)
tvs.top(tv); tvs.top(tv);
} }
omx = ev.ax(); omy = ev.ay();
}); });
} }

View File

@ -66,17 +66,22 @@ struct Ps2_mouse_packet : Genode::Register<32>
static bool mouse_event(Input::Event const &ev) static bool mouse_event(Input::Event const &ev)
{ {
using Input::Event; using namespace Input;
if (ev.type() == Event::PRESS || ev.type() == Event::RELEASE) {
if (ev.code() == Input::BTN_LEFT) return true;
if (ev.code() == Input::BTN_MIDDLE) return true;
if (ev.code() == Input::BTN_RIGHT) return true;
}
if (ev.type() == Event::MOTION) bool result = false;
return true;
return false; auto mouse_button = [] (Keycode key) {
return key == BTN_LEFT || key == BTN_MIDDLE || key == BTN_RIGHT; };
ev.handle_press([&] (Keycode key, Genode::Codepoint) {
result |= mouse_button(key); });
ev.handle_release([&] (Keycode key) {
result |= mouse_button(key); });
result |= ev.absolute_motion() || ev.relative_motion();
return result;
} }
@ -88,26 +93,25 @@ static bool mouse_event(Input::Event const &ev)
unsigned Seoul::Console::_input_to_ps2mouse(Input::Event const &ev) unsigned Seoul::Console::_input_to_ps2mouse(Input::Event const &ev)
{ {
/* track state of mouse buttons */ /* track state of mouse buttons */
using Input::Event; auto apply_button = [] (Input::Event const &ev, Input::Keycode key, bool &state) {
if (ev.type() == Event::PRESS || ev.type() == Event::RELEASE) { if (ev.key_press (key)) state = true;
bool const pressed = ev.type() == Event::PRESS; if (ev.key_release(key)) state = false;
if (ev.code() == Input::BTN_LEFT) _left = pressed; };
if (ev.code() == Input::BTN_MIDDLE) _middle = pressed;
if (ev.code() == Input::BTN_RIGHT) _right = pressed;
}
int rx; apply_button(ev, Input::BTN_LEFT, _left);
int ry; apply_button(ev, Input::BTN_MIDDLE, _middle);
apply_button(ev, Input::BTN_RIGHT, _right);
if (ev.absolute_motion()) { int rx = 0;
static Input::Event last_event; int ry = 0;
rx = ev.ax() - last_event.ax();
ry = ev.ay() - last_event.ay(); ev.handle_absolute_motion([&] (int x, int y) {
last_event = ev; static int ox = 0, oy = 0;
} else { rx = x - ox; ry = y - oy;
rx = ev.rx(); ox = x; oy = y;
ry = ev.ry(); });
}
ev.handle_relative_motion([&] (int x, int y) { rx = x; ry = y; });
/* clamp relative motion vector to bounds */ /* clamp relative motion vector to bounds */
int const boundary = 200; int const boundary = 200;
@ -316,16 +320,13 @@ void Seoul::Console::_handle_input()
_motherboard()->bus_input.send(msg); _motherboard()->bus_input.send(msg);
} }
if (ev.type() == Input::Event::PRESS) { ev.handle_press([&] (Input::Keycode key, Genode::Codepoint) {
if (ev.code() <= 0xee) { if (key <= 0xee)
_vkeyb.handle_keycode_press(ev.code()); _vkeyb.handle_keycode_press(key); });
}
} ev.handle_release([&] (Input::Keycode key) {
if (ev.type() == Input::Event::RELEASE) { if (key <= 0xee)
if (ev.code() <= 0xee) { /* keyboard event */ _vkeyb.handle_keycode_release(key); });
_vkeyb.handle_keycode_release(ev.code());
}
}
}); });
} }

View File

@ -203,18 +203,11 @@ void GenodeConsole::handle_input()
if (!_vbox_keyboard || !_vbox_mouse) if (!_vbox_keyboard || !_vbox_mouse)
return; return;
bool const press = ev.type() == Input::Event::PRESS; auto keyboard_submit = [&] (Input::Keycode key, bool release) {
bool const release = ev.type() == Input::Event::RELEASE;
bool const key = press || release;
bool const motion = ev.type() == Input::Event::MOTION;
bool const wheel = ev.type() == Input::Event::WHEEL;
bool const touch = ev.type() == Input::Event::TOUCH;
if (key) { Scan_code scan_code(key);
Scan_code scan_code(ev.keycode());
unsigned char const release_bit = unsigned char const release_bit = release ? 0x80 : 0;
(ev.type() == Input::Event::RELEASE) ? 0x80 : 0;
if (scan_code.normal()) if (scan_code.normal())
_vbox_keyboard->PutScancode(scan_code.code() | release_bit); _vbox_keyboard->PutScancode(scan_code.code() | release_bit);
@ -223,122 +216,116 @@ void GenodeConsole::handle_input()
_vbox_keyboard->PutScancode(0xe0); _vbox_keyboard->PutScancode(0xe0);
_vbox_keyboard->PutScancode(scan_code.ext() | release_bit); _vbox_keyboard->PutScancode(scan_code.ext() | release_bit);
} }
} };
/* /* obtain bit mask of currently pressed mouse buttons */
* Track press/release status of keys and buttons. Currently, auto curr_mouse_button_bits = [&] () {
* only the mouse-button states are actually used. return (_key_status[Input::BTN_LEFT] ? MouseButtonState_LeftButton : 0)
*/ | (_key_status[Input::BTN_RIGHT] ? MouseButtonState_RightButton : 0)
if (press) | (_key_status[Input::BTN_MIDDLE] ? MouseButtonState_MiddleButton : 0);
_key_status[ev.keycode()] = true; };
if (release) unsigned const old_mouse_button_bits = curr_mouse_button_bits();
_key_status[ev.keycode()] = false;
bool const mouse_button_event = ev.handle_press([&] (Input::Keycode key, Genode::Codepoint) {
key && _mouse_button(ev.keycode()); keyboard_submit(key, false);
_key_status[key] = true;
});
bool const mouse_event = mouse_button_event || motion; ev.handle_release([&] (Input::Keycode key) {
keyboard_submit(key, true);
_key_status[key] = false;
});
if (mouse_event) { unsigned const mouse_button_bits = curr_mouse_button_bits();
unsigned const buttons = (_key_status[Input::BTN_LEFT] ? MouseButtonState_LeftButton : 0)
| (_key_status[Input::BTN_RIGHT] ? MouseButtonState_RightButton : 0)
| (_key_status[Input::BTN_MIDDLE] ? MouseButtonState_MiddleButton : 0);
if (ev.absolute_motion()) {
_last_received_motion_event_was_absolute = true; if (mouse_button_bits != old_mouse_button_bits) {
/* transform absolute to relative if guest is so odd */ if (_last_received_motion_event_was_absolute) {
if (!guest_abs && guest_rel) { /* prefer absolute button event */
int const boundary = 20; if (guest_abs)
int rx = ev.ax() - _ax; _vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, mouse_button_bits);
int ry = ev.ay() - _ay; else if (guest_rel)
rx = Genode::min(boundary, Genode::max(-boundary, rx)); _vbox_mouse->PutMouseEvent(0, 0, 0, 0, mouse_button_bits);
ry = Genode::min(boundary, Genode::max(-boundary, ry)); } else {
_vbox_mouse->PutMouseEvent(rx, ry, 0, 0, buttons); /* prefer relative button event */
} else
_vbox_mouse->PutMouseEventAbsolute(ev.ax(), ev.ay(), 0,
0, buttons);
_ax = ev.ax();
_ay = ev.ay();
} else if (ev.relative_motion()) {
_last_received_motion_event_was_absolute = false;
/* prefer relative motion event */
if (guest_rel) if (guest_rel)
_vbox_mouse->PutMouseEvent(ev.rx(), ev.ry(), 0, 0, buttons); _vbox_mouse->PutMouseEvent(0, 0, 0, 0, mouse_button_bits);
else if (guest_abs) { else if (guest_abs)
_ax += ev.rx(); _vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, mouse_button_bits);
_ay += ev.ry();
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
}
}
/* only the buttons changed */
else {
if (_last_received_motion_event_was_absolute) {
/* prefer absolute button event */
if (guest_abs)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
else if (guest_rel)
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, buttons);
} else {
/* prefer relative button event */
if (guest_rel)
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, buttons);
else if (guest_abs)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
}
} }
} }
if (wheel) { ev.handle_absolute_motion([&] (int x, int y) {
_last_received_motion_event_was_absolute = true;
/* transform absolute to relative if guest is so odd */
if (!guest_abs && guest_rel) {
int const boundary = 20;
int rx = x - _ax;
int ry = y - _ay;
rx = Genode::min(boundary, Genode::max(-boundary, rx));
ry = Genode::min(boundary, Genode::max(-boundary, ry));
_vbox_mouse->PutMouseEvent(rx, ry, 0, 0, mouse_button_bits);
} else
_vbox_mouse->PutMouseEventAbsolute(x, y, 0, 0, mouse_button_bits);
_ax = x;
_ay = y;
});
ev.handle_relative_motion([&] (int x, int y) {
_last_received_motion_event_was_absolute = false;
/* prefer relative motion event */
if (guest_rel)
_vbox_mouse->PutMouseEvent(x, y, 0, 0, mouse_button_bits);
else if (guest_abs) {
_ax += x;
_ay += y;
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, mouse_button_bits);
}
});
ev.handle_wheel([&] (int x, int y) {
if (_last_received_motion_event_was_absolute) if (_last_received_motion_event_was_absolute)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, -ev.ry(), -ev.rx(), 0); _vbox_mouse->PutMouseEventAbsolute(_ax, _ay, -y, -x, 0);
else else
_vbox_mouse->PutMouseEvent(0, 0, -ev.ry(), -ev.rx(), 0); _vbox_mouse->PutMouseEvent(0, 0, -y, -x, 0);
} });
ev.handle_touch([&] (Input::Touch_id id, int x, int y) {
if (touch) {
/* if multitouch queue is full - send it */ /* if multitouch queue is full - send it */
if (mt_number >= sizeof(mt_events) / sizeof(mt_events[0])) { if (mt_number >= sizeof(mt_events) / sizeof(mt_events[0])) {
_vbox_mouse->PutEventMultiTouch(mt_number, mt_number, _vbox_mouse->PutEventMultiTouch(mt_number, mt_number,
mt_events, RTTimeMilliTS()); mt_events, RTTimeMilliTS());
mt_number = 0; mt_number = 0;
} }
int x = ev.ax();
int y = ev.ay();
int slot = ev.code();
/* Mouse::putEventMultiTouch drops values of 0 */ /* Mouse::putEventMultiTouch drops values of 0 */
if (x <= 0) x = 1; if (x <= 0) x = 1;
if (y <= 0) y = 1; if (y <= 0) y = 1;
enum MultiTouch { enum { IN_CONTACT = 0x01, IN_RANGE = 0x02 };
None = 0x0,
InContact = 0x01,
InRange = 0x02
};
int status = MultiTouch::InContact | MultiTouch::InRange; uint16_t const s = RT_MAKE_U16(id.value, IN_CONTACT | IN_RANGE);
if (ev.touch_release())
status = MultiTouch::None;
uint16_t const s = RT_MAKE_U16(slot, status);
mt_events[mt_number++] = RT_MAKE_U64_FROM_U16(x, y, s, 0); mt_events[mt_number++] = RT_MAKE_U64_FROM_U16(x, y, s, 0);
} });
ev.handle_touch_release([&] (Input::Touch_id id) {
uint16_t const s = RT_MAKE_U16(id.value, 0);
mt_events[mt_number++] = RT_MAKE_U64_FROM_U16(0, 0, s, 0);
});
}); });
/* if there are elements - send it */ /* if there are elements in multi-touch queue - send it */
if (mt_number) if (mt_number)
_vbox_mouse->PutEventMultiTouch(mt_number, mt_number, mt_events, _vbox_mouse->PutEventMultiTouch(mt_number, mt_number, mt_events,
RTTimeMilliTS()); RTTimeMilliTS());
} }
void GenodeConsole::handle_mode_change() void GenodeConsole::handle_mode_change()

View File

@ -148,18 +148,11 @@ void GenodeConsole::handle_input()
if (!_vbox_keyboard || !_vbox_mouse) if (!_vbox_keyboard || !_vbox_mouse)
return; return;
bool const press = ev.type() == Input::Event::PRESS; auto keyboard_submit = [&] (Input::Keycode key, bool release) {
bool const release = ev.type() == Input::Event::RELEASE;
bool const key = press || release;
bool const motion = ev.type() == Input::Event::MOTION;
bool const wheel = ev.type() == Input::Event::WHEEL;
bool const touch = ev.type() == Input::Event::TOUCH;
if (key) { Scan_code scan_code(key);
Scan_code scan_code(ev.keycode());
unsigned char const release_bit = unsigned char const release_bit = release ? 0x80 : 0;
(ev.type() == Input::Event::RELEASE) ? 0x80 : 0;
if (scan_code.normal()) if (scan_code.normal())
_vbox_keyboard->PutScancode(scan_code.code() | release_bit); _vbox_keyboard->PutScancode(scan_code.code() | release_bit);
@ -168,122 +161,116 @@ void GenodeConsole::handle_input()
_vbox_keyboard->PutScancode(0xe0); _vbox_keyboard->PutScancode(0xe0);
_vbox_keyboard->PutScancode(scan_code.ext() | release_bit); _vbox_keyboard->PutScancode(scan_code.ext() | release_bit);
} }
} };
/* /* obtain bit mask of currently pressed mouse buttons */
* Track press/release status of keys and buttons. Currently, auto curr_mouse_button_bits = [&] () {
* only the mouse-button states are actually used. return (_key_status[Input::BTN_LEFT] ? MouseButtonState_LeftButton : 0)
*/ | (_key_status[Input::BTN_RIGHT] ? MouseButtonState_RightButton : 0)
if (press) | (_key_status[Input::BTN_MIDDLE] ? MouseButtonState_MiddleButton : 0);
_key_status[ev.keycode()] = true; };
if (release) unsigned const old_mouse_button_bits = curr_mouse_button_bits();
_key_status[ev.keycode()] = false;
bool const mouse_button_event = ev.handle_press([&] (Input::Keycode key, Genode::Codepoint) {
key && _mouse_button(ev.keycode()); keyboard_submit(key, false);
_key_status[key] = true;
});
bool const mouse_event = mouse_button_event || motion; ev.handle_release([&] (Input::Keycode key) {
keyboard_submit(key, true);
_key_status[key] = false;
});
if (mouse_event) { unsigned const mouse_button_bits = curr_mouse_button_bits();
unsigned const buttons = (_key_status[Input::BTN_LEFT] ? MouseButtonState_LeftButton : 0)
| (_key_status[Input::BTN_RIGHT] ? MouseButtonState_RightButton : 0)
| (_key_status[Input::BTN_MIDDLE] ? MouseButtonState_MiddleButton : 0);
if (ev.absolute_motion()) {
_last_received_motion_event_was_absolute = true; if (mouse_button_bits != old_mouse_button_bits) {
/* transform absolute to relative if guest is so odd */ if (_last_received_motion_event_was_absolute) {
if (!guest_abs && guest_rel) { /* prefer absolute button event */
int const boundary = 20; if (guest_abs)
int rx = ev.ax() - _ax; _vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, mouse_button_bits);
int ry = ev.ay() - _ay; else if (guest_rel)
rx = Genode::min(boundary, Genode::max(-boundary, rx)); _vbox_mouse->PutMouseEvent(0, 0, 0, 0, mouse_button_bits);
ry = Genode::min(boundary, Genode::max(-boundary, ry)); } else {
_vbox_mouse->PutMouseEvent(rx, ry, 0, 0, buttons); /* prefer relative button event */
} else
_vbox_mouse->PutMouseEventAbsolute(ev.ax(), ev.ay(), 0,
0, buttons);
_ax = ev.ax();
_ay = ev.ay();
} else if (ev.relative_motion()) {
_last_received_motion_event_was_absolute = false;
/* prefer relative motion event */
if (guest_rel) if (guest_rel)
_vbox_mouse->PutMouseEvent(ev.rx(), ev.ry(), 0, 0, buttons); _vbox_mouse->PutMouseEvent(0, 0, 0, 0, mouse_button_bits);
else if (guest_abs) { else if (guest_abs)
_ax += ev.rx(); _vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, mouse_button_bits);
_ay += ev.ry();
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
}
}
/* only the buttons changed */
else {
if (_last_received_motion_event_was_absolute) {
/* prefer absolute button event */
if (guest_abs)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
else if (guest_rel)
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, buttons);
} else {
/* prefer relative button event */
if (guest_rel)
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, buttons);
else if (guest_abs)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
}
} }
} }
if (wheel) { ev.handle_absolute_motion([&] (int x, int y) {
_last_received_motion_event_was_absolute = true;
/* transform absolute to relative if guest is so odd */
if (!guest_abs && guest_rel) {
int const boundary = 20;
int rx = x - _ax;
int ry = y - _ay;
rx = Genode::min(boundary, Genode::max(-boundary, rx));
ry = Genode::min(boundary, Genode::max(-boundary, ry));
_vbox_mouse->PutMouseEvent(rx, ry, 0, 0, mouse_button_bits);
} else
_vbox_mouse->PutMouseEventAbsolute(x, y, 0, 0, mouse_button_bits);
_ax = x;
_ay = y;
});
ev.handle_relative_motion([&] (int x, int y) {
_last_received_motion_event_was_absolute = false;
/* prefer relative motion event */
if (guest_rel)
_vbox_mouse->PutMouseEvent(x, y, 0, 0, mouse_button_bits);
else if (guest_abs) {
_ax += x;
_ay += y;
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, mouse_button_bits);
}
});
ev.handle_wheel([&] (int x, int y) {
if (_last_received_motion_event_was_absolute) if (_last_received_motion_event_was_absolute)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, -ev.ry(), -ev.rx(), 0); _vbox_mouse->PutMouseEventAbsolute(_ax, _ay, -y, -x, 0);
else else
_vbox_mouse->PutMouseEvent(0, 0, -ev.ry(), -ev.rx(), 0); _vbox_mouse->PutMouseEvent(0, 0, -y, -x, 0);
} });
ev.handle_touch([&] (Input::Touch_id id, int x, int y) {
if (touch) {
/* if multitouch queue is full - send it */ /* if multitouch queue is full - send it */
if (mt_number >= sizeof(mt_events) / sizeof(mt_events[0])) { if (mt_number >= sizeof(mt_events) / sizeof(mt_events[0])) {
_vbox_mouse->PutEventMultiTouch(mt_number, mt_number, _vbox_mouse->PutEventMultiTouch(mt_number, mt_number,
mt_events, RTTimeMilliTS()); mt_events, RTTimeMilliTS());
mt_number = 0; mt_number = 0;
} }
int x = ev.ax();
int y = ev.ay();
int slot = ev.code();
/* Mouse::putEventMultiTouch drops values of 0 */ /* Mouse::putEventMultiTouch drops values of 0 */
if (x <= 0) x = 1; if (x <= 0) x = 1;
if (y <= 0) y = 1; if (y <= 0) y = 1;
enum MultiTouch { enum { IN_CONTACT = 0x01, IN_RANGE = 0x02 };
None = 0x0,
InContact = 0x01,
InRange = 0x02
};
int status = MultiTouch::InContact | MultiTouch::InRange; uint16_t const s = RT_MAKE_U16(id.value, IN_CONTACT | IN_RANGE);
if (ev.touch_release())
status = MultiTouch::None;
uint16_t const s = RT_MAKE_U16(slot, status);
mt_events[mt_number++] = RT_MAKE_U64_FROM_U16(x, y, s, 0); mt_events[mt_number++] = RT_MAKE_U64_FROM_U16(x, y, s, 0);
} });
ev.handle_touch_release([&] (Input::Touch_id id) {
uint16_t const s = RT_MAKE_U16(id.value, 0);
mt_events[mt_number++] = RT_MAKE_U64_FROM_U16(0, 0, s, 0);
});
}); });
/* if there are elements - send it */ /* if there are elements in multi-touch queue - send it */
if (mt_number) if (mt_number)
_vbox_mouse->PutEventMultiTouch(mt_number, mt_number, mt_events, _vbox_mouse->PutEventMultiTouch(mt_number, mt_number, mt_events,
RTTimeMilliTS()); RTTimeMilliTS());
} }
void GenodeConsole::handle_mode_change() void GenodeConsole::handle_mode_change()