Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

2759 lines (2492 sloc) 72.861 kb
/*
* QEMU graphical console
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "console.h"
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#include <locale.h>
#include <wchar.h>
#include "debug.h"
#include "consmap.h"
#define DEFAULT_BACKSCROLL (512)
#define MAX_CONSOLES 12
#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
/* fonts */
#define G0 0
#define G1 1
int insertmode = 0;
typedef struct TextAttributes {
uint8_t fgcol:4;
uint8_t bgcol:4;
uint8_t bold:1;
uint8_t uline:1;
uint8_t blink:1;
uint8_t invers:1;
uint8_t unvisible:1;
uint8_t used:1;
uint8_t utf:1;
uint8_t font:1; /* 0 or 1 */
uint8_t codec[2]; /* 0-3 translation table per font */
} TextAttributes;
typedef struct CellAttributes {
uint8_t highlit:1;
uint8_t wrapped:1;
uint8_t columns:3;
uint8_t spanned:1;
} CellAttributes;
typedef struct TextCell {
uint8_t ch;
TextAttributes t_attrib;
CellAttributes c_attrib;
} TextCell;
#define MAX_ESC_PARAMS 16
#define MAX_PALETTE_PARAMS 7
enum TTYState {
TTY_STATE_NORM,
TTY_STATE_ESC,
TTY_STATE_PERCENT,
TTY_STATE_G0,
TTY_STATE_G1,
TTY_STATE_CSI,
TTY_STATE_NONSTD,
TTY_STATE_PALETTE
/*
XXX to be done
TTY_STATE_HASH,
TTY_STATE_SQUARE,
TTY_STATE_GETPARS,
TTY_STATE_GOTPARS,
*/
};
struct stream_chunk
{
int offset;
int len;
struct stream_chunk *next;
char data[];
};
struct chunked_stream {
int fd;
void *opaque;
struct stream_chunk *chunk;
struct stream_chunk **chunk_tail;
};
void
write_or_chunk(struct chunked_stream *s, uint8_t *buf, int len)
{
int done;
struct stream_chunk *chunk;
while (s->chunk) {
done = write(s->fd, s->chunk->data + s->chunk->offset,
s->chunk->len - s->chunk->offset);
s->chunk->offset += done;
if (s->chunk->offset == s->chunk->len) {
s->chunk = s->chunk->next;
if (s->chunk == NULL)
s->chunk_tail = &s->chunk;
} else
break;
}
if (s->chunk == NULL) {
done = write(s->fd, buf, len);
if (done == len)
return;
}
chunk = malloc(sizeof(struct stream_chunk) + len - done);
if (chunk == NULL)
return; /* XXX raise error */
chunk->next = NULL;
chunk->offset = 0;
chunk->len = len - done;
memcpy(chunk->data, buf + done, len - done);
*s->chunk_tail = chunk;
s->chunk_tail = &chunk->next;
}
struct selection{
int startx, starty;
int endx, endy;
};
/* ??? This is mis-named.
It is used for both text and graphical consoles. */
struct TextConsole {
int text_console; /* true if text console */
DisplayState *ds;
/* Graphic console state. */
/* width and height in pixels of "frame"/display */
int g_width, g_height;
/* width and height in char cells of "frame"/display*/
int width, height;
/* height, including history currently used,
This should go beyond total_height-heigth */
int backscroll;
/* maximum possible height (backscroll)*/
int total_height;
/* current cursor position */
int x, y;
/* saved cursor position */
int saved_x, saved_y;
/* boolean, selfexplanatory */
char cursor_visible;
/* screen's 1st line (the top line)*/
int y_base;
/* this is ofset that is substracted from y_base
and points to currently displayed screen */
int y_scroll;
/* scroll region */
int sr_top, sr_bottom;
/* self explanatory */
char autowrap;
char wrapped;
int insert_mode;
int cursorkey_mode;
/* display control chars */
char display_ctrl;
/* toggle high bit */
char toggle_meta;
/* orgin mode, not used currently - only set */
char origin_mode;
/* default text attributes */
TextAttributes t_attrib_default;
/* currently active text attributes */
TextAttributes t_attrib;
/* currently saved text attributes */
TextAttributes saved_t_attrib;
/* the actual content */
TextCell *cells;
/* default text attributes */
CellAttributes c_attrib_default;
enum TTYState state;
int esc_params[MAX_ESC_PARAMS];
int nb_esc_params;
int has_esc_param;
int has_qmark;
struct chunked_stream input_stream;
/* first one for current selection, second one for old */
struct selection selections[2];
int selecting;
/* mouse position */
int mouse_x, mouse_y;
/* unicode bits (state of unicode input) */
int unicodeIndex;
char unicodeData[7];
int unicodeLength;
uint8_t palette_params[MAX_PALETTE_PARAMS];
uint8_t nb_palette_params;
#if 0
/* kbd read handler */
IOCanRWHandler *fd_can_read;
IOReadHandler *fd_read;
void *fd_opaque;
/* fifo for key pressed */
QEMUFIFO out_fifo;
uint8_t out_fifo_buf[16];
QEMUTimer *kbd_timer;
#endif
};
typedef struct TextConsole TextConsole;
static TextConsole *active_console;
static TextConsole *consoles[MAX_CONSOLES];
static int nb_consoles = 0;
void set_color_table(DisplayState *ds);
#define clip_y(s, v) { \
if ((s)->v < 0) \
(s)->v = 0; \
if ((s)->v >= (s)->height) \
(s)->v = (s)->height - 1; \
}
#define clip_x(s, v) { \
if ((s)->v < 0) \
(s)->v = 0; \
if ((s)->v >= (s)->width) \
(s)->v = (s)->width - 1; \
}
#define clip_xy(s,x,y) {clip_x(s,x);clip_y(s,y);}
/* convert a RGBA color to a color index usable in graphic primitives */
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
{
unsigned int r, g, b, color;
switch(ds->depth) {
case 8:
r = (rgba >> 16) & 0xff;
g = (rgba >> 8) & 0xff;
b = (rgba) & 0xff;
color = ((r >> 5) << 5 | (g >> 5) << 2 | (b >> 6));
break;
case 15:
r = (rgba >> 16) & 0xff;
g = (rgba >> 8) & 0xff;
b = (rgba) & 0xff;
color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
break;
case 16:
r = (rgba >> 16) & 0xff;
g = (rgba >> 8) & 0xff;
b = (rgba) & 0xff;
color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
break;
case 32:
default:
color = rgba;
break;
}
return color;
}
static void vga_fill_rect (DisplayState *ds,
int posx, int posy, int width, int height, uint32_t color)
{
uint8_t *d, *d1;
int x, y, bpp;
bpp = (ds->depth + 7) >> 3;
d1 = ds->data +
ds->linesize * posy + bpp * posx;
for (y = 0; y < height; y++) {
d = d1;
switch(bpp) {
case 1:
memset(d,color,width);
d+=width;
break;
case 2:
for (x = 0; x < width; x++) {
*((uint16_t *)d) = color;
d += bpp;
}
break;
case 4:
for (x = 0; x < width; x++) {
*((uint32_t *)d) = color;
d += bpp;
}
break;
}
d1 += ds->linesize;
}
}
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
{
const uint8_t *s;
uint8_t *d;
int wb, y, bpp;
bpp = (ds->depth + 7) >> 3;
wb = w * bpp;
if (yd <= ys) {
s = ds->data +
ds->linesize * ys + bpp * xs;
d = ds->data +
ds->linesize * yd + bpp * xd;
for (y = 0; y < h; y++) {
memmove(d, s, wb);
d += ds->linesize;
s += ds->linesize;
}
} else {
s = ds->data +
ds->linesize * (ys + h - 1) + bpp * xs;
d = ds->data +
ds->linesize * (yd + h - 1) + bpp * xd;
for (y = 0; y < h; y++) {
memmove(d, s, wb);
d -= ds->linesize;
s -= ds->linesize;
}
}
}
/***********************************************************/
/* basic char display */
#define FONT_HEIGHT 16
#define FONT_WIDTH 8
#include "vgafont.h"
#include "graphfont.h"
#define cbswap_32(__x) \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
#ifdef WORDS_BIGENDIAN
#define PAT(x) x
#else
#define PAT(x) cbswap_32(x)
#endif
static const uint32_t dmask16[16] = {
PAT(0x00000000),
PAT(0x000000ff),
PAT(0x0000ff00),
PAT(0x0000ffff),
PAT(0x00ff0000),
PAT(0x00ff00ff),
PAT(0x00ffff00),
PAT(0x00ffffff),
PAT(0xff000000),
PAT(0xff0000ff),
PAT(0xff00ff00),
PAT(0xff00ffff),
PAT(0xffff0000),
PAT(0xffff00ff),
PAT(0xffffff00),
PAT(0xffffffff),
};
static const uint32_t dmask4[4] = {
PAT(0x00000000),
PAT(0x0000ffff),
PAT(0xffff0000),
PAT(0xffffffff),
};
static uint32_t color_table[2][8];
enum color_names {
COLOR_BLACK = 0,
COLOR_RED = 1,
COLOR_GREEN = 2,
COLOR_BROWN = 3,
COLOR_BLUE = 4,
COLOR_MAGENTA = 5,
COLOR_CYAN = 6,
COLOR_WHITE = 7
};
static const uint32_t color_table_rgb[2][8] = {
{ /* dark */
QEMU_RGB(0x00, 0x00, 0x00), /* black */
QEMU_RGB(0xc0, 0x00, 0x00), /* red */
QEMU_RGB(0x00, 0xc0, 0x00), /* green */
QEMU_RGB(0xb2, 0x68, 0x18), /* brown */
QEMU_RGB(0x00, 0x00, 0xc0), /* blue */
QEMU_RGB(0xc0, 0x00, 0xc0), /* magenta */
QEMU_RGB(0x00, 0xc0, 0xc0), /* cyan */
QEMU_RGB(0xc0, 0xc0, 0xc0), /* white */
},
{ /* bright */
QEMU_RGB(0x00, 0x00, 0x00), /* black */
QEMU_RGB(0xff, 0x00, 0x00), /* red */
QEMU_RGB(0x00, 0xff, 0x00), /* green */
QEMU_RGB(0xb2, 0x68, 0x18), /* brown */
QEMU_RGB(0x00, 0x00, 0xff), /* blue */
QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
QEMU_RGB(0xff, 0xff, 0xff), /* white */
}
};
#define UTFVAL(B) (consmap[curf][B]&0xffff)
/* simplest binary search */
static int get_glyphcode(TextConsole *s, int chart)
{
int low = 0, high = 255, mid;
int h=0, o='?';
int curf = s->t_attrib.codec[s->t_attrib.font];
/* there is no point in transcribing latin1 char */
if (curf == MAPLAT1) {
if (chart <= 0x7f)
return chart;
else
curf = MAPGRAF;
}
if (chart > UTFVAL(high) || chart < UTFVAL(low))
return o;
while(low <= high) {
h++;
mid = (low + high) / 2;
if (UTFVAL(mid) > chart)
high = mid - 1;
else
if (UTFVAL(mid) < chart)
low = mid + 1;
else {
o = (consmap[curf][mid]>>16)&0xff;
break;
}
}
dprintf("utf8: %x to: %x, lookups: %d\n", chart, o, h);
return o;
}
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
{
switch(ds->depth) {
case 8:
col |= col << 8;
col |= col << 16;
break;
case 15:
case 16:
col |= col << 16;
break;
default:
break;
}
return col;
}
static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
{
if (!do_log)
return;
if (t_attrib->bold) {
dprintf("b");
} else {
dprintf(" ");
}
if (t_attrib->uline) {
dprintf("u");
} else {
dprintf(" ");
}
if (t_attrib->blink) {
dprintf("l");
} else {
dprintf(" ");
}
if (t_attrib->invers) {
dprintf("i");
} else {
dprintf(" ");
}
if (t_attrib->unvisible) {
dprintf("n");
} else {
dprintf(" ");
}
dprintf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
}
/* does a framebuffer scrolling by N lines */
static void vga_scroll(TextConsole *s, int n)
{
int h;
h = s->g_height-(abs(n)*FONT_HEIGHT);
if (n>0) { // up
vga_bitblt(s->ds, 0, n*FONT_HEIGHT, 0, 0, s->g_width, h );
vga_fill_rect(s->ds, 0, h, s->g_width, (abs(n)*FONT_HEIGHT), s->t_attrib.bgcol);
}
else { // down
vga_bitblt(s->ds, 0, 0, 0, -n*FONT_HEIGHT, s->g_width, h );
vga_fill_rect(s->ds, 0, 0, s->g_width, (abs(n)*FONT_HEIGHT), s->t_attrib.bgcol);
}
}
static void vga_putcharxy(TextConsole *s, int x, int y, int ch,
TextAttributes *t_attrib, CellAttributes *c_attrib)
{
uint8_t *d;
const uint8_t *font_ptr;
unsigned int font_data, linesize, xorcol, bpp;
int i;
unsigned int fgcol, bgcol;
DisplayState *ds = s->ds;
// dprintf("x: %2i y: %2i", x, y);
console_print_text_attributes(t_attrib, ch);
// dprintf("font:%d\n", t_attrib->font);
if (t_attrib->invers ^ c_attrib->highlit ^
((s->cursor_visible && x == s->x && y == s->y && !s->y_scroll) ))
{
bgcol = color_table[0][t_attrib->fgcol];
fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
} else {
fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
bgcol = color_table[0][t_attrib->bgcol];
}
bpp = (ds->depth + 7) >> 3;
d = ds->data +
ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
linesize = ds->linesize;
// dprintf("vga_putcharxy: %d font:%d\n", ch, t_attrib->font );
switch( t_attrib->font ) {
case G0:
font_ptr = vgafont16 + FONT_HEIGHT * ch;
break;
case G1:
default:
font_ptr = graphfont16 + FONT_HEIGHT * ch;
break;
}
xorcol = bgcol ^ fgcol;
switch(ds->depth) {
case 8:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
if (t_attrib->uline
&& ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
font_data = 0xFFFF;
}
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
d += linesize;
}
break;
case 16:
case 15:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
if (t_attrib->uline
&& ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
font_data = 0xFFFF;
}
((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
d += linesize;
}
break;
case 32:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
font_data = 0xFFFF;
}
((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
d += linesize;
}
break;
}
}
static void text_console_resize(TextConsole *s)
{
TextCell *cells, *c, *c1;
int w1, x, y, last_width;
dprintf("text console resize %p\n", s->cells);
last_width = s->width;
s->width = s->g_width / FONT_WIDTH;
s->height = s->g_height / FONT_HEIGHT;
s->sr_top = 0;
s->sr_bottom = s->height - 1;
w1 = last_width;
if (s->width < w1)
w1 = s->width;
cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
memset(cells,0,s->width * s->total_height * sizeof(TextCell));
for(y = 0; y < s->total_height; y++) {
c = &cells[y * s->width];
if (w1 > 0) {
c1 = &s->cells[y * last_width];
for(x = 0; x < w1; x++) {
*c++ = *c1++;
}
}
for(x = w1; x < s->width; x++) {
c->ch = ' ';
c->t_attrib = s->t_attrib_default;
c->c_attrib = s->c_attrib_default;
c++;
}
}
qemu_free(s->cells);
s->cells = cells;
}
/*
where virtual lines have to be used in
loop, this macro should be used instead of y++
*/
#define next_line(A,Y) ((Y+1)%s->total_height)
/* projection onto 'real' screen
warning, this can return negative y or over s->height */
static int virtual_to_screen(TextConsole *s, int y)
{
y -= s->y_base-s->y_scroll;
y %= s->total_height;
if (y<0)
y += s->total_height;
return y;
}
/*
this should be used whenever we want to access data from
TextCells that reflect currently displayed screen frame
*/
static int screen_to_virtual(TextConsole *s, int y)
{
y += s->y_base-s->y_scroll;
y %= s->total_height;
if (y<0)
y += s->total_height;
return y;
}
/*
paints character under X,Y - as visible on screen
also sends VNC update for the character
*/
static void update_xy(TextConsole *s, int x, int y)
{
TextCell *c;
if (y<0 || x<0 || x>=s->width || y>=s->height)
return;
if (s == active_console) {
if (y < s->height) {
c = &s->cells[screen_to_virtual(s,y) * s->width + x];
vga_putcharxy(s, x, y, c->ch,
&(c->t_attrib), &(c->c_attrib));
s->ds->dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
FONT_WIDTH, FONT_HEIGHT);
}
}
}
/*
update whole rectangle of characters, as visible on screen
since this relies on update_x,y() - it also sends out VNC update
*/
static void update_rect(TextConsole *s, int x, int y, int w, int h)
{
int i,j;
for(i=0;i<h;i++) {
if (i+y > s->height)
break;
for(j=0;j<w;j++) {
if (j+x > s->width) {
w=j;
break;
}
update_xy(s, x+j, y+i);
}
}
}
static void set_cursor(TextConsole *s, int x, int y)
{
s->y = y;
s->wrapped = 0;
s->x = x;
}
static void console_show_cursor(TextConsole *s, int show)
{
s->cursor_visible = show;
if (s == active_console && s->x < s->width) {
update_xy(s, s->x, s->y);
}
}
/* calculate 'dinstance' (number of lines) between two given
lines on virtual console
*/
static int line_dist(TextConsole *s, int yf, int yt)
{
if (yf <= yt )
return yt-yf;
yt += s->total_height;
return yt-yf;
}
#define swap_coords(TY, FY, TX, FX) {int tmp; tmp = FX; FX = TX; TX = tmp; \
tmp = FY;FY = TY;TY = tmp;}
/* returns the selection as null terminated char
takes coordinates in virtual space already
*/
static char *
get_text(TextConsole *s, int from_x, int from_y, int to_x, int to_y)
{
TextCell *c;
char *buffer;
int bufidx = 0;
int sc_fy, sc_ty;
sc_fy = virtual_to_screen(s, from_y);
sc_ty = virtual_to_screen(s, to_y);
/* swap if necessary */
if ((sc_ty < sc_fy || (sc_ty == sc_fy && to_x < from_x)) && abs(sc_fy)-abs(sc_ty) < s->height) {
swap_coords(to_y, from_y, to_x, from_x);
sc_fy = sc_ty;
}
dprintf("get_text from %d/%d to %d/%d \n", from_y, from_x, to_y, to_x);
buffer = malloc((line_dist(s, from_y, to_y) + 1) * (s->width + 1));
if (buffer == NULL)
return NULL;
while(from_y != to_y || from_x != to_x) {
c = &s->cells[from_y*s->width + from_x];
if (c->t_attrib.used)
buffer[bufidx++] = c->ch;
from_x++;
if (from_x >= s->width) {
from_x = 0;
from_y = next_line(s, from_y);
if (!(c->t_attrib.used && c->c_attrib.wrapped))
buffer[bufidx++] = '\n';
}
}
buffer[bufidx] = 0;
return buffer;
}
/*
macros operating on selection structure
*/
#define zero_selection(A,B) {memset( &A->selections[B],0,sizeof(struct selection) );}
#define is_selection_zero(A,B) ((A->selections[B].startx | \
A->selections[B].starty | \
A->selections[B].endx | \
A->selections[B].endy ) == 0 )
/*
highlight the selected text visualy
this operates on 'virtual' coordinates
*/
static void
highlight(TextConsole *s, int from_x, int from_y, int to_x, int to_y, int highlight)
{
TextCell *c;
int sc_fy, sc_ty;
int x;
int last_c = 0;
if (from_y == to_y && to_x == from_x)
return;
sc_fy = virtual_to_screen(s, from_y);
sc_ty = virtual_to_screen(s, to_y);
/* swap if necessary */
if ((sc_ty < sc_fy || (sc_ty == sc_fy && to_x < from_x)) && abs(sc_fy)-abs(sc_ty) < s->height) {
swap_coords(to_y, from_y, to_x, from_x);
sc_fy = sc_ty;
}
dprintf("highlight from %d/%d to %d/%d - %d \n", from_y, from_x, to_y, to_x, highlight);
if (to_y != from_y) x = s->width - 1;
else x = to_x - 1;
while(x >= from_x) {
c = &s->cells[from_y * s->width + x];
if (c->c_attrib.highlit != highlight) {
if (c->t_attrib.used || from_y != to_y || last_c) {
c->c_attrib.highlit = highlight;
update_xy(s, x, sc_fy);
last_c = 1;
}
}
c--;
x--;
if (x < from_x && from_y != to_y) {
from_y = next_line(s, from_y);
if (from_y != to_y) x = s->width - 1;
else x = to_x - 1;
sc_fy = virtual_to_screen(s, from_y);
last_c = 0;
from_x = 0;
}
}
}
/*
static void
refresh(TextConsole *s, int y, int x)
{
TextCell *c;
if (x < 0 || y < 0 || x >= s->width || y >= s->height)
return;
c = &s->cells[cy(y) * s->width + x];
vga_putcharxy(s, x, y, c->ch, &(c->t_attrib), &(c->c_attrib));
s->ds->dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
FONT_WIDTH, FONT_HEIGHT);
}
*/
int
mouse_is_absolute(void *opaque)
{
return 1;
}
static void console_refresh(TextConsole *s)
{
TextCell *c;
int x, y;
if (s != active_console)
return;
vga_fill_rect(s->ds, 0, 0, s->g_width, s->g_height, s->t_attrib.bgcol);
for(y = 0; y < s->height; y++) {
c = &s->cells[screen_to_virtual(s,y) * s->width];
for(x = 0; x < s->width; x++) {
vga_putcharxy(s, x, y, c->ch, &(c->t_attrib), &(c->c_attrib));
c++;
}
}
s->ds->dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
console_show_cursor(s, 1);
}
static void clear_line(TextConsole *s, int line, int from_x, int to_x)
{
TextCell *c;
int m_fy, i;
if (to_x <= from_x)
return;
if (to_x > s->width)
to_x = s->width;
m_fy = screen_to_virtual(s, line);
c = &s->cells[(m_fy * s->width)+from_x];
for (i = from_x; i < to_x; i++) {
c->ch = ' ';
c->t_attrib = s->t_attrib_default;
c->t_attrib.fgcol = s->t_attrib.fgcol;
c->t_attrib.bgcol = s->t_attrib.bgcol;
c->c_attrib.wrapped = s->c_attrib_default.wrapped;
c++;
}
update_rect(s, from_x, line, to_x - from_x, 1);
}
static void clear(TextConsole *s, int from_x, int start_y, int to_x, int height)
{
int i;
dprintf("clear(%d, %d, %d, %d)\n", from_x, start_y, to_x,
start_y + height);
for (i = 0; i < height; i++)
clear_line(s, start_y + i,
(i == 0) ? from_x : 0, (i == height - 1) ? to_x : s->width);
}
/* this just scrolls view */
static void console_scroll(TextConsole *s, int ydelta)
{
if (!s || !s->text_console)
return;
s->y_scroll += -ydelta;
if (s->y_scroll > s->backscroll) {
ydelta += (s->y_scroll - s->backscroll);
s->y_scroll = s->backscroll;
}
if (s->y_scroll < 0 ) {
ydelta += s->y_scroll;
s->y_scroll = 0;
}
if (ydelta == 0)
return;
if (abs(ydelta) < s->height) {
vga_scroll(s, ydelta);
if (ydelta>0)
update_rect(s, 0, s->height-ydelta, s->width, ydelta );
else
update_rect(s, 0, 0, s->width, -ydelta );
/* update whole region, because dpy_copy_rect is currently not used */
s->ds->dpy_update(s->ds, 0, 0, s->g_width, s->g_height);
}
else {
update_rect(s, 0, 0, s->width, s->height );
}
}
static void scroll_text_cells(TextConsole* s, int f, int t, int by)
{
TextCell* fc, *tc;
int m_fy, m_ty, direction;
direction = by/abs(by);
by = abs(by);
while(by--) {
m_fy = screen_to_virtual(s, f);
m_ty = screen_to_virtual(s, t);
fc = &s->cells[(m_fy * s->width)];
tc = &s->cells[(m_ty * s->width)];
memmove(tc, fc, s->width*sizeof(TextCell));
t += direction;
f += direction;
};
}
static void scroll_to_base(TextConsole*s)
{
if (s->y_scroll)
console_scroll(s, s->y_scroll);
}
/* scrolls down, moves whole view to the +n point */
static void scroll_down(TextConsole* s, int n)
{
if (!s || !s->text_console)
return;
if ( s->sr_top != 0 || s->sr_bottom != s->height-1 ) {
if ( n > s->sr_bottom-s->sr_top ) {
n = s->sr_bottom-s->sr_top;
}
scroll_text_cells(s, s->sr_bottom-n, s->sr_bottom, n - s->sr_bottom + s->sr_top - 1);
update_rect(s, 0, s->sr_top + n, s->width, s->sr_bottom - s->sr_top - n + 1);
clear(s, 0, s->sr_top, s->width, n);
return;
}
s->backscroll -= n;
if (s->backscroll < 0)
s->backscroll = 0;
s->y_base -= n;
if (s->y_base < 0)
s->y_base += s->total_height;
vga_scroll(s, -n);
clear(s, 0, s->sr_top, s->width, n);
s->ds->dpy_update(s->ds, 0, 0, s->g_width, s->g_height);
}
/* scrolls up, moves whole view to the -n point */
static void scroll_up(TextConsole* s, int n)
{
if (!s || !s->text_console)
return;
if ( s->sr_top != 0 || s->sr_bottom != s->height-1 ) {
if ( n > s->sr_bottom-s->sr_top ) {
n = s->sr_bottom-s->sr_top;
}
scroll_text_cells(s, s->sr_top+n, s->sr_top, s->sr_bottom-s->sr_top-n+1);
update_rect(s, 0, s->sr_top, s->width, s->sr_bottom - s->sr_top - n + 1);
clear(s, 0, s->sr_bottom - n + 1, s->width, n);
return;
}
s->backscroll += n;
if (s->backscroll > (s->total_height-s->height) )
s->backscroll = s->total_height-s->height;
s->y_base = s->y_base + n;
if (s->y_base > s->total_height )
s->y_base -= s->total_height;
vga_scroll(s, n);
clear(s, 0, s->sr_bottom - n + 1, s->width, n);
s->ds->dpy_update(s->ds, 0, 0, s->g_width, s->g_height);
}
void
mouse_event(int dx, int dy, int dz, int buttons_state, void *opaque)
{
static int odx = 0;
int ndx;
CharDriverState *chr = opaque;
TextConsole *s = chr->opaque;
char *text;
dprintf("mouse event %03x:%03x:%x:%x\n", dx, dy, dz, buttons_state);
ndx = dx;
dx = dx * s->width / 0x7FFF;
dy = dy * s->height / 0x7FFF;
/* boundry check & fix */
if (dy >= s->height)
dy = s->height-1;
if (dx >= s->width)
dx = s->width-1;
if (dy < 0)
dy = 0;
if (dx < 0)
dx = 0;
if (dz == -1)
console_scroll(s, -1);
if (dz == 1)
console_scroll(s, 1);
s->mouse_x = dx;
s->mouse_y = dy;
/* button not pressed */
if (buttons_state == 0) {
/* if button was pressed before, means we have to grab selected text
end send it to peer's clipboard */
if (s->selecting) {
text = get_text(s, s->selections[0].startx, s->selections[0].starty,
s->selections[0].endx, s->selections[0].endy);
if ( text != NULL && strlen(text) )
s->ds->dpy_set_server_text(s->ds, text);
/* set flag, copy current selection to old one */
s->selecting = 0;
memcpy( &s->selections[1], &s->selections[0], sizeof(struct selection) );
zero_selection(s, 0);
}
} else if (buttons_state == 1) {
/* button pressed, no selection made - we have to initialze selection */
if (s->selecting == 0 ){
/* if previous highlight is still displayed,
we have to cancel it */
if ( !is_selection_zero(s, 1) )
highlight(s, s->selections[1].startx, s->selections[1].starty,
s->selections[1].endx, s->selections[1].endy, 0);
zero_selection(s, 1);
/* initialize current coordinates */
s->selections[0].startx = dx;
s->selections[0].starty = screen_to_virtual(s, dy);
s->selections[0].endx = dx;
s->selections[0].endy = screen_to_virtual(s, dy);
s->selecting=1;
/* highlite current character */
highlight(s, dx, screen_to_virtual(s, dy), dx, screen_to_virtual(s, dy), 1);
}
else {
if ( !is_selection_zero(s, 0) )
/* in this case, we just have to update selection */
/* zero the highlight first */
highlight(s, s->selections[0].startx, s->selections[0].starty,
s->selections[0].endx, s->selections[0].endy, 0);
if (dx == s->selections[0].endx) {
if (ndx - odx > 10) dx++;
} else if (dx == s->selections[0].endx - 1) {
if (odx - ndx < 10) dx++;
}
if (dx >= s->width) dx = s->width - 1;
/* update coords */
s->selections[0].endx = dx;
s->selections[0].endy = screen_to_virtual(s, dy);
/* highlight new region */
highlight(s, s->selections[0].startx, s->selections[0].starty,
s->selections[0].endx, s->selections[0].endy, 1);
}
}
odx = ndx;
}
static void va_write(TextConsole *s, char *f, ...)
{
va_list ap;
char *str;
va_start(ap, f);
vasprintf(&str, f, ap);
if (str)
write_or_chunk(&s->input_stream, (uint8_t *)str, strlen(str));
free(str);
va_end(ap);
}
static void console_put_lf(TextConsole *s)
{
scroll_to_base(s);
set_cursor(s, s->x, s->y + 1);
if (s->y > s->sr_bottom) {
set_cursor(s, s->x, s->sr_bottom);
scroll_up(s, 1);
}
}
static void console_put_cr(TextConsole *s)
{
set_cursor(s, 0, s->y);
}
static void console_put_ri(TextConsole *s)
{
set_cursor(s, s->x, s->y - 1);
if (s->y < s->sr_top) {
set_cursor(s, s->x, s->sr_top);
scroll_down(s, 1);
}
}
#if !defined(__APPLE__)
/* Set console attributes depending on the current escape codes.
* NOTE: I know this code is not very efficient (checking every color for it
* self) but it is more readable and better maintainable.
*/
static void console_handle_escape(TextConsole *s)
{
int i;
dprintf("handle ESC CSI M %d\n", s->nb_esc_params);
if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
s->t_attrib = s->t_attrib_default;
return;
}
for (i=0; i<s->nb_esc_params; i++) {
dprintf("\tparam %d\n", s->esc_params[i]);
switch (s->esc_params[i]) {
case 0: /* reset all console attributes to default */
s->t_attrib = s->t_attrib_default;
break;
case 1:
s->t_attrib.bold = 1;
break;
case 4:
s->t_attrib.uline = 1;
break;
case 5:
s->t_attrib.blink = 1;
break;
case 7:
s->t_attrib.invers = 1;
break;
case 8:
s->t_attrib.unvisible = 1;
break;
case 10:
s->t_attrib.font = 0;
s->display_ctrl = 0;
s->toggle_meta = 0;
break;
case 11:
s->t_attrib.codec[s->t_attrib.font] = MAPGRAF;
s->display_ctrl = 1;
s->toggle_meta = 0;
break;
case 12:
s->t_attrib.codec[s->t_attrib.font] = MAPIBMPC;
s->display_ctrl = 1;
s->toggle_meta = 1;
break;
/*
21 set normal intensity (this is not compatible with ECMA-48)
*/
case 22:
s->t_attrib.bold = 0;
break;
case 24:
s->t_attrib.uline = 0;
break;
case 25:
s->t_attrib.blink = 0;
break;
case 27:
s->t_attrib.invers = 0;
break;
case 28:
s->t_attrib.unvisible = 0;
break;
/* set foreground color */
case 30:
s->t_attrib.fgcol=COLOR_BLACK;
break;
case 31:
s->t_attrib.fgcol=COLOR_RED;
break;
case 32:
s->t_attrib.fgcol=COLOR_GREEN;
break;
case 33:
s->t_attrib.fgcol=COLOR_BROWN;
break;
case 34:
s->t_attrib.fgcol=COLOR_BLUE;
break;
case 35:
s->t_attrib.fgcol=COLOR_MAGENTA;
break;
case 36:
s->t_attrib.fgcol=COLOR_CYAN;
break;
case 37:
s->t_attrib.fgcol=COLOR_WHITE;
break;
case 38:
/* set to default foreground, underscore on */
s->t_attrib.fgcol=s->t_attrib_default.fgcol;
s->t_attrib.uline = 1;
break;
case 39:
/* set to default foreground, underscore off */
s->t_attrib.fgcol=s->t_attrib_default.fgcol;
s->t_attrib.uline = 0;
break;
/* set background color */
case 40:
s->t_attrib.bgcol=COLOR_BLACK;
break;
case 41:
s->t_attrib.bgcol=COLOR_RED;
break;
case 42:
s->t_attrib.bgcol=COLOR_GREEN;
break;
case 43:
s->t_attrib.bgcol=COLOR_BROWN;
break;
case 44:
s->t_attrib.bgcol=COLOR_BLUE;
break;
case 45:
s->t_attrib.bgcol=COLOR_MAGENTA;
break;
case 46:
s->t_attrib.bgcol=COLOR_CYAN;
break;
case 47:
s->t_attrib.bgcol=COLOR_WHITE;
break;
case 48:
/* TODO: implement - set collors acording to x,y cursor position */
break;
case 49:
/* set to default */
s->t_attrib.bgcol=s->t_attrib_default.bgcol;
break;
}
}
}
#endif
char normbuf[1024];
int normidx = 0, norm_x = 0, norm_y = 0;
static void print_norm(void)
{
if (normidx) {
normbuf[normidx] = 0;
dprintf("norm %d:%d >%s<\n", norm_x, norm_y, normbuf);
normidx = 0;
}
}
static void put_norm(TextConsole *s, char ch)
{
if (normidx == 0) {
norm_x = s->x;
norm_y = s->y;
}
normbuf[normidx++] = ch;
if (normidx == 1024)
print_norm();
}
static void do_putchar_utf(TextConsole *s, wchar_t ch, char glyph)
{
TextCell *c;
int nc, i;
scroll_to_base(s);
if (s->wrapped) {
c = &s->cells[screen_to_virtual(s, s->y) * s->width + s->x];
c->c_attrib.wrapped=1;
set_cursor(s, 0, s->y);
console_put_lf(s);
}
nc = wcwidth(ch);
dprintf("utf-8: %d columns char\n", nc);
if (nc < 0) nc = 1;
for (i = 0; i < nc; i++) {
put_norm(s, glyph);
c = &s->cells[screen_to_virtual(s, s->y) * s->width + s->x + i];
c->ch = glyph;
c->t_attrib = s->t_attrib;
c->t_attrib.used = 1;
c->c_attrib = s->c_attrib_default;
c->c_attrib.columns = nc;
c->c_attrib.spanned = i ? 1 : 0;
update_xy(s, s->x + i, s->y);
}
if (s->x + nc < s->width)
set_cursor(s, s->x + nc, s->y);
else
if (s->autowrap)
s->wrapped = 1;
}
static void do_putchar(TextConsole *s, int ch)
{
TextCell *c;
scroll_to_base(s);
put_norm(s, ch);
if (s->wrapped) {
c = &s->cells[screen_to_virtual(s, s->y) * s->width + s->x];
c->c_attrib.wrapped=1;
set_cursor(s, 0, s->y);
console_put_lf(s);
}
c = &s->cells[screen_to_virtual(s, s->y) * s->width + s->x];
c->ch = ch;
c->t_attrib = s->t_attrib;
c->t_attrib.used = 1;
c->c_attrib = s->c_attrib_default;
update_xy(s, s->x, s->y);
if (s->x + 1 < s->width)
set_cursor(s, s->x + 1, s->y);
else
if (s->autowrap)
s->wrapped = 1;
}
static int handle_params(TextConsole *s, int ch)
{
int i;
dprintf("putchar csi %02x '%c'\n", ch, ch > 0x1f ? ch : ' ');
if (ch >= '0' && ch <= '9') {
if (s->nb_esc_params < MAX_ESC_PARAMS) {
s->esc_params[s->nb_esc_params] =
s->esc_params[s->nb_esc_params] * 10 + ch - '0';
}
s->has_esc_param = 1;
return 0;
} else {
if (s->has_esc_param)
s->nb_esc_params++;
s->has_esc_param = 0;
if (ch == '?') {
s->has_qmark = 1;
return 0;
}
if (ch == ';')
return 0;
dprintf("csi %x[%c] with args", ch,
ch > 0x1f ? ch : ' ');
if (s->has_qmark)
dprintf(" ?");
for (i = 0; i < s->nb_esc_params; i++)
dprintf(" 0x%02x/%d", s->esc_params[i], s->esc_params[i]);
dprintf("\n");
}
return 1;
}
static void reset_params(TextConsole *s)
{
int i;
for(i=0;i<MAX_ESC_PARAMS;i++)
s->esc_params[i] = 0;
s->nb_esc_params = 0;
s->has_qmark = 0;
}
static void console_dch(TextConsole *s)
{
TextCell *c, *d, *t;
int x, a, nc, i;
if (s->esc_params[0] == 0)
s->esc_params[0] = 1;
a = s->nb_esc_params ? s->esc_params[0] : 1;
c = &s->cells[screen_to_virtual(s,s->y) * s->width + s->x];
d = c+a;
nc = 0;
i = 0;
t = c;
while (t->c_attrib.spanned) {
t--;
c--;
}
while (i < a) {
nc = nc + t->c_attrib.columns;
t = t + t->c_attrib.columns;
i++;
}
for(x = s->x; x < s->width - nc; x++) {
c->ch = d->ch;
c->t_attrib = d->t_attrib;
c++;
d++;
update_xy(s, x, s->y);
}
for (; x < s->width; x++) {
c->ch = ' ';
c->t_attrib = s->t_attrib_default;
c->t_attrib.fgcol = s->t_attrib.fgcol;
c->t_attrib.bgcol = s->t_attrib.bgcol;
c->c_attrib.wrapped = s->c_attrib_default.wrapped;
c++;
update_xy(s, x, s->y);
}
}
static void console_putchar(TextConsole *s, int ch)
{
TextCell *c, *d;
int y1, i, x, x1, a;
int x_, y_;
dprintf("putchar %02x '%c' state:%d\n", ch, ch > 0x1f ? ch : ' ', s->state);
if (s->unicodeIndex > 0 && (ch & 0xc0) == 0x80) goto unicode;
switch(s->state) {
case TTY_STATE_NORM:
dprintf("putchar norm %02x '%c'\n", ch, ch > 0x1f ? ch : ' ');
if (s->display_ctrl && (ch == 127 || !((0x0800f501 >> ch) & 1))) goto unicode;
switch(ch) {
case NUL:
case STX:
case SOH:
break;
case BEL:
dprintf("bell\n");
s->ds->dpy_bell(s->ds);
break;
case BS:
dprintf("BS\n");
if (s->x > 0)
set_cursor(s, s->x - 1, s->y);
break;
case HT:
dprintf("HT\n");
if (s->x + (8 - (s->x % 8)) > s->width) {
set_cursor(s, 0, s->y);
console_put_lf(s);
} else {
set_cursor(s, s->x + (8 - (s->x % 8)), s->y);
}
break;
case LF:
case VT:
case FF:
dprintf("LF\n");
console_put_lf(s);
break;
case CR:
dprintf("CR\n");
set_cursor(s, 0, s->y);
break;
case SO:
dprintf("SO G1 switch\n");
s->t_attrib.font = G1;
s->display_ctrl = 1;
break;
case SI:
dprintf("SI G0 switch\n");
s->t_attrib.font = G0;
s->display_ctrl = 0;
break;
case CAN:
case ESN:
dprintf("not implemented CAN\n");
break;
case ESC:
dprintf("ESC state\n");
print_norm();
reset_params(s);
s->state = TTY_STATE_ESC;
break;
case DEL: /* according to term=linux 'standard' should be ignored.*/
break;
case CSI:
dprintf("CSI state\n");
print_norm();
reset_params(s);
s->state = TTY_STATE_CSI;
break;
default:
unicode:
/* utf 8 bit */
if (s->t_attrib.utf && !s->display_ctrl) {
if (s->unicodeIndex > 0) {
wchar_t wc;
if ((ch & 0xc0) != 0x80) {
dprintf("bogus unicode data %u\n", ch);
s->unicodeIndex = 0;
do_putchar(s, '?');
return;
}
s->unicodeData[s->unicodeIndex++] = ch;
if (s->unicodeIndex < s->unicodeLength) {
return;
}
mbrtowc(&wc, s->unicodeData, s->unicodeLength, NULL);
switch (s->unicodeLength) {
case 2:
ch = (s->unicodeData[0] & 0x1f);
break;
case 3:
ch = (s->unicodeData[0] & 0x0f);
break;
case 4:
ch = (s->unicodeData[0] & 0x07);
break;
case 5:
ch = (s->unicodeData[0] & 0x03);
break;
case 6:
ch = (s->unicodeData[0] & 0x01);
break;
default:
dprintf("bogus unicode length %u\n", s->unicodeLength);
s->unicodeIndex = 0;
return;
break;
}
for (i = 1; i <= s->unicodeLength - 1; i++) {
ch = (ch << 6) + (s->unicodeData[i] & 0x3f);
}
s->unicodeIndex = 0;
ch = get_glyphcode(s, ch);
do_putchar_utf(s, wc, ch);
return;
}
/* multibyte sequence */
else if (ch > 0x7f) {
if ((ch & 0xe0) == 0xc0) {
memset(s->unicodeData, '\0', 7);
s->unicodeData[0] = ch;
s->unicodeIndex = 1;
s->unicodeLength = 2;
return;
}
else
if ((ch & 0xf0) == 0xe0) {
memset(s->unicodeData, '\0', 7);
s->unicodeData[0] = ch;
s->unicodeIndex = 1;
s->unicodeLength = 3;
return;
}
else
if ((ch & 0xf8) == 0xf0) {
memset(s->unicodeData, '\0', 7);
s->unicodeData[0] = ch;
s->unicodeIndex = 1;
s->unicodeLength = 4;
return;
}
else
if ((ch & 0xfc) == 0xf8) {
memset(s->unicodeData, '\0', 7);
s->unicodeData[0] = ch;
s->unicodeIndex = 1;
s->unicodeLength = 5;
return;
}
else
if ((ch & 0xfe) == 0xfc) {
memset(s->unicodeData, '\0', 7);
s->unicodeData[0] = ch;
s->unicodeIndex = 1;
s->unicodeLength = 6;
return;
} else {
dprintf("Invalid unicode sequence start %x\n", ch);
s->unicodeIndex = 0;
do_putchar(s, '?');
return;
}
} else {
/* single ASCII char */
do_putchar(s, ch);
}
/* end of utf 8 bit */
} else {
do_putchar(s, s->toggle_meta ? (ch|0x80) : ch);
return;
}
break;
}
break;
case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
if (ch != '[')
dprintf("putchar esc %02x '%c'\n", ch > 0x1f ? ch : ' ', ch);
s->state = TTY_STATE_NORM;
switch (ch) {
case ']': /* Operating system command */
s->state = TTY_STATE_NONSTD;
break;
case '>': /* Set numeric keypad mode */
break;
case '=': /* Set application keypad mode */
break;
case '#': /* boo */
dprintf("DECTEST: this should print E's on screen\n");
break;
case 'c': /* reset */
dprintf("RESET\n");
set_cursor(s, 0, 0);
s->display_ctrl = 0;
s->toggle_meta = 0;
s->nb_esc_params = 0;
s->t_attrib = s->t_attrib_default;
/* reset any highlighted area */
if ( !is_selection_zero(s, 1) )
highlight(s, s->selections[1].startx, s->selections[1].starty,
s->selections[1].endx, s->selections[1].endy, 0);
zero_selection(s,1);
clear(s, s->x, s->y, s->width, s->height);
break;
case 'D': /* linefeed */
dprintf("ESC_LF\n");
console_put_lf(s);
break;
case 'H': /* Set tab stop at current column.*/
dprintf("TAB stop - unimplemented\n");
break;
case 'Z': /* DEC private identification */
dprintf("DEC INDENT\n");
va_write(s, "\033[?6c");
break;
/* charset selection */
case '%':
dprintf("ESC PERCENT\n");
s->state = TTY_STATE_PERCENT;
break;
case '(': /* G0 charset */
dprintf("ESC (\n");
s->state = TTY_STATE_G0;
break;
case ')': /* G1 charset */
dprintf("ESC )\n");
s->state = TTY_STATE_G1;
break;
case '[': /* CSI */
reset_params(s);
s->state = TTY_STATE_CSI;
break;
case 'E': /* new line */
dprintf("ESC LF CR\n");
console_put_lf(s);
console_put_cr(s);
break;
case 'M': /* reverse linefeed */
dprintf("ESC RLF\n");
console_put_ri(s);
break;
case '7': /* save current state */
dprintf("ESC SAVE STATE\n");
s->saved_x = s->x;
s->saved_y = s->y;
s->saved_t_attrib = s->t_attrib;
break;
case '8': /* restore current state */
dprintf("ESC RESTORE STATE\n");
set_cursor(s, s->saved_x, s->saved_y);
s->t_attrib = s->saved_t_attrib;
break;
case 'P':
case 'R':
default:
dprintf("unknown STATE_ESC command %d\n", ch);
break;
}
break;
case TTY_STATE_CSI: /* handle escape sequence parameters */
if (handle_params(s, ch)) {
s->state = TTY_STATE_NORM;
switch(ch) {
case '@': /* ins del characters */
y1 = screen_to_virtual(s, s->y);
c = &s->cells[y1 * s->width + s->width - 1];
if (s->esc_params[0] == 0)
s->esc_params[0] = 1;
a = s->nb_esc_params ? s->esc_params[0] : 1;
d = &s->cells[y1 * s->width + s->width - 1 - a];
for (x = s->width - 1; x >= s->x + a; x--) {
c->ch = d->ch;
c->t_attrib = d->t_attrib;
c--;
d--;
update_xy(s, x, s->y);
}
clear_line(s, s->y, s->x, s->x + a);
break;
case 'A': /* cursor up */
if (s->esc_params[0] == 0)
s->esc_params[0] = 1;
a = s->nb_esc_params ? s->esc_params[0] : 1;
dprintf("cursor up %d\n", a);
set_cursor(s, s->x, s->y - a);
if (s->y < s->sr_top)
set_cursor(s, s->x, s->sr_top);
break;
case 'B': /* cursor down */
if (s->esc_params[0] == 0)
s->esc_params[0] = 1;
a = s->nb_esc_params ? s->esc_params[0] : 1;
dprintf("cursor down %d\n", a);
set_cursor(s, s->x, s->y + a);
if (s->y > s->sr_bottom)
set_cursor(s, s->x, s->sr_bottom);
break;
case 'a':
case 'C': /* cursor right */
if (s->esc_params[0] == 0)
s->esc_params[0] = 1;
a = s->nb_esc_params ? s->esc_params[0] : 1;
dprintf("cursor right %d\n", a);
set_cursor(s, s->x + a, s->y);
if (s->x >= s->width)
set_cursor(s, s->width - 1, s->y);
break;
case 'D': /* cursor left */
if (s->esc_params[0] == 0)
s->esc_params[0] = 1;
a = s->nb_esc_params ? s->esc_params[0] : 1;
dprintf("cursor left %d\n", a);
set_cursor(s, s->x - a, s->y);
if (s->x < 0)
set_cursor(s, 0, s->y);
break;
case 'E': /* cursor down and to first column */
if (s->esc_params[0] == 0)
s->esc_params[0] = 1;
a = s->nb_esc_params ? s->esc_params[0] : 1;
dprintf("cursor down %d and to first column\n", a);
set_cursor(s, 0, s->y + a);
if (s->y > s->sr_bottom)
set_cursor(s, 0, s->sr_bottom);
break;
case 'F': /* cursor up and to first column */
if (s->esc_params[0] == 0)
s->esc_params[0] = 1;
a = s->nb_esc_params ? s->esc_params[0] : 1;
dprintf("cursor up %d and to first column\n", a);
set_cursor(s, 0, s->y - a);;
if (s->y < s->sr_top)
set_cursor(s, 0, s->sr_top);
break;
case '`': /* fallthrough */
case 'G':
if (s->nb_esc_params == 1) {
dprintf("set cursor x %d\n", s->esc_params[0] - 1);
set_cursor(s, s->esc_params[0] - 1, s->y);
clip_x(s, x);
}
break;
case 'f':
case 'H': /* cursor position */
x_ = y_ = 0;
if (s->nb_esc_params > 1)
x_ = s->esc_params[1] - 1;
if (s->nb_esc_params > 0)
y_ = s->esc_params[0] - 1;
set_cursor(s, x_, (s->origin_mode ? s->sr_top : 0) + y_);
clip_xy(s, x, y);
dprintf("cursor pos %d:%d\n", s->y, s->x);
break;
case 'J': /* eraseInDisplay */
if (s->nb_esc_params == 0)
s->esc_params[0] = 0;
switch(s->esc_params[0]) {
case 0: /* erase from cursor to end of display */
clear(s, s->x, s->y, s->width,
s->sr_bottom - s->y + 1);
break;
case 1: /* erase from start to cursor */
clear(s, 0, s->sr_top, s->x + 1, s->y - s->sr_top + 1);
break;
case 2: /* erase whole display */
clear(s, 0, s->sr_top, s->width,
s->sr_bottom - s->sr_top + 1);
break;
}
break;
case 'K':
if (s->nb_esc_params == 0) {
s->esc_params[0] = 0;
s->nb_esc_params = 1;
}
if (s->nb_esc_params == 1) {
x = 0;
x1 = s->width;
if (s->esc_params[0] == 0)
x = s->x;
else if (s->esc_params[0] == 1)
x1 = s->x + 1;
dprintf("clear line %d %d->%d\n", s->y, x, x1);
clear(s, x, s->y, x1, 1);
}
break;
case 'L':
if (s->esc_params[0] == 0)
s->esc_params[0] = 1;
scroll_down(s, s->esc_params[0]);
break;
case 'M':
if (s->esc_params[0] == 0)
s->esc_params[0] = 1;
scroll_text_cells(s, s->y + s->esc_params[0], s->y, s->sr_bottom - s->y - s->esc_params[0] + 1);
update_rect(s, 0, s->y, s->width, s->sr_bottom - s->y - s->esc_params[0] + 1);
clear(s, 0, s->sr_bottom - s->esc_params[0] + 1, s->width, s->esc_params[0]);
break;
case 'P': /* DCH */
console_dch(s);
break;
case 'X':
{
int i = 0, a, nc = 0;
TextCell *c = &s->cells[screen_to_virtual(s,s->y) * s->width + s->x];
if (s->esc_params[0] == 0)
s->esc_params[0] = 1;
a = s->esc_params[0];
while (c->c_attrib.spanned)
c--;
while (i < a) {
nc = nc + c->c_attrib.columns;
c = c + c->c_attrib.columns;
i++;
}
clear(s, s->x, s->y, s->x + nc, 1);
break;
}
case 'c': /* device attributes */
if (s->nb_esc_params == 0 )
va_write(s, "\033[?6c"); // I'm a VT102
/* if there are any params, just return */
break;
case 'd':
if (s->nb_esc_params == 1) {
set_cursor(s, s->x, s->esc_params[0]-1);
}
break;
case 'e':
if (s->nb_esc_params == 1) {
if (s->esc_params[0] == 0)
s->esc_params[0] = 1;
set_cursor(s, s->x, s->y + s->esc_params[0]);
if (s->y > s->sr_bottom)
set_cursor(s, s->x, s->sr_bottom);
}
break;
case 'm':
#if !defined(__APPLE__)
console_handle_escape(s);
#endif
break;
case 'l': /* reset mode */
case 'h': /* set mode */
a = (ch == 'h') ? 1 : 0;
if (s->has_qmark) {
for (i = 0; i < s->nb_esc_params; i++) {
switch (s->esc_params[i]) {
case 1:
s->cursorkey_mode = a;
break;
case 2:
s->t_attrib.utf = ~a;
break;
case 3: // I
// s->column_mode = a;
break;
case 4:
// s->scrolling_mode = a;
break;
case 5:
// s->screen_mode = a;
break;
case 6:
s->origin_mode = a;
break;
case 7:
s->autowrap = a;
break;
case 8:
// s->autorepeat_mode = a;
break;
case 9:
// s->interlace_mode = a;
break;
case 20: // I
// s->line_mode = a;
break;
case 25:
s->cursor_visible = a;
break;
case 1000:
// s->mousereporting_mode = a;
break;
}
}
} else if (s->nb_esc_params >= 1) {
switch (s->esc_params[0]) {
case 3:
s->display_ctrl = a;
break;
case 4:
s->insert_mode = a;
break;
case 20:
// s->line_mode = a;
break;
}
}
break;
case 'n':
if (s->nb_esc_params == 1) {
switch (s->esc_params[0]) {
case 5: /* DSR */
va_write(s, "%c[0n", 0x1b);
break;
case 6: /* CPR */
va_write(s, "%c[%d;%dR", 0x1b, s->y + 1, s->x + 1);
break;
}
}
break;
case 'r':
if (s->nb_esc_params == 0) {
s->sr_top = 0;
s->sr_bottom = s->height - 1;
} else if (s->nb_esc_params == 2) {
s->sr_top = s->esc_params[0] - 1;
s->sr_bottom = s->esc_params[1] - 1;
clip_xy(s, sr_top, sr_bottom);
}
set_cursor(s, 0, s->sr_top);
break;
case 's':
s->saved_x = s->x;
s->saved_y = s->y;
break;
case 'u':
set_cursor(s, s->saved_x, s->saved_y);
break;
case 'q':
dprintf("led toggle\n");
break;
case 'x':
/* request terminal parametrs */
/* report
no parity set
8 bits per character
19200 transmit
19200 receive
bit rate multiplier is 16
switch values are all 0 */
va_write(s, "\033[2;1;1;120;120;1;0x");
break;
case ']':
dprintf("setterm(%d) NOT IMPLEMENTED\n", s->esc_params[0]);
break;
default:
dprintf("unknown command %x[%c] with args", ch,
ch > 0x1f ? ch : ' ');
for (i = 0; i < s->nb_esc_params; i++)
dprintf(" %0x/%d", s->esc_params[i], s->esc_params[i]);
dprintf("\n");
break;
}
break;
case TTY_STATE_G0:
case TTY_STATE_G1:
i = (s->state == TTY_STATE_G1) ? G0:G1;
dprintf("TTY_STATE_G%01d %d\n", i, ch);
switch(ch) {
case '0':
s->t_attrib.codec[i] = MAPGRAF;
break;
case 'B':
s->t_attrib.codec[i] = MAPLAT1;
break;
case 'U':
s->t_attrib.codec[i] = MAPIBMPC;
break;
case 'K':
s->t_attrib.codec[i] = MAPUSER;
break;
}
s->state = TTY_STATE_NORM;
break;
case TTY_STATE_PERCENT:
dprintf("TTY_STATE_PERCENT %d\n", ch);
switch (ch) {
case '@':
s->t_attrib.utf = 0;
s->t_attrib_default.utf = 0;
break;
case 'G':
case '8':
s->t_attrib.utf = 1;
s->t_attrib_default.utf = 1;
break;
}
s->state = TTY_STATE_NORM;
break;
}
break;
case TTY_STATE_NONSTD:
dprintf("TTY_STATE_NONSTD %c\n", ch);
switch (ch) {
case 'P':
s->nb_palette_params = 0;
memset(s->palette_params, 0x00, sizeof(uint8_t) * MAX_PALETTE_PARAMS);
s->state = TTY_STATE_PALETTE;
break;
case 'R':
set_color_table(s->ds);
s->state = TTY_STATE_NORM;
break;
default:
s->state = TTY_STATE_NORM;
break;
}
break;
case TTY_STATE_PALETTE:
if ( (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f') ) {
s->palette_params[s->nb_palette_params++] = (ch > '9' ? (ch & 0xDF) - 'A' + 10 : ch - '0');
if (s->nb_palette_params == 7) {
uint8_t r, g, b, j = 1;
r = 16 * s->palette_params[j++];
r += s->palette_params[j++];
g = 16 * s->palette_params[j++];
g += s->palette_params[j++];
b = 16 * s->palette_params[j++];
b += s->palette_params[j];
*(color_table[0] + s->palette_params[0]) = col_expand(s->ds, vga_get_color(s->ds, QEMU_RGB(r, g, b)));
s->state = TTY_STATE_NORM;
}
} else
s->state = TTY_STATE_NORM;
break;
}
}
void console_select(unsigned int index)
{
TextConsole *s;
if (index >= MAX_CONSOLES)
return;
s = consoles[index];
if (s) {
active_console = s;
if (s->text_console) {
if (s->g_width != s->ds->width ||
s->g_height != s->ds->height) {
s->g_width = s->ds->width;
s->g_height = s->ds->height;
text_console_resize(s);
}
console_refresh(s);
} else {
s->ds->hw_invalidate(s->ds->hw_opaque);
}
}
}
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
{
TextConsole *s = chr->opaque;
int i;
console_show_cursor(s, 0);
for(i = 0; i < len; i++) {
console_putchar(s, buf[i]);
}
console_show_cursor(s, 1);
return len;
}
#if 0
static void console_chr_add_read_handler(CharDriverState *chr,
IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read, void *opaque)
{
TextConsole *s = chr->opaque;
s->fd_can_read = fd_can_read;
s->fd_read = fd_read;
s->fd_opaque = opaque;
}
static void console_send_event(CharDriverState *chr, int event)
{
TextConsole *s = chr->opaque;
int i;
if (event == CHR_EVENT_FOCUS) {
for(i = 0; i < nb_consoles; i++) {
if (consoles[i] == s) {
console_select(i);
break;
}
}
}
}
static void kbd_send_chars(void *opaque)
{
TextConsole *s = opaque;
int len;
uint8_t buf[16];
len = s->fd_can_read(s->fd_opaque);
if (len > s->out_fifo.count)
len = s->out_fifo.count;
if (len > 0) {
if (len > sizeof(buf))
len = sizeof(buf);
qemu_fifo_read(&s->out_fifo, buf, len);
s->fd_read(s->fd_opaque, buf, len);
}
/* characters are pending: we send them a bit later (XXX:
horrible, should change char device API) */
if (s->out_fifo.count > 0) {
qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
}
}
#endif
static int cmputfents(const void *p1, const void *p2)
{
short a,b;
a=*(short*)p1;
b=*(short*)p2;
return a-b;
}
static void prepare_console_maps()
{
unsigned int i,j;
for(i=0;i<3;i++)
for(j=0;j<256;j++) {
consmap[i][j] |= j<<16;
}
/*
now we have to sort it, in order to prepare for binary search
*/
for(i=0;i<3;i++)
qsort( consmap[i], 256, sizeof(unsigned int), cmputfents );
}
/* Not safe after we drop privileges */
void dump_console_to_file(CharDriverState *chr, char *fn)
{
FILE* f;
TextConsole *s = chr->opaque;
if (s == NULL)
return;
if (s->cells == NULL)
return;
f=fopen(fn, "wb");
if (!f)
return;
fwrite(&(s->g_width), sizeof(int), 1, f);
fwrite(&(s->g_height), sizeof(int), 1, f);
fwrite(&(s->total_height), sizeof(int), 1, f);
fwrite(&(s->sr_bottom), sizeof(int), 1, f);
fwrite(&(s->sr_top), sizeof(int), 1, f);
fwrite(&(s->y_base), sizeof(int), 1, f);
fwrite(&(s->y_scroll), sizeof(int), 1, f);
fwrite(&(s->wrapped), sizeof(char), 1, f);
fwrite(&(s->x), sizeof(int), 1, f);
fwrite(&(s->y), sizeof(int), 1, f);
fwrite(&(s->saved_x), sizeof(int), 1, f);
fwrite(&(s->saved_y), sizeof(int), 1, f);
fwrite(&(s->backscroll), sizeof(int), 1, f);
fwrite(&(s->total_height), sizeof(int), 1, f);
fwrite(&(s->cursor_visible), sizeof(char), 1, f);
fwrite(&(s->autowrap), sizeof(char), 1, f);
fwrite(&(s->wrapped), sizeof(char), 1, f);
fwrite(&(s->insert_mode), sizeof(int), 1, f);
fwrite(&(s->cursorkey_mode), sizeof(int), 1, f);
fwrite(&(s->display_ctrl), sizeof(char), 1, f);
fwrite(&(s->toggle_meta), sizeof(char), 1, f);
fwrite(&(s->t_attrib_default), sizeof(TextAttributes), 1, f);
fwrite(&(s->t_attrib), sizeof(TextAttributes), 1, f);
fwrite(&(s->saved_t_attrib), sizeof(TextAttributes), 1, f);
fwrite(s->cells, sizeof(TextCell), s->width * s->total_height, f);
fwrite(&(s->state), sizeof(int), 1, f);
fwrite((s->esc_params), sizeof(int), MAX_ESC_PARAMS, f);
fwrite(&(s->nb_esc_params), sizeof(int), 1, f);
fwrite(&(s->has_esc_param), sizeof(int), 1, f);
fwrite(&(s->has_qmark), sizeof(int), 1, f);
fwrite((s->selections), sizeof(struct selection), 2, f);
fwrite(&(s->selecting), sizeof(int), 1, f);
fwrite(&(s->mouse_x), sizeof(int), 1, f);
fwrite(&(s->mouse_y), sizeof(int), 1, f);
fwrite(&(s->unicodeIndex), sizeof(int), 1, f);
fwrite((s->unicodeData), sizeof(char), 7, f);
fwrite(&(s->unicodeLength), sizeof(int), 1, f);
fclose(f);
}
void load_console_from_file(CharDriverState *chr, char *fn)
{
FILE* f;
TextConsole *s = chr->opaque;
if (s == NULL)
return;
if (s->cells == NULL)
return;
f=fopen(fn, "rb");
if (!f)
return;
fread(&(s->g_width), sizeof(int), 1, f);
fread(&(s->g_height), sizeof(int), 1, f);
fread(&(s->total_height), sizeof(int), 1, f);
text_console_resize(s);
fread(&(s->sr_bottom), sizeof(int), 1, f);
fread(&(s->sr_top), sizeof(int), 1, f);
fread(&(s->y_base), sizeof(int), 1, f);
fread(&(s->y_scroll), sizeof(int), 1, f);
fread(&(s->wrapped), sizeof(char), 1, f);
fread(&(s->x), sizeof(int), 1, f);
fread(&(s->y), sizeof(int), 1, f);
fread(&(s->saved_x), sizeof(int), 1, f);
fread(&(s->saved_y), sizeof(int), 1, f);
fread(&(s->backscroll), sizeof(int), 1, f);
fread(&(s->total_height), sizeof(int), 1, f);
fread(&(s->cursor_visible), sizeof(char), 1, f);
fread(&(s->autowrap), sizeof(char), 1, f);
fread(&(s->wrapped), sizeof(char), 1, f);
fread(&(s->insert_mode), sizeof(int), 1, f);
fread(&(s->cursorkey_mode), sizeof(int), 1, f);
fread(&(s->display_ctrl), sizeof(char), 1, f);
fread(&(s->toggle_meta), sizeof(char), 1, f);
fread(&(s->t_attrib_default), sizeof(TextAttributes), 1, f);
fread(&(s->t_attrib), sizeof(TextAttributes), 1, f);
fread(&(s->saved_t_attrib), sizeof(TextAttributes), 1, f);
fread(s->cells, sizeof(TextCell), s->width * s->total_height, f);
fread(&(s->state), sizeof(int), 1, f);
fread(s->esc_params, sizeof(int), MAX_ESC_PARAMS, f);
fread(&(s->nb_esc_params), sizeof(int), 1, f);
fread(&(s->has_esc_param), sizeof(int), 1, f);
fread(&(s->has_qmark), sizeof(int), 1, f);
fread(s->selections, sizeof(struct selection), 2, f);
fread(&(s->selecting), sizeof(int), 1, f);
fread(&(s->mouse_x), sizeof(int), 1, f);
fread(&(s->mouse_y), sizeof(int), 1, f);
fread(&(s->unicodeIndex), sizeof(int), 1, f);
fread(s->unicodeData, sizeof(char), 7, f);
fread(&(s->unicodeLength), sizeof(int), 1, f);
fclose(f);
}
/* called when an ascii key is pressed */
void kbd_put_keysym(int keysym)
{
TextConsole *s;
uint8_t buf[16], *q;
int c;
dprintf("kbd_put_keysym 0x%x\n", keysym );
s = active_console;
if (!s || !s->text_console)
return;
switch(keysym) {
case QEMU_KEY_CTRL_UP:
console_scroll(s, -1);
break;
case QEMU_KEY_CTRL_DOWN:
console_scroll(s, 1);
break;
case QEMU_KEY_SHIFT_PAGEUP:
console_scroll(s, -10);
break;
case QEMU_KEY_SHIFT_PAGEDOWN:
console_scroll(s, 10);
break;
default:
/* convert the QEMU keysym to VT100 key string */
q = buf;
switch (keysym) {
case QEMU_KEY_BACKSPACE:
/* following closely the linux term "standard" */
*q++ = 0x7f;
break;
case 0xe100 ... 0xe11f:
*q++ = '\033';
*q++ = '[';
c = keysym - 0xe100;
if (c >= 10)
*q++ = '0' + (c / 10);
*q++ = '0' + (c % 10);
*q++ = '~';
break;
case 0xe141 ... 0xe144:
*q++ = '\033';
dprintf("cm %d , %c\n", s->cursorkey_mode, keysym&0xff );
*q++ = s->cursorkey_mode ? 'O' : '[';
*q++ = keysym & 0xff;
break;
case 0xe120 ... 0xe140:
case 0xe145 ... 0xe17f:
*q++ = '\033';
*q++ = '[';
*q++ = keysym & 0xff;
break;
case 0xffb0 ... 0xffb9: /* keypad numbers from 0 to 9 */
*q++ = (keysym & 0x00ff) - 0xb0 + 0x30;
break;
case 0xffbe ... 0xffc2: /* F1 to F5 */
*q++ = '\033';
*q++ = '[';
*q++ = '[';
*q++ = 'A' + (keysym & 0xff) - 0xbe;
break;
case 0xffc3 ... 0xffc5: /* F6 to F8 */
*q++ = '\033';
*q++ = '[';
*q++ = '1';
*q++ = '7' + (keysym & 0xff) - 0xc3;
*q++ = '~';
break;
case 0xffc6: /* F9 */
case 0xffc7: /* F10 */
*q++ = '\033';
*q++ = '[';
*q++ = '2';
*q++ = '0' + (keysym & 0xff) - 0xc6;
*q++ = '~';
break;
case 0xffc8 ... 0xffcb: /* F11 to F14 */
*q++ = '\033';
*q++ = '[';
*q++ = '2';
*q++ = '3' + (keysym & 0xff) - 0xc8;
*q++ = '~';
break;
case 0xff95: /* KP_Home */
*q++ = '\033';
*q++ = '[';
*q++ = '1';
*q++ = '~';
break;
case 0xff96: /* KP_Left */
*q++ = '\033';
*q++ = '[';
*q++ = 'D';
break;
case 0xff97: /* KP_Up */
*q++ = '\033';
*q++ = '[';
*q++ = 'A';
break;
case 0xff98: /* KP_Right */
*q++ = '\033';
*q++ = '[';
*q++ = 'C';
break;
case 0xff99: /* KP_Down */
*q++ = '\033';
*q++ = '[';
*q++ = 'B';
break;
case 0xff9c: /* KP_End */
*q++ = '\033';
*q++ = '[';
*q++ = '4';
*q++ = '~';
break;
case 0xff9b: /* KP_Next (PgDown) */
*q++ = '\033';
*q++ = '[';
*q++ = '6';
*q++ = '~';
break;
case 0xff9d: /* Ignore KP_Begin (alternative to 5) */
break;
case 0xff7f: /* Ignore Num_Lock */
break;
case 0xffae: /* KP_Decimal */
*q++ = '.';
break;
case 0xff9e: /* KP_Insert */
case 0xff63: /* Insert */
*q++ = '\033';
*q++ = '[';
*q++ = '4';
if (!insertmode) {
*q++ = 'h';
insertmode = 1;
} else {
*q++ = 'l';
insertmode = 0;
}
break;
case 0xff9f: /* KP_Delete */
*q++ = '\033';
*q++ = '[';
*q++ = '3';
*q++ = '~';
break;
case 0xff8d: /* KP_Enter */
*q++ = 0x0d;
break;
case 0xffab: /* KP_Add */
*q++ = '+';
break;
case 0xff9a: /* KP_Prior (PgUp) */
*q++ = '\033';
*q++ = '[';
*q++ = '5';
*q++ = '~';
break;
case 0xffaf: /* KP_Divide */
*q++ = '/';
break;
case 0xffaa: /* KP_Multiply */
*q++ = '*';
break;
case 0xffad: /* KP_Subtract */
*q++ = '-';
break;
default:
*q++ = keysym;
}
for (c = 0; c < q - buf; c++)
dprintf("fchar %c %x\n", buf[c] > 0x1f ? buf[c] : ' ', buf[c]);
dprintf("write_or_chunk(%d, %ld)\n", s->input_stream.fd, (long int)(q-buf));
if (s->input_stream.fd != -1)
write_or_chunk(&s->input_stream, buf, q - buf);
break;
}
}
static TextConsole *new_console(DisplayState *ds, int text)
{
TextConsole *s;
int i;
if (nb_consoles >= MAX_CONSOLES)
return NULL;
s = qemu_mallocz(sizeof(TextConsole));
if (!s) {
return NULL;
}
memset(s, 0, sizeof(TextConsole));
if (!active_console || (active_console->text_console && !text))
active_console = s;
s->ds = ds;
s->cells = 0;
s->text_console = text;
ds->graphic_mode = text ? 0 : 1;
if (text) {
consoles[nb_consoles++] = s;
} else {
/* HACK: Put graphical consoles before text consoles. */
for (i = nb_consoles; i > 0; i--) {
if (!consoles[i - 1]->text_console)
break;
consoles[i] = consoles[i - 1];
}
consoles[i] = s;
}
s->input_stream.fd = -1;
s->autowrap = 1;
return s;
}
TextConsole *graphic_console_init(DisplayState *ds)
{
TextConsole *s;
s = new_console(ds, 0);
if (!s)
return NULL;
return s;
}
int is_graphic_console(void)
{
return !active_console->text_console;
}
void set_color_table(DisplayState *ds)
{
int i, j;
for(j = 0; j < 2; j++) {
for(i = 0; i < 8; i++) {
color_table[j][i] =
col_expand(ds, vga_get_color(ds, color_table_rgb[j][i]));
}
}
}
unsigned char nrof_clients_connected(CharDriverState *chr)
{
TextConsole *s = chr->opaque;
return s->ds->dpy_clients_connected(s->ds);
}
CharDriverState *text_console_init(DisplayState *ds)
{
CharDriverState *chr;
TextConsole *s;
static int color_inited;
/* init unicode maps */
// parse_unicode_map("/usr/share/xen/qemu/cp437_to_uni.trans");
prepare_console_maps();
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
return NULL;
s = new_console(ds, 1);
if (!s) {
free(chr);
return NULL;
}
chr->opaque = s;
chr->chr_write = console_puts;
#if 0
chr->chr_add_read_handler = console_chr_add_read_handler;
chr->chr_send_event = console_send_event;
#endif
#if 0
s->out_fifo.buf = s->out_fifo_buf;
s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
#endif
if (!color_inited) {
color_inited = 1;
set_color_table(ds);
}
s->y_base = DEFAULT_BACKSCROLL/3;
s->total_height = DEFAULT_BACKSCROLL;
set_cursor(s, 0, 0);
zero_selection(s, 1);
s->mouse_x = -1;
s->mouse_y = -1;
s->g_width = s->ds->width;
s->g_height = s->ds->height;
/* Set text attribute defaults */
s->t_attrib_default.bold = 0;
s->t_attrib_default.uline = 0;
s->t_attrib_default.blink = 0;
s->t_attrib_default.invers = 0;
s->t_attrib_default.unvisible = 0;
s->t_attrib_default.fgcol = COLOR_WHITE;
s->t_attrib_default.bgcol = COLOR_BLACK;
s->t_attrib_default.used = 0;
/* by default we love utf */
s->t_attrib_default.utf = 1;
s->t_attrib_default.codec[0] = MAPLAT1;
s->t_attrib_default.codec[1] = MAPGRAF;
s->t_attrib_default.font = G0;
s->c_attrib_default.highlit = 0;
s->c_attrib_default.wrapped = 0;
s->c_attrib_default.columns = 1;
s->c_attrib_default.spanned = 0;
s->unicodeIndex = 0;
s->unicodeLength = 0;
/* set current text attributes to default */
s->t_attrib = s->t_attrib_default;
text_console_resize(s);
return chr;
}
void
console_set_input(CharDriverState *chr, int fd, void *opaque)
{
TextConsole *s = chr->opaque;
s->input_stream.fd = fd;
s->input_stream.opaque = opaque;
s->input_stream.chunk = NULL;
s->input_stream.chunk_tail = &s->input_stream.chunk;
}
int
console_input_fd(CharDriverState *chr)
{
TextConsole *s = chr->opaque;
return s->input_stream.fd;
}
Jump to Line
Something went wrong with that request. Please try again.