Commit e7f0ad58c12b907ace1b263f06f2a2bdecfbde9f
1 parent
82c643ff
virtual console
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1024 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
711 additions
and
0 deletions
console.c
0 → 100644
1 | +/* | |
2 | + * QEMU graphical console | |
3 | + * | |
4 | + * Copyright (c) 2004 Fabrice Bellard | |
5 | + * | |
6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | + * of this software and associated documentation files (the "Software"), to deal | |
8 | + * in the Software without restriction, including without limitation the rights | |
9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | + * copies of the Software, and to permit persons to whom the Software is | |
11 | + * furnished to do so, subject to the following conditions: | |
12 | + * | |
13 | + * The above copyright notice and this permission notice shall be included in | |
14 | + * all copies or substantial portions of the Software. | |
15 | + * | |
16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | + * THE SOFTWARE. | |
23 | + */ | |
24 | +#include "vl.h" | |
25 | + | |
26 | +#define DEFAULT_BACKSCROLL 512 | |
27 | +#define MAX_CONSOLES 12 | |
28 | + | |
29 | +#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) | |
30 | +#define RGB(r, g, b) RGBA(r, g, b, 0xff) | |
31 | + | |
32 | +typedef struct TextCell { | |
33 | + uint8_t ch; | |
34 | + uint8_t bgcol:4; | |
35 | + uint8_t fgcol:4; | |
36 | +} TextCell; | |
37 | + | |
38 | +#define MAX_ESC_PARAMS 3 | |
39 | + | |
40 | +enum TTYState { | |
41 | + TTY_STATE_NORM, | |
42 | + TTY_STATE_ESC, | |
43 | + TTY_STATE_CSI, | |
44 | +}; | |
45 | + | |
46 | +struct TextConsole { | |
47 | + int text_console; /* true if text console */ | |
48 | + DisplayState *ds; | |
49 | + int g_width, g_height; | |
50 | + int width; | |
51 | + int height; | |
52 | + int total_height; | |
53 | + int backscroll_height; | |
54 | + int fgcol; | |
55 | + int bgcol; | |
56 | + int x, y; | |
57 | + int y_displayed; | |
58 | + int y_base; | |
59 | + TextCell *cells; | |
60 | + | |
61 | + enum TTYState state; | |
62 | + int esc_params[MAX_ESC_PARAMS]; | |
63 | + int nb_esc_params; | |
64 | + | |
65 | + /* kbd read handler */ | |
66 | + IOReadHandler *fd_read; | |
67 | + void *fd_opaque; | |
68 | +}; | |
69 | + | |
70 | +static TextConsole *active_console; | |
71 | +static TextConsole *consoles[MAX_CONSOLES]; | |
72 | +static int nb_consoles = 0; | |
73 | + | |
74 | +/* convert a RGBA color to a color index usable in graphic primitives */ | |
75 | +static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba) | |
76 | +{ | |
77 | + unsigned int r, g, b, color; | |
78 | + | |
79 | + switch(ds->depth) { | |
80 | +#if 0 | |
81 | + case 8: | |
82 | + r = (rgba >> 16) & 0xff; | |
83 | + g = (rgba >> 8) & 0xff; | |
84 | + b = (rgba) & 0xff; | |
85 | + color = (rgb_to_index[r] * 6 * 6) + | |
86 | + (rgb_to_index[g] * 6) + | |
87 | + (rgb_to_index[b]); | |
88 | + break; | |
89 | +#endif | |
90 | + case 15: | |
91 | + r = (rgba >> 16) & 0xff; | |
92 | + g = (rgba >> 8) & 0xff; | |
93 | + b = (rgba) & 0xff; | |
94 | + color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); | |
95 | + break; | |
96 | + case 16: | |
97 | + r = (rgba >> 16) & 0xff; | |
98 | + g = (rgba >> 8) & 0xff; | |
99 | + b = (rgba) & 0xff; | |
100 | + color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); | |
101 | + break; | |
102 | + case 32: | |
103 | + default: | |
104 | + color = rgba; | |
105 | + break; | |
106 | + } | |
107 | + return color; | |
108 | +} | |
109 | + | |
110 | +static void vga_fill_rect (DisplayState *ds, | |
111 | + int posx, int posy, int width, int height, uint32_t color) | |
112 | +{ | |
113 | + uint8_t *d, *d1; | |
114 | + int x, y, bpp; | |
115 | + | |
116 | + bpp = (ds->depth + 7) >> 3; | |
117 | + d1 = ds->data + | |
118 | + ds->linesize * posy + bpp * posx; | |
119 | + for (y = 0; y < height; y++) { | |
120 | + d = d1; | |
121 | + switch(bpp) { | |
122 | + case 1: | |
123 | + for (x = 0; x < width; x++) { | |
124 | + *((uint8_t *)d) = color; | |
125 | + d++; | |
126 | + } | |
127 | + break; | |
128 | + case 2: | |
129 | + for (x = 0; x < width; x++) { | |
130 | + *((uint16_t *)d) = color; | |
131 | + d += 2; | |
132 | + } | |
133 | + break; | |
134 | + case 4: | |
135 | + for (x = 0; x < width; x++) { | |
136 | + *((uint32_t *)d) = color; | |
137 | + d += 4; | |
138 | + } | |
139 | + break; | |
140 | + } | |
141 | + d1 += ds->linesize; | |
142 | + } | |
143 | +} | |
144 | + | |
145 | +/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */ | |
146 | +static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h) | |
147 | +{ | |
148 | + const uint8_t *s; | |
149 | + uint8_t *d; | |
150 | + int wb, y, bpp; | |
151 | + | |
152 | + bpp = (ds->depth + 7) >> 3; | |
153 | + wb = w * bpp; | |
154 | + if (yd <= ys) { | |
155 | + s = ds->data + | |
156 | + ds->linesize * ys + bpp * xs; | |
157 | + d = ds->data + | |
158 | + ds->linesize * yd + bpp * xd; | |
159 | + for (y = 0; y < h; y++) { | |
160 | + memmove(d, s, wb); | |
161 | + d += ds->linesize; | |
162 | + s += ds->linesize; | |
163 | + } | |
164 | + } else { | |
165 | + s = ds->data + | |
166 | + ds->linesize * (ys + h - 1) + bpp * xs; | |
167 | + d = ds->data + | |
168 | + ds->linesize * (yd + h - 1) + bpp * xd; | |
169 | + for (y = 0; y < h; y++) { | |
170 | + memmove(d, s, wb); | |
171 | + d -= ds->linesize; | |
172 | + s -= ds->linesize; | |
173 | + } | |
174 | + } | |
175 | +} | |
176 | + | |
177 | +/***********************************************************/ | |
178 | +/* basic char display */ | |
179 | + | |
180 | +#define FONT_HEIGHT 16 | |
181 | +#define FONT_WIDTH 8 | |
182 | + | |
183 | +#include "vgafont.h" | |
184 | + | |
185 | +#define cbswap_32(__x) \ | |
186 | +((uint32_t)( \ | |
187 | + (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ | |
188 | + (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ | |
189 | + (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ | |
190 | + (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )) | |
191 | + | |
192 | +#ifdef WORDS_BIGENDIAN | |
193 | +#define PAT(x) x | |
194 | +#else | |
195 | +#define PAT(x) cbswap_32(x) | |
196 | +#endif | |
197 | + | |
198 | +static const uint32_t dmask16[16] = { | |
199 | + PAT(0x00000000), | |
200 | + PAT(0x000000ff), | |
201 | + PAT(0x0000ff00), | |
202 | + PAT(0x0000ffff), | |
203 | + PAT(0x00ff0000), | |
204 | + PAT(0x00ff00ff), | |
205 | + PAT(0x00ffff00), | |
206 | + PAT(0x00ffffff), | |
207 | + PAT(0xff000000), | |
208 | + PAT(0xff0000ff), | |
209 | + PAT(0xff00ff00), | |
210 | + PAT(0xff00ffff), | |
211 | + PAT(0xffff0000), | |
212 | + PAT(0xffff00ff), | |
213 | + PAT(0xffffff00), | |
214 | + PAT(0xffffffff), | |
215 | +}; | |
216 | + | |
217 | +static const uint32_t dmask4[4] = { | |
218 | + PAT(0x00000000), | |
219 | + PAT(0x0000ffff), | |
220 | + PAT(0xffff0000), | |
221 | + PAT(0xffffffff), | |
222 | +}; | |
223 | + | |
224 | +static uint32_t color_table[8]; | |
225 | + | |
226 | +static const uint32_t color_table_rgb[8] = { | |
227 | + RGB(0x00, 0x00, 0x00), | |
228 | + RGB(0xff, 0x00, 0x00), | |
229 | + RGB(0x00, 0xff, 0x00), | |
230 | + RGB(0xff, 0xff, 0x00), | |
231 | + RGB(0x00, 0x00, 0xff), | |
232 | + RGB(0xff, 0x00, 0xff), | |
233 | + RGB(0x00, 0xff, 0xff), | |
234 | + RGB(0xff, 0xff, 0xff), | |
235 | +}; | |
236 | + | |
237 | +static inline unsigned int col_expand(DisplayState *ds, unsigned int col) | |
238 | +{ | |
239 | + switch(ds->depth) { | |
240 | + case 8: | |
241 | + col |= col << 8; | |
242 | + col |= col << 16; | |
243 | + break; | |
244 | + case 15: | |
245 | + case 16: | |
246 | + col |= col << 16; | |
247 | + break; | |
248 | + default: | |
249 | + break; | |
250 | + } | |
251 | + | |
252 | + return col; | |
253 | +} | |
254 | + | |
255 | +static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, | |
256 | + unsigned int fgcol, unsigned int bgcol) | |
257 | +{ | |
258 | + uint8_t *d; | |
259 | + const uint8_t *font_ptr; | |
260 | + unsigned int font_data, linesize, xorcol, bpp; | |
261 | + int i; | |
262 | + | |
263 | + bpp = (ds->depth + 7) >> 3; | |
264 | + d = ds->data + | |
265 | + ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH; | |
266 | + linesize = ds->linesize; | |
267 | + font_ptr = vgafont16 + FONT_HEIGHT * ch; | |
268 | + xorcol = bgcol ^ fgcol; | |
269 | + switch(ds->depth) { | |
270 | + case 8: | |
271 | + for(i = 0; i < FONT_HEIGHT; i++) { | |
272 | + font_data = *font_ptr++; | |
273 | + ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; | |
274 | + ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; | |
275 | + d += linesize; | |
276 | + } | |
277 | + break; | |
278 | + case 16: | |
279 | + case 15: | |
280 | + for(i = 0; i < FONT_HEIGHT; i++) { | |
281 | + font_data = *font_ptr++; | |
282 | + ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol; | |
283 | + ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol; | |
284 | + ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol; | |
285 | + ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol; | |
286 | + d += linesize; | |
287 | + } | |
288 | + break; | |
289 | + case 32: | |
290 | + for(i = 0; i < FONT_HEIGHT; i++) { | |
291 | + font_data = *font_ptr++; | |
292 | + ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol; | |
293 | + ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol; | |
294 | + ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol; | |
295 | + ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol; | |
296 | + ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol; | |
297 | + ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol; | |
298 | + ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol; | |
299 | + ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol; | |
300 | + d += linesize; | |
301 | + } | |
302 | + break; | |
303 | + } | |
304 | +} | |
305 | + | |
306 | +static void text_console_resize(TextConsole *s) | |
307 | +{ | |
308 | + TextCell *cells, *c, *c1; | |
309 | + int w1, x, y, last_width; | |
310 | + | |
311 | + last_width = s->width; | |
312 | + s->width = s->g_width / FONT_WIDTH; | |
313 | + s->height = s->g_height / FONT_HEIGHT; | |
314 | + | |
315 | + w1 = last_width; | |
316 | + if (s->width < w1) | |
317 | + w1 = s->width; | |
318 | + | |
319 | + cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell)); | |
320 | + for(y = 0; y < s->total_height; y++) { | |
321 | + c = &cells[y * s->width]; | |
322 | + if (w1 > 0) { | |
323 | + c1 = &s->cells[y * last_width]; | |
324 | + for(x = 0; x < w1; x++) { | |
325 | + *c++ = *c1++; | |
326 | + } | |
327 | + } | |
328 | + for(x = w1; x < s->width; x++) { | |
329 | + c->ch = ' '; | |
330 | + c->fgcol = 7; | |
331 | + c->bgcol = 0; | |
332 | + c++; | |
333 | + } | |
334 | + } | |
335 | + free(s->cells); | |
336 | + s->cells = cells; | |
337 | +} | |
338 | + | |
339 | +static void update_xy(TextConsole *s, int x, int y) | |
340 | +{ | |
341 | + TextCell *c; | |
342 | + int y1, y2; | |
343 | + | |
344 | + if (s == active_console) { | |
345 | + y1 = (s->y_base + y) % s->total_height; | |
346 | + y2 = y1 - s->y_displayed; | |
347 | + if (y2 < 0) | |
348 | + y2 += s->total_height; | |
349 | + if (y2 < s->height) { | |
350 | + c = &s->cells[y1 * s->width + x]; | |
351 | + vga_putcharxy(s->ds, x, y2, c->ch, | |
352 | + color_table[c->fgcol], color_table[c->bgcol]); | |
353 | + dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, | |
354 | + FONT_WIDTH, FONT_HEIGHT); | |
355 | + } | |
356 | + } | |
357 | +} | |
358 | + | |
359 | +static void console_show_cursor(TextConsole *s, int show) | |
360 | +{ | |
361 | + TextCell *c; | |
362 | + int y, y1; | |
363 | + | |
364 | + if (s == active_console) { | |
365 | + y1 = (s->y_base + s->y) % s->total_height; | |
366 | + y = y1 - s->y_displayed; | |
367 | + if (y < 0) | |
368 | + y += s->total_height; | |
369 | + if (y < s->height) { | |
370 | + c = &s->cells[y1 * s->width + s->x]; | |
371 | + if (show) { | |
372 | + vga_putcharxy(s->ds, s->x, y, c->ch, | |
373 | + color_table[0], color_table[7]); | |
374 | + } else { | |
375 | + vga_putcharxy(s->ds, s->x, y, c->ch, | |
376 | + color_table[c->fgcol], color_table[c->bgcol]); | |
377 | + } | |
378 | + dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, | |
379 | + FONT_WIDTH, FONT_HEIGHT); | |
380 | + } | |
381 | + } | |
382 | +} | |
383 | + | |
384 | +static void console_refresh(TextConsole *s) | |
385 | +{ | |
386 | + TextCell *c; | |
387 | + int x, y, y1; | |
388 | + | |
389 | + if (s != active_console) | |
390 | + return; | |
391 | + | |
392 | + vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height, | |
393 | + color_table[0]); | |
394 | + y1 = s->y_displayed; | |
395 | + for(y = 0; y < s->height; y++) { | |
396 | + c = s->cells + y1 * s->width; | |
397 | + for(x = 0; x < s->width; x++) { | |
398 | + vga_putcharxy(s->ds, x, y, c->ch, | |
399 | + color_table[c->fgcol], color_table[c->bgcol]); | |
400 | + c++; | |
401 | + } | |
402 | + if (++y1 == s->total_height) | |
403 | + y1 = 0; | |
404 | + } | |
405 | + dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height); | |
406 | + console_show_cursor(s, 1); | |
407 | +} | |
408 | + | |
409 | +static void console_scroll(int ydelta) | |
410 | +{ | |
411 | + TextConsole *s; | |
412 | + int i, y1; | |
413 | + | |
414 | + s = active_console; | |
415 | + if (!s || !s->text_console) | |
416 | + return; | |
417 | + | |
418 | + if (ydelta > 0) { | |
419 | + for(i = 0; i < ydelta; i++) { | |
420 | + if (s->y_displayed == s->y_base) | |
421 | + break; | |
422 | + if (++s->y_displayed == s->total_height) | |
423 | + s->y_displayed = 0; | |
424 | + } | |
425 | + } else { | |
426 | + ydelta = -ydelta; | |
427 | + i = s->backscroll_height; | |
428 | + if (i > s->total_height - s->height) | |
429 | + i = s->total_height - s->height; | |
430 | + y1 = s->y_base - i; | |
431 | + if (y1 < 0) | |
432 | + y1 += s->total_height; | |
433 | + for(i = 0; i < ydelta; i++) { | |
434 | + if (s->y_displayed == y1) | |
435 | + break; | |
436 | + if (--s->y_displayed < 0) | |
437 | + s->y_displayed = s->total_height - 1; | |
438 | + } | |
439 | + } | |
440 | + console_refresh(s); | |
441 | +} | |
442 | + | |
443 | +static void console_put_lf(TextConsole *s) | |
444 | +{ | |
445 | + TextCell *c; | |
446 | + int x, y1; | |
447 | + | |
448 | + s->x = 0; | |
449 | + s->y++; | |
450 | + if (s->y >= s->height) { | |
451 | + s->y = s->height - 1; | |
452 | + | |
453 | + if (s->y_displayed == s->y_base) { | |
454 | + if (++s->y_displayed == s->total_height) | |
455 | + s->y_displayed = 0; | |
456 | + } | |
457 | + if (++s->y_base == s->total_height) | |
458 | + s->y_base = 0; | |
459 | + if (s->backscroll_height < s->total_height) | |
460 | + s->backscroll_height++; | |
461 | + y1 = (s->y_base + s->height - 1) % s->total_height; | |
462 | + c = &s->cells[y1 * s->width]; | |
463 | + for(x = 0; x < s->width; x++) { | |
464 | + c->ch = ' '; | |
465 | + c->fgcol = s->fgcol; | |
466 | + c->bgcol = s->bgcol; | |
467 | + c++; | |
468 | + } | |
469 | + if (s == active_console && s->y_displayed == s->y_base) { | |
470 | + vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, | |
471 | + s->width * FONT_WIDTH, | |
472 | + (s->height - 1) * FONT_HEIGHT); | |
473 | + vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT, | |
474 | + s->width * FONT_WIDTH, FONT_HEIGHT, | |
475 | + color_table[s->bgcol]); | |
476 | + dpy_update(s->ds, 0, 0, | |
477 | + s->width * FONT_WIDTH, s->height * FONT_HEIGHT); | |
478 | + } | |
479 | + } | |
480 | +} | |
481 | + | |
482 | +static void console_putchar(TextConsole *s, int ch) | |
483 | +{ | |
484 | + TextCell *c; | |
485 | + int y1, i, x; | |
486 | + | |
487 | + switch(s->state) { | |
488 | + case TTY_STATE_NORM: | |
489 | + switch(ch) { | |
490 | + case '\r': | |
491 | + s->x = 0; | |
492 | + break; | |
493 | + case '\n': | |
494 | + console_put_lf(s); | |
495 | + break; | |
496 | + case 27: | |
497 | + s->state = TTY_STATE_ESC; | |
498 | + break; | |
499 | + default: | |
500 | + y1 = (s->y_base + s->y) % s->total_height; | |
501 | + c = &s->cells[y1 * s->width + s->x]; | |
502 | + c->ch = ch; | |
503 | + c->fgcol = s->fgcol; | |
504 | + c->bgcol = s->bgcol; | |
505 | + update_xy(s, s->x, s->y); | |
506 | + s->x++; | |
507 | + if (s->x >= s->width) | |
508 | + console_put_lf(s); | |
509 | + break; | |
510 | + } | |
511 | + break; | |
512 | + case TTY_STATE_ESC: | |
513 | + if (ch == '[') { | |
514 | + for(i=0;i<MAX_ESC_PARAMS;i++) | |
515 | + s->esc_params[i] = 0; | |
516 | + s->nb_esc_params = 0; | |
517 | + s->state = TTY_STATE_CSI; | |
518 | + } else { | |
519 | + s->state = TTY_STATE_NORM; | |
520 | + } | |
521 | + break; | |
522 | + case TTY_STATE_CSI: | |
523 | + if (ch >= '0' && ch <= '9') { | |
524 | + if (s->nb_esc_params < MAX_ESC_PARAMS) { | |
525 | + s->esc_params[s->nb_esc_params] = | |
526 | + s->esc_params[s->nb_esc_params] * 10 + ch - '0'; | |
527 | + } | |
528 | + } else { | |
529 | + s->nb_esc_params++; | |
530 | + if (ch == ';') | |
531 | + break; | |
532 | + s->state = TTY_STATE_NORM; | |
533 | + switch(ch) { | |
534 | + case 'D': | |
535 | + if (s->x > 0) | |
536 | + s->x--; | |
537 | + break; | |
538 | + case 'C': | |
539 | + if (s->x < (s->width - 1)) | |
540 | + s->x++; | |
541 | + break; | |
542 | + case 'K': | |
543 | + /* clear to eol */ | |
544 | + y1 = (s->y_base + s->y) % s->total_height; | |
545 | + for(x = s->x; x < s->width; x++) { | |
546 | + c = &s->cells[y1 * s->width + x]; | |
547 | + c->ch = ' '; | |
548 | + c->fgcol = s->fgcol; | |
549 | + c->bgcol = s->bgcol; | |
550 | + c++; | |
551 | + update_xy(s, x, s->y); | |
552 | + } | |
553 | + break; | |
554 | + default: | |
555 | + break; | |
556 | + } | |
557 | + break; | |
558 | + } | |
559 | + } | |
560 | +} | |
561 | + | |
562 | +void console_select(unsigned int index) | |
563 | +{ | |
564 | + TextConsole *s; | |
565 | + | |
566 | + if (index >= MAX_CONSOLES) | |
567 | + return; | |
568 | + s = consoles[index]; | |
569 | + if (s) { | |
570 | + active_console = s; | |
571 | + if (s->text_console) { | |
572 | + if (s->g_width != s->ds->width || | |
573 | + s->g_height != s->ds->height) | |
574 | + text_console_resize(s); | |
575 | + console_refresh(s); | |
576 | + } | |
577 | + } | |
578 | +} | |
579 | + | |
580 | +static int console_puts(CharDriverState *chr, const uint8_t *buf, int len) | |
581 | +{ | |
582 | + TextConsole *s = chr->opaque; | |
583 | + int i; | |
584 | + | |
585 | + console_show_cursor(s, 0); | |
586 | + for(i = 0; i < len; i++) { | |
587 | + console_putchar(s, buf[i]); | |
588 | + } | |
589 | + console_show_cursor(s, 1); | |
590 | + return len; | |
591 | +} | |
592 | + | |
593 | +static void console_chr_add_read_handler(CharDriverState *chr, | |
594 | + IOCanRWHandler *fd_can_read, | |
595 | + IOReadHandler *fd_read, void *opaque) | |
596 | +{ | |
597 | + TextConsole *s = chr->opaque; | |
598 | + s->fd_read = fd_read; | |
599 | + s->fd_opaque = opaque; | |
600 | +} | |
601 | + | |
602 | +/* called when an ascii key is pressed */ | |
603 | +void kbd_put_keysym(int keysym) | |
604 | +{ | |
605 | + TextConsole *s; | |
606 | + uint8_t buf[16], *q; | |
607 | + int c; | |
608 | + | |
609 | + s = active_console; | |
610 | + if (!s || !s->text_console) | |
611 | + return; | |
612 | + | |
613 | + switch(keysym) { | |
614 | + case QEMU_KEY_CTRL_UP: | |
615 | + console_scroll(-1); | |
616 | + break; | |
617 | + case QEMU_KEY_CTRL_DOWN: | |
618 | + console_scroll(1); | |
619 | + break; | |
620 | + case QEMU_KEY_CTRL_PAGEUP: | |
621 | + console_scroll(-10); | |
622 | + break; | |
623 | + case QEMU_KEY_CTRL_PAGEDOWN: | |
624 | + console_scroll(10); | |
625 | + break; | |
626 | + default: | |
627 | + if (s->fd_read) { | |
628 | + /* convert the QEMU keysym to VT100 key string */ | |
629 | + q = buf; | |
630 | + if (keysym >= 0xe100 && keysym <= 0xe11f) { | |
631 | + *q++ = '\033'; | |
632 | + *q++ = '['; | |
633 | + c = keysym - 0xe100; | |
634 | + if (c >= 10) | |
635 | + *q++ = '0' + (c / 10); | |
636 | + *q++ = '0' + (c % 10); | |
637 | + *q++ = '~'; | |
638 | + } else if (keysym >= 0xe120 && keysym <= 0xe17f) { | |
639 | + *q++ = '\033'; | |
640 | + *q++ = '['; | |
641 | + *q++ = keysym & 0xff; | |
642 | + } else { | |
643 | + *q++ = keysym; | |
644 | + } | |
645 | + s->fd_read(s->fd_opaque, buf, q - buf); | |
646 | + } | |
647 | + break; | |
648 | + } | |
649 | +} | |
650 | + | |
651 | +TextConsole *graphic_console_init(DisplayState *ds) | |
652 | +{ | |
653 | + TextConsole *s; | |
654 | + | |
655 | + if (nb_consoles >= MAX_CONSOLES) | |
656 | + return NULL; | |
657 | + s = qemu_mallocz(sizeof(TextConsole)); | |
658 | + if (!s) { | |
659 | + return NULL; | |
660 | + } | |
661 | + if (!active_console) | |
662 | + active_console = s; | |
663 | + s->ds = ds; | |
664 | + consoles[nb_consoles++] = s; | |
665 | + return s; | |
666 | +} | |
667 | + | |
668 | +int is_active_console(TextConsole *s) | |
669 | +{ | |
670 | + return s == active_console; | |
671 | +} | |
672 | + | |
673 | +CharDriverState *text_console_init(DisplayState *ds) | |
674 | +{ | |
675 | + CharDriverState *chr; | |
676 | + TextConsole *s; | |
677 | + int i; | |
678 | + static int color_inited; | |
679 | + | |
680 | + chr = qemu_mallocz(sizeof(CharDriverState)); | |
681 | + if (!chr) | |
682 | + return NULL; | |
683 | + s = graphic_console_init(ds); | |
684 | + if (!s) { | |
685 | + free(chr); | |
686 | + return NULL; | |
687 | + } | |
688 | + s->text_console = 1; | |
689 | + chr->opaque = s; | |
690 | + chr->chr_write = console_puts; | |
691 | + chr->chr_add_read_handler = console_chr_add_read_handler; | |
692 | + if (!color_inited) { | |
693 | + color_inited = 1; | |
694 | + for(i = 0; i < 8; i++) { | |
695 | + color_table[i] = col_expand(s->ds, | |
696 | + vga_get_color(s->ds, color_table_rgb[i])); | |
697 | + } | |
698 | + } | |
699 | + s->y_displayed = 0; | |
700 | + s->y_base = 0; | |
701 | + s->total_height = DEFAULT_BACKSCROLL; | |
702 | + s->x = 0; | |
703 | + s->y = 0; | |
704 | + s->fgcol = 7; | |
705 | + s->bgcol = 0; | |
706 | + s->g_width = s->ds->width; | |
707 | + s->g_height = s->ds->height; | |
708 | + text_console_resize(s); | |
709 | + | |
710 | + return chr; | |
711 | +} | ... | ... |