genode/repos/ports/src/virtualbox5/frontend/console.h

274 lines
7.5 KiB
C++

/*
* \brief Console implementation of VirtualBox for Genode
* \author Alexander Boettcher
* \author Norman Feske
* \date 2013-10-16
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/log.h>
#include <base/attached_dataspace.h>
#include <base/attached_rom_dataspace.h>
#include <input/event.h>
#include <input/keycodes.h>
#include <input_session/connection.h>
#define Framebuffer Fb_Genode
#include <nitpicker_session/connection.h>
#undef Framebuffer
#include <os/reporter.h>
#include <report_session/connection.h>
#include <timer_session/connection.h>
/* included from os/src/drivers/input/spec/ps2 */
#include <scan_code_set_1.h>
/* repos/ports includes */
#include <pointer/shape_report.h>
#include "../vmm.h"
/* VirtualBox includes */
#include "ConsoleImpl.h"
class Scan_code
{
private:
class Converter
{
public:
unsigned char scan_code [Input::KEY_UNKNOWN];
unsigned char scan_code_ext [Input::KEY_UNKNOWN];
private:
unsigned char _search_scan_code(Input::Keycode keycode)
{
for (unsigned i = 0; i < SCAN_CODE_SET_1_NUM_KEYS; i++)
if (scan_code_set_1[i] == keycode)
return i;
return 0;
}
unsigned char _search_scan_code_ext(Input::Keycode keycode)
{
for (unsigned i = 0; i < SCAN_CODE_SET_1_NUM_KEYS; i++)
if (scan_code_set_1_0xe0[i] == keycode)
return i;
return 0;
}
public:
Converter()
{
init_scan_code_set_1_0xe0();
for (unsigned i = 0; i < Input::KEY_UNKNOWN; i++) {
scan_code [i] = _search_scan_code ((Input::Keycode)i);
scan_code_ext [i] = _search_scan_code_ext((Input::Keycode)i);
}
}
};
static Converter &converter()
{
static Converter inst;
return inst;
}
Input::Keycode _keycode;
public:
Scan_code(Input::Keycode keycode) : _keycode(keycode) { }
bool normal() const { return converter().scan_code[_keycode]; }
bool valid() const
{
return normal() || ext();
}
unsigned char code() const
{
return converter().scan_code[_keycode];
}
unsigned char ext() const
{
return converter().scan_code_ext[_keycode];
}
};
class GenodeConsole : public Console {
private:
Nitpicker::Connection _nitpicker;
Input::Session_client &_input;
unsigned _ax, _ay;
bool _last_received_motion_event_was_absolute;
Report::Connection _shape_report_connection;
Genode::Attached_dataspace _shape_report_ds;
Genode::Constructible<Genode::Attached_rom_dataspace> _caps_lock;
Pointer::Shape_report *_shape_report;
Genode::Reporter *_clipboard_reporter;
Genode::Attached_rom_dataspace *_clipboard_rom;
IKeyboard *_vbox_keyboard;
IMouse *_vbox_mouse;
Genode::Signal_handler<GenodeConsole> _input_signal_dispatcher;
Genode::Signal_handler<GenodeConsole> _mode_change_signal_dispatcher;
Genode::Signal_handler<GenodeConsole> _clipboard_signal_dispatcher;
Genode::Signal_handler<GenodeConsole> _input_sticky_keys_dispatcher;
bool _key_status[Input::KEY_MAX + 1];
static bool _mouse_button(Input::Keycode keycode)
{
return keycode == Input::BTN_LEFT
|| keycode == Input::BTN_RIGHT
|| keycode == Input::BTN_MIDDLE;
}
void _handle_input();
void _handle_mode_change();
void _handle_cb_rom_change();
void _handle_sticky_keys();
public:
GenodeConsole()
:
Console(),
_nitpicker(genode_env()),
_input(*_nitpicker.input()),
_ax(0), _ay(0),
_last_received_motion_event_was_absolute(false),
_shape_report_connection(genode_env(), "shape",
sizeof(Pointer::Shape_report)),
_shape_report_ds(genode_env().rm(), _shape_report_connection.dataspace()),
_shape_report(_shape_report_ds.local_addr<Pointer::Shape_report>()),
_clipboard_reporter(nullptr),
_clipboard_rom(nullptr),
_vbox_keyboard(0),
_vbox_mouse(0),
_input_signal_dispatcher(genode_env().ep(), *this, &GenodeConsole::handle_input),
_mode_change_signal_dispatcher(genode_env().ep(), *this, &GenodeConsole::handle_mode_change),
_clipboard_signal_dispatcher(genode_env().ep(), *this, &GenodeConsole::handle_cb_rom_change),
_input_sticky_keys_dispatcher(genode_env().ep(), *this, &GenodeConsole::handle_sticky_keys)
{
for (unsigned i = 0; i <= Input::KEY_MAX; i++)
_key_status[i] = 0;
_input.sigh(_input_signal_dispatcher);
Genode::Attached_rom_dataspace config(genode_env(), "config");
/* by default we take the capslock key from the input stream */
Genode::String<10> capslock("input");
if (config.xml().attribute_value("capslock", capslock) == "ROM") {
_caps_lock.construct(genode_env(), "capslock");
_caps_lock->sigh(_input_sticky_keys_dispatcher);
}
}
Nitpicker::Connection &nitpicker() { return _nitpicker; }
void init_clipboard();
void init_backends(IKeyboard * gKeyboard, IMouse * gMouse);
void i_onMouseCapabilityChange(BOOL supportsAbsolute,
BOOL supportsRelative, BOOL supportsMT,
BOOL needsHostCursor);
void i_onMousePointerShapeChange(bool fVisible, bool fAlpha,
uint32_t xHot, uint32_t yHot,
uint32_t width, uint32_t height,
const uint8_t *pu8Shape,
uint32_t cbShape)
{
if (fVisible && ((width == 0) || (height == 0)))
return;
_shape_report->visible = fVisible;
_shape_report->x_hot = xHot;
_shape_report->y_hot = yHot;
_shape_report->width = width;
_shape_report->height = height;
unsigned int and_mask_size = (_shape_report->width + 7) / 8 *
_shape_report->height;
const unsigned char *and_mask = pu8Shape;
const unsigned char *shape = and_mask + ((and_mask_size + 3) & ~3);
size_t shape_size = cbShape - (shape - and_mask);
if (shape_size > Pointer::MAX_SHAPE_SIZE) {
Genode::error(__func__, ": shape data buffer is too small for ",
shape_size, " bytes");
return;
}
/* convert the shape data from BGRA encoding to RGBA encoding */
unsigned char const *bgra_shape = shape;
unsigned char *rgba_shape = _shape_report->shape;
for (unsigned int y = 0; y < _shape_report->height; y++) {
unsigned char const *bgra_line = &bgra_shape[y * _shape_report->width * 4];
unsigned char *rgba_line = &rgba_shape[y * _shape_report->width * 4];
for (unsigned int i = 0; i < _shape_report->width * 4; i += 4) {
rgba_line[i + 0] = bgra_line[i + 2];
rgba_line[i + 1] = bgra_line[i + 1];
rgba_line[i + 2] = bgra_line[i + 0];
rgba_line[i + 3] = bgra_line[i + 3];
}
}
if (fVisible && !fAlpha) {
for (unsigned int i = 0; i < width * height; i++) {
unsigned int *color =
&((unsigned int*)_shape_report->shape)[i];
/* heuristic from VBoxSDL.cpp */
if (and_mask[i / 8] & (1 << (7 - (i % 8)))) {
if (*color & 0x00ffffff)
*color = 0xff000000;
else
*color = 0x00000000;
} else
*color |= 0xff000000;
}
}
_shape_report_connection.submit(sizeof(Pointer::Shape_report));
}
void update_video_mode();
void handle_input();
void handle_mode_change();
void handle_cb_rom_change();
void handle_sticky_keys();
};