Refactor terminal for intrinsic Unicode support
Refactor the graphical terminal server to internally represent characters as 16-bit codepoints and handle the duplex terminal stream as UTF-8. - Make the Codepoint class printable to the Output interface - Decode data received at the Terminal session from UTF-8 to a 16-bit character - Pass 16-bit characters through terminal decoder and char-cell arrays - Send Unicode through terminal session in a burst of UTF-8 bytes Fix #3148
This commit is contained in:
parent
0c24e1efdc
commit
22327b43ae
|
@ -1,9 +1,9 @@
|
||||||
create_boot_directory
|
create_boot_directory
|
||||||
|
|
||||||
import_from_depot genodelabs/src/[base_src] \
|
import_from_depot [depot_user]/src/[base_src] \
|
||||||
genodelabs/pkg/[drivers_interactive_pkg] \
|
[depot_user]/pkg/[drivers_interactive_pkg] \
|
||||||
genodelabs/pkg/terminal \
|
[depot_user]/pkg/terminal \
|
||||||
genodelabs/src/init
|
[depot_user]/src/init
|
||||||
|
|
||||||
install_config {
|
install_config {
|
||||||
<config>
|
<config>
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
create_boot_directory
|
create_boot_directory
|
||||||
|
|
||||||
import_from_depot genodelabs/src/[base_src] \
|
import_from_depot [depot_user]/src/[base_src] \
|
||||||
genodelabs/pkg/[drivers_interactive_pkg] \
|
[depot_user]/pkg/[drivers_interactive_pkg] \
|
||||||
genodelabs/pkg/terminal \
|
[depot_user]/pkg/terminal \
|
||||||
genodelabs/src/nitpicker \
|
[depot_user]/src/nitpicker \
|
||||||
genodelabs/src/nit_fb \
|
[depot_user]/src/nit_fb \
|
||||||
genodelabs/src/demo \
|
[depot_user]/src/demo \
|
||||||
genodelabs/src/init
|
[depot_user]/src/init
|
||||||
|
|
||||||
install_config {
|
install_config {
|
||||||
<config>
|
<config>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2011-2017 Genode Labs GmbH
|
* Copyright (C) 2011-2019 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
@ -254,29 +254,6 @@ void Terminal::Main::_handle_input()
|
||||||
|
|
||||||
event.handle_press([&] (Input::Keycode, Codepoint codepoint) {
|
event.handle_press([&] (Input::Keycode, Codepoint codepoint) {
|
||||||
|
|
||||||
struct Utf8 { char b0, b1, b2, b3, b4; };
|
|
||||||
|
|
||||||
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 {
|
||||||
CODEPOINT_UP = 0xf700, CODEPOINT_DOWN = 0xf701,
|
CODEPOINT_UP = 0xf700, CODEPOINT_DOWN = 0xf701,
|
||||||
|
@ -321,7 +298,7 @@ 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.b0);
|
_read_buffer.add(codepoint);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Genode Labs GmbH
|
* Copyright (C) 2018-2019 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
@ -105,7 +105,8 @@ class Terminal::Session_component : public Rpc_object<Session, Session_component
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
for (Utf8_ptr utf8(src); utf8.complete() && i < max; ) {
|
for (Utf8_ptr utf8(src); utf8.complete() && i < max; ) {
|
||||||
|
|
||||||
_character_consumer.consume_character(utf8.codepoint().value);
|
_character_consumer.consume_character(
|
||||||
|
Terminal::Character(utf8.codepoint()));
|
||||||
|
|
||||||
i += utf8.length();
|
i += utf8.length();
|
||||||
if (i >= max)
|
if (i >= max)
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2011-2018 Genode Labs GmbH
|
* Copyright (C) 2011-2019 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
@ -198,14 +198,8 @@ class Terminal::Text_screen_surface
|
||||||
for (unsigned column = 0; column < _cell_array.num_cols(); column++) {
|
for (unsigned column = 0; column < _cell_array.num_cols(); column++) {
|
||||||
|
|
||||||
Char_cell cell = _cell_array.get_cell(column, line);
|
Char_cell cell = _cell_array.get_cell(column, line);
|
||||||
unsigned char ascii = cell.ascii;
|
|
||||||
|
|
||||||
if (ascii == 0)
|
_font.apply_glyph(cell.codepoint(), [&] (Glyph_painter::Glyph const &glyph) {
|
||||||
ascii = ' ';
|
|
||||||
|
|
||||||
Text_painter::Codepoint const c { ascii };
|
|
||||||
|
|
||||||
_font.apply_glyph(c, [&] (Glyph_painter::Glyph const &glyph) {
|
|
||||||
|
|
||||||
Color_palette::Highlighted const highlighted { cell.highlight() };
|
Color_palette::Highlighted const highlighted { cell.highlight() };
|
||||||
Color_palette::Inverse const inverse { cell.inverse() };
|
Color_palette::Inverse const inverse { cell.inverse() };
|
||||||
|
@ -274,7 +268,7 @@ class Terminal::Text_screen_surface
|
||||||
void apply_character(Character c)
|
void apply_character(Character c)
|
||||||
{
|
{
|
||||||
/* submit character to sequence decoder */
|
/* submit character to sequence decoder */
|
||||||
_decoder.insert(c.c);
|
_decoder.insert(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void import(Snapshot const &snapshot)
|
void import(Snapshot const &snapshot)
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Genode Labs GmbH
|
* Copyright (C) 2018-2019 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
|
|
@ -47,9 +47,9 @@ static void convert_char_array_to_window(Cell_array<Char_cell> *cell_array,
|
||||||
for (unsigned column = 0; column < cell_array->num_cols(); column++) {
|
for (unsigned column = 0; column < cell_array->num_cols(); column++) {
|
||||||
|
|
||||||
Char_cell cell = cell_array->get_cell(column, line);
|
Char_cell cell = cell_array->get_cell(column, line);
|
||||||
unsigned char ascii = cell.ascii;
|
unsigned char ascii = cell.codepoint().value;
|
||||||
|
|
||||||
if (ascii == 0) {
|
if (ascii == 0 || ascii & 0x80) {
|
||||||
window.print_char(' ', false, false);
|
window.print_char(' ', false, false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -301,10 +301,12 @@ class Terminal::Session_component : public Genode::Rpc_object<Session, Session_c
|
||||||
{
|
{
|
||||||
unsigned char *src = _io_buffer.local_addr<unsigned char>();
|
unsigned char *src = _io_buffer.local_addr<unsigned char>();
|
||||||
|
|
||||||
|
Terminal::Character character;
|
||||||
for (unsigned i = 0; i < num_bytes; i++) {
|
for (unsigned i = 0; i < num_bytes; i++) {
|
||||||
|
|
||||||
/* submit character to sequence decoder */
|
/* submit character to sequence decoder */
|
||||||
_decoder.insert(src[i]);
|
character.value = src[i];
|
||||||
|
_decoder.insert(character);
|
||||||
}
|
}
|
||||||
|
|
||||||
return num_bytes;
|
return num_bytes;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
* Copyright (C) 2013-2019 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
@ -20,8 +20,9 @@
|
||||||
|
|
||||||
struct Char_cell
|
struct Char_cell
|
||||||
{
|
{
|
||||||
|
Genode::uint16_t value { ' ' };
|
||||||
|
|
||||||
unsigned char attr;
|
unsigned char attr;
|
||||||
unsigned char ascii;
|
|
||||||
unsigned char color;
|
unsigned char color;
|
||||||
|
|
||||||
enum { ATTR_COLIDX_MASK = 0x07U,
|
enum { ATTR_COLIDX_MASK = 0x07U,
|
||||||
|
@ -31,14 +32,14 @@ struct Char_cell
|
||||||
|
|
||||||
enum { COLOR_MASK = 0x3f }; /* 111111 */
|
enum { COLOR_MASK = 0x3f }; /* 111111 */
|
||||||
|
|
||||||
Char_cell() : attr(0), ascii(0), color(0) { }
|
Char_cell() : attr(0), color(0) { }
|
||||||
|
|
||||||
Char_cell(unsigned char c, Font_face f,
|
Char_cell(Terminal::Character c, Font_face f,
|
||||||
int colidx, bool inv, bool highlight)
|
int colidx, bool inv, bool highlight)
|
||||||
:
|
:
|
||||||
|
value(c.value),
|
||||||
attr(f.attr_bits() | (inv ? ATTR_INVERSE : 0)
|
attr(f.attr_bits() | (inv ? ATTR_INVERSE : 0)
|
||||||
| (highlight ? ATTR_HIGHLIGHT : 0)),
|
| (highlight ? ATTR_HIGHLIGHT : 0)),
|
||||||
ascii(c),
|
|
||||||
color(colidx & COLOR_MASK)
|
color(colidx & COLOR_MASK)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
@ -56,6 +57,9 @@ struct Char_cell
|
||||||
void clear_cursor() { attr &= ~ATTR_CURSOR; }
|
void clear_cursor() { attr &= ~ATTR_CURSOR; }
|
||||||
|
|
||||||
bool has_cursor() const { return attr & ATTR_CURSOR; }
|
bool has_cursor() const { return attr & ATTR_CURSOR; }
|
||||||
|
|
||||||
|
Terminal::Codepoint codepoint() const {
|
||||||
|
return Terminal::Codepoint { value }; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -184,7 +188,7 @@ class Char_cell_array_character_screen : public Terminal::Character_screen
|
||||||
if (_irm == INSERT)
|
if (_irm == INSERT)
|
||||||
_missing("insert mode");
|
_missing("insert mode");
|
||||||
|
|
||||||
switch (c.ascii()) {
|
switch (c.value) {
|
||||||
|
|
||||||
case '\n': /* 10 */
|
case '\n': /* 10 */
|
||||||
_new_line();
|
_new_line();
|
||||||
|
@ -215,10 +219,10 @@ class Char_cell_array_character_screen : public Terminal::Character_screen
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (c.ascii() > 0x1f) {
|
if (c.value > 0x1f) {
|
||||||
Cursor_guard guard(*this);
|
Cursor_guard guard(*this);
|
||||||
_char_cell_array.set_cell(_cursor_pos.x, _cursor_pos.y,
|
_char_cell_array.set_cell(_cursor_pos.x, _cursor_pos.y,
|
||||||
Char_cell(c.ascii(), Font_face::REGULAR,
|
Char_cell(c, Font_face::REGULAR,
|
||||||
_color_index, _inverse, _highlight));
|
_color_index, _inverse, _highlight));
|
||||||
_cursor_pos.x++;
|
_cursor_pos.x++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2011-2017 Genode Labs GmbH
|
* Copyright (C) 2011-2019 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* \brief Escape-sequence decoder
|
* \brief Escape-sequence decoder
|
||||||
* \author Norman Feske
|
* \author Norman Feske
|
||||||
|
* \author Emery Hemingway
|
||||||
* \date 2011-06-06
|
* \date 2011-06-06
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2011-2017 Genode Labs GmbH
|
* Copyright (C) 2011-2019 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
@ -452,8 +453,10 @@ class Terminal::Decoder
|
||||||
|
|
||||||
Decoder(Character_screen &screen) : _screen(screen) { }
|
Decoder(Character_screen &screen) : _screen(screen) { }
|
||||||
|
|
||||||
void insert(unsigned char c)
|
void insert(Character character)
|
||||||
{
|
{
|
||||||
|
auto const c = character.value;
|
||||||
|
|
||||||
switch (_state) {
|
switch (_state) {
|
||||||
|
|
||||||
case STATE_IDLE:
|
case STATE_IDLE:
|
||||||
|
@ -467,7 +470,7 @@ class Terminal::Decoder
|
||||||
/* handle special characters */
|
/* handle special characters */
|
||||||
|
|
||||||
/* handle normal characters */
|
/* handle normal characters */
|
||||||
_screen.output(c);
|
_screen.output(character);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2011-2017 Genode Labs GmbH
|
* Copyright (C) 2011-2019 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
@ -15,6 +15,7 @@
|
||||||
#define _TERMINAL__READ_BUFFER_H_
|
#define _TERMINAL__READ_BUFFER_H_
|
||||||
|
|
||||||
#include <os/ring_buffer.h>
|
#include <os/ring_buffer.h>
|
||||||
|
#include <util/utf8.h>
|
||||||
#include <base/signal.h>
|
#include <base/signal.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,6 +51,19 @@ class Terminal::Read_buffer : public Genode::Ring_buffer<unsigned char, READ_BUF
|
||||||
Genode::Signal_transmitter(_sigh_cap).submit();
|
Genode::Signal_transmitter(_sigh_cap).submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add(Codepoint code)
|
||||||
|
{
|
||||||
|
/* send Unicode in a burst of UTF-8 */
|
||||||
|
Genode::String<5> utf8(code);
|
||||||
|
char const *str = utf8.string();
|
||||||
|
|
||||||
|
while (*str)
|
||||||
|
Genode::Ring_buffer<unsigned char, READ_BUFFER_SIZE>::add(*str++);
|
||||||
|
|
||||||
|
if (_sigh_cap.valid())
|
||||||
|
Genode::Signal_transmitter(_sigh_cap).submit();
|
||||||
|
}
|
||||||
|
|
||||||
void add(char const *str)
|
void add(char const *str)
|
||||||
{
|
{
|
||||||
while (*str)
|
while (*str)
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
#define _TERMINAL__TYPES_H_
|
#define _TERMINAL__TYPES_H_
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
|
#include <util/utf8.h>
|
||||||
#include <util/interface.h>
|
#include <util/interface.h>
|
||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
|
using Genode::Codepoint;
|
||||||
struct Character;
|
struct Character;
|
||||||
struct Boundary;
|
struct Boundary;
|
||||||
struct Offset;
|
struct Offset;
|
||||||
|
@ -34,14 +35,13 @@ namespace Terminal {
|
||||||
*/
|
*/
|
||||||
struct Terminal::Character
|
struct Terminal::Character
|
||||||
{
|
{
|
||||||
unsigned char c;
|
Genode::uint16_t value;
|
||||||
|
|
||||||
Character() : c(0) { }
|
Character() : value(0) { }
|
||||||
Character(unsigned char c) : c(c) { }
|
Character(Codepoint cp)
|
||||||
|
: value(cp.value < 1<<16 ? cp.value : 0) { }
|
||||||
|
|
||||||
bool valid() const { return c != 0; }
|
bool valid() const { return value != 0; }
|
||||||
|
|
||||||
unsigned char ascii() const { return c; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Genode Labs GmbH
|
* Copyright (C) 2018-2019 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
@ -14,6 +14,7 @@
|
||||||
#ifndef _INCLUDE__OS__UTIL__UTF8_H_
|
#ifndef _INCLUDE__OS__UTIL__UTF8_H_
|
||||||
#define _INCLUDE__OS__UTIL__UTF8_H_
|
#define _INCLUDE__OS__UTIL__UTF8_H_
|
||||||
|
|
||||||
|
#include <base/output.h>
|
||||||
#include <base/stdint.h>
|
#include <base/stdint.h>
|
||||||
|
|
||||||
namespace Genode {
|
namespace Genode {
|
||||||
|
@ -29,6 +30,32 @@ struct Genode::Codepoint
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
|
|
||||||
bool valid() const { return value != INVALID; }
|
bool valid() const { return value != INVALID; }
|
||||||
|
|
||||||
|
void print(Output &output) const
|
||||||
|
{
|
||||||
|
/* extract 'n' bits 'at' bit position of value */
|
||||||
|
auto bits = [&] (unsigned at, unsigned n) {
|
||||||
|
return (char)((value >> at) & ((1 << n) - 1)); };
|
||||||
|
|
||||||
|
if (value < 1<<7) {
|
||||||
|
output.out_char(bits( 0, 7));
|
||||||
|
} else
|
||||||
|
if (value < 1<<11) {
|
||||||
|
output.out_char(bits( 6, 5) | 0xc0);
|
||||||
|
output.out_char(bits( 0, 6) | 0x80);
|
||||||
|
} else
|
||||||
|
if (value < 1<<16) {
|
||||||
|
output.out_char(bits(12, 4) | 0xe0);
|
||||||
|
output.out_char(bits( 6, 6) | 0x80);
|
||||||
|
output.out_char(bits( 0, 6) | 0x80);
|
||||||
|
} else
|
||||||
|
if (value < 0x11<<16) {
|
||||||
|
output.out_char(bits(18, 3) | 0xf0);
|
||||||
|
output.out_char(bits(12, 6) | 0x80);
|
||||||
|
output.out_char(bits( 6, 6) | 0x80);
|
||||||
|
output.out_char(bits( 0, 6) | 0x80);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user