source: libcaca/trunk/caca/caca_conio.c @ 4148

Last change on this file since 4148 was 3607, checked in by Sam Hocevar, 10 years ago

Implement conio.h functions cgets(), cputs(), getpass(), movetext(),
putch() and _setcurstortype().

  • Property svn:keywords set to Id
File size: 11.5 KB
Line 
1/*
2 *  libcaca       Colour ASCII-Art library
3 *  Copyright (c) 2002-2009 Sam Hocevar <sam@hocevar.net>
4 *                All Rights Reserved
5 *
6 *  $Id: caca_conio.c 3607 2009-08-02 11:09:42Z sam $
7 *
8 *  This library is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 *  This file contains a full conio.h reimplementation. More information
17 *  on conio.h can be found on http://poli.cs.vsb.cz/c/help/conio.htm
18 */
19
20#include "config.h"
21
22#if !defined(__KERNEL__)
23#   include <stdio.h>
24#   include <stdlib.h>
25#endif
26
27#include "caca.h"
28#include "caca_internals.h"
29#include "caca_conio.h"
30
31static caca_canvas_t *cv;
32static caca_display_t *dp;
33
34static caca_timer_t refresh_timer = {0, 0};
35static uint64_t refresh_ticks;
36
37static int unget_ch = -1;
38static int kbhit_ch = -1;
39static char pass_buffer[8 + 1];
40
41static void conio_init(void);
42static void conio_refresh(void);
43static void conio_fini(void);
44
45int caca_conio_directvideo = 0;
46int caca_conio__wscroll = 1;
47
48/** \brief DOS conio.h cgets() equivalent */
49char * caca_conio_cgets(char *str)
50{
51    int len = ((uint8_t *)str)[0];
52    int pos = 0;
53
54    conio_init();
55
56    while (pos < len)
57    {
58        int ch = caca_conio_getch();
59        if (ch == '\n' || ch == '\r')
60            break;
61        str[2 + pos] = (char)(uint8_t)ch;
62        /* FIXME: handle scrolling */
63        caca_put_char(cv, caca_wherex(cv), caca_wherey(cv), ch);
64        caca_gotoxy(cv, caca_wherex(cv) + 1, caca_wherey(cv));
65        pos++;
66    }
67
68    str[2 + pos] = '\0';
69    str[1] = (char)(uint8_t)pos;
70
71    conio_refresh();
72
73    return str + 2;
74}
75
76/** \brief DOS conio.h clreol() equivalent */
77void caca_conio_clreol(void)
78{
79    conio_init();
80
81    /* FIXME: must work within the currently active text window */
82    caca_fill_box(cv, caca_wherex(cv), caca_wherey(cv),
83                  caca_get_canvas_width(cv), caca_wherey(cv), ' ');
84
85    conio_refresh();
86}
87
88/** \brief DOS conio.h clrscr() equivalent */
89void caca_conio_clrscr(void)
90{
91    conio_init();
92
93    /* FIXME: must work within the currently active text window */
94    caca_clear_canvas(cv);
95    caca_gotoxy(cv, 0, 0);
96
97    conio_refresh();
98}
99
100/** \brief DOS conio.h cprintf() equivalent */
101int caca_conio_cprintf(const char *format, ...)
102{
103    va_list args;
104    int ret;
105
106    conio_init();
107
108    /* FIXME: handle scrolling */
109    va_start(args, format);
110    ret = caca_vprintf(cv, caca_wherex(cv), caca_wherey(cv), format, args);
111    va_end(args);
112
113    caca_gotoxy(cv, caca_wherex(cv) + ret, caca_wherey(cv));
114
115    conio_refresh();
116
117    return ret;
118}
119
120/** \brief DOS conio.h cputs() equivalent */
121int caca_conio_cputs(const char *str)
122{
123    int ch;
124
125    conio_init();
126
127    while ((ch = (uint8_t)*str++))
128    {
129        /* FIXME: handle windows, scrolling, '\n' and '\r' */
130        caca_put_char(cv, caca_wherex(cv), caca_wherey(cv), ch);
131        caca_gotoxy(cv, caca_wherex(cv) + 1, caca_wherey(cv));
132    }
133
134    conio_refresh();
135
136    return ch;
137}
138
139/** \brief DOS stdio.h cscanf() equivalent */
140int caca_conio_cscanf(char *format, ...)
141{
142    conio_init();
143
144    /* TODO: implement this function */
145
146    return 0;
147}
148
149/** \brief DOS dos.h delay() equivalent */
150void caca_conio_delay(unsigned int milliseconds)
151{
152    int64_t usec = (int64_t)milliseconds * 1000;
153    caca_timer_t timer = {0, 0};
154
155    conio_init();
156
157    _caca_getticks(&timer);
158
159    /* Refresh screen as long as we have enough time */
160    while(usec > 5000)
161    {
162        conio_refresh();
163        _caca_sleep(5000);
164        usec -= _caca_getticks(&timer);
165    }
166
167    if(usec > 0)
168        _caca_sleep(usec);
169
170    conio_refresh();
171}
172
173/** \brief DOS conio.h delline() equivalent */
174void caca_conio_delline(void)
175{
176    conio_init();
177
178    /* TODO: implement this function */
179}
180
181/** \brief DOS conio.h getch() equivalent */
182int caca_conio_getch(void)
183{
184    caca_event_t ev;
185    int ret;
186
187    conio_init();
188
189    if(unget_ch >= 0)
190    {
191        int tmp = unget_ch;
192        unget_ch = -1;
193        return tmp;
194    }
195
196    if(kbhit_ch >= 0)
197    {
198        int tmp = kbhit_ch;
199        kbhit_ch = -1;
200        return tmp;
201    }
202
203    while(caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, 1000) == 0)
204        conio_refresh();
205
206    ret = caca_get_event_key_ch(&ev);
207
208    conio_refresh();
209
210    return ret;
211}
212
213/** \brief DOS conio.h getche() equivalent */
214int caca_conio_getche(void)
215{
216    /* conio_init() is called here. */
217    int tmp = caca_conio_getch();
218    /* conio_refresh() is called here. */
219    caca_conio_printf("%c", tmp);
220
221    return tmp;
222}
223
224/** \brief DOS conio.h getpass() equivalent */
225char * caca_conio_getpass(const char *prompt)
226{
227    int pos = 0;
228
229    conio_init();
230
231    while (pos < 8)
232    {
233        int ch = caca_conio_getch();
234        if (ch == '\n' || ch == '\r')
235            break;
236        pass_buffer[pos] = (char)(uint8_t)ch;
237        pos++;
238    }
239
240    pass_buffer[pos] = '\0';
241
242    conio_refresh();
243
244    return pass_buffer;
245}
246
247/** \brief DOS conio.h gettext() equivalent */
248int caca_conio_gettext(int left, int top, int right, int bottom, void *destin)
249{
250    conio_init();
251
252    /* TODO: implement this function */
253
254    return 0;
255}
256
257/** \brief DOS conio.h gettextinfo() equivalent */
258void caca_conio_gettextinfo(struct caca_conio_text_info *r)
259{
260    conio_init();
261
262    /* TODO: implement this function */
263}
264
265/** \brief DOS conio.h gotoxy() equivalent */
266void caca_conio_gotoxy(int x, int y)
267{
268    conio_init();
269
270    caca_gotoxy(cv, x - 1, y - 1);
271
272    conio_refresh();
273}
274
275/** \brief DOS conio.h highvideo() equivalent */
276void caca_conio_highvideo(void)
277{
278    conio_init();
279
280    /* TODO: implement this function */
281}
282
283/** \brief DOS conio.h insline() equivalent */
284void caca_conio_insline(void)
285{
286    conio_init();
287
288    /* TODO: implement this function */
289}
290
291/** \brief DOS conio.h kbhit() equivalent */
292int caca_conio_kbhit(void)
293{
294    static caca_timer_t timer = {0, 0};
295    static int last_failed = 0;
296    caca_event_t ev;
297
298    conio_init();
299
300    /* If last call failed and this call is made less than 100µs
301     * afterwards, we assume the caller is in a busy loop and we
302     * delay it slightly to avoid resource leakage. */
303    if(last_failed && _caca_getticks(&timer) < 100)
304    {
305        _caca_sleep(1000);
306        conio_refresh();
307    }
308
309    last_failed = 0;
310
311    if(kbhit_ch >= 0)
312        return 1;
313
314    if(caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, 0))
315    {
316        kbhit_ch = caca_get_event_key_ch(&ev);
317        return 1;
318    }
319
320    last_failed = 1;
321
322    return 0;
323}
324
325/** \brief DOS conio.h lowvideo() equivalent */
326void caca_conio_lowvideo(void)
327{
328    conio_init();
329
330    /* TODO: implement this function */
331}
332
333/** \brief DOS conio.h movetext() equivalent */
334int caca_conio_movetext(int left, int top, int right, int bottom,
335                        int destleft, int desttop)
336{
337    caca_canvas_t *tmp;
338
339    conio_init();
340
341    if (left < 1 || top < 1 || left > right || top > bottom
342         || destleft < 1 || desttop < 1 || destleft > right
343         || desttop > bottom || right > caca_get_canvas_width(cv)
344         || bottom > caca_get_canvas_width(cv))
345        return 0;
346
347    tmp = caca_create_canvas(right - left + 1, bottom - top + 1);
348    caca_blit(tmp, 1 - left, 1 - top, cv, NULL);
349    caca_blit(cv, destleft - 1, desttop - 1, tmp, NULL);
350
351    conio_refresh();
352
353    return 1;
354}
355
356/** \brief DOS conio.h normvideo() equivalent */
357void caca_conio_normvideo(void)
358{
359    conio_init();
360
361    /* TODO: implement this function */
362}
363
364/** \brief DOS dos.h nosound() equivalent */
365void caca_conio_nosound(void)
366{
367    conio_init();
368
369    /* TODO: implement this function */
370}
371
372/** \brief DOS stdio.h printf() equivalent */
373int caca_conio_printf(const char *format, ...)
374{
375    va_list args;
376    int ret;
377
378    conio_init();
379
380    va_start(args, format);
381    ret = caca_vprintf(cv, caca_wherex(cv), caca_wherey(cv), format, args);
382    va_end(args);
383
384    caca_gotoxy(cv, caca_wherex(cv) + ret, caca_wherey(cv));
385
386    conio_refresh();
387
388    return 0;
389}
390
391/** \brief DOS conio.h putch() equivalent */
392int caca_conio_putch(int ch)
393{
394    conio_init();
395
396    /* FIXME: handle scrolling, windows */
397    caca_put_char(cv, caca_wherex(cv), caca_wherey(cv), ch);
398    caca_gotoxy(cv, caca_wherex(cv) + 1, caca_wherey(cv));
399
400    return ch;
401}
402
403/** \brief DOS conio.h puttext() equivalent */
404int caca_conio_puttext(int left, int top, int right, int bottom, void *destin)
405{
406    conio_init();
407
408    /* TODO: implement this function */
409
410    return 0;
411}
412
413/** \brief DOS conio.h _setcursortype() equivalent */
414void caca_conio__setcursortype(int cur_t)
415{
416    conio_init();
417
418    switch(cur_t)
419    {
420        case CACA_CONIO__NOCURSOR:
421            caca_set_cursor(dp, 0);
422            break;
423        case CACA_CONIO__SOLIDCURSOR:
424        case CACA_CONIO__NORMALCURSOR:
425            caca_set_cursor(dp, 1);
426            break;
427    }
428
429    conio_refresh();
430}
431
432/** \brief DOS dos.h sleep() equivalent */
433void caca_conio_sleep(unsigned int seconds)
434{
435    int64_t usec = (int64_t)seconds * 1000000;
436    caca_timer_t timer = {0, 0};
437
438    conio_init();
439
440    _caca_getticks(&timer);
441
442    /* Refresh screen as long as we have enough time */
443    while(usec > 5000)
444    {
445        conio_refresh();
446        _caca_sleep(5000);
447        usec -= _caca_getticks(&timer);
448    }
449
450    if(usec > 0)
451        _caca_sleep(usec);
452
453    conio_refresh();
454}
455
456/** \brief DOS dos.h sound() equivalent */
457void caca_conio_sound(unsigned int frequency)
458{
459    conio_init();
460
461    /* TODO: implement this function */
462}
463
464/** \brief DOS conio.h textattr() equivalent */
465void caca_conio_textattr(int newattr)
466{
467    conio_init();
468
469    /* TODO: implement this function */
470}
471
472/** \brief DOS conio.h textbackground() equivalent */
473void caca_conio_textbackground(int newcolor)
474{
475    conio_init();
476
477    caca_set_color_ansi(cv, caca_attr_to_ansi_fg(caca_get_attr(cv, -1, -1)),
478                        newcolor);
479}
480
481/** \brief DOS conio.h textcolor() equivalent */
482void caca_conio_textcolor(int newcolor)
483{
484    conio_init();
485
486    caca_set_color_ansi(cv, newcolor,
487                        caca_attr_to_ansi_bg(caca_get_attr(cv, -1, -1)));
488}
489
490/** \brief DOS conio.h textmode() equivalent */
491void caca_conio_textmode(int newmode)
492{
493    conio_init();
494
495    /* TODO: implement this function */
496}
497
498/** \brief DOS conio.h ungetch() equivalent */
499int caca_conio_ungetch(int ch)
500{
501    conio_init();
502
503    if(unget_ch >= 0)
504        return EOF;
505
506    unget_ch = ch;
507
508    return ch;
509}
510
511/** \brief DOS conio.h wherex() equivalent */
512int caca_conio_wherex(void)
513{
514    conio_init();
515
516    return caca_wherex(cv) + 1;
517}
518
519/** \brief DOS conio.h wherey() equivalent */
520int caca_conio_wherey(void)
521{
522    conio_init();
523
524    return caca_wherey(cv) + 1;
525}
526
527/** \brief DOS conio.h window() equivalent */
528void caca_conio_window(int left, int top, int right, int bottom)
529{
530    conio_init();
531
532    /* TODO: implement this function */
533}
534
535/* XXX: the following functions are local. */
536
537static void conio_init(void)
538{
539    if(!cv)
540        cv = caca_create_canvas(80, 25);
541    if(!dp)
542    {
543        dp = caca_create_display(cv);
544        caca_refresh_display(dp);
545        caca_set_cursor(dp, 1);
546        _caca_getticks(&refresh_timer);
547        refresh_ticks = 0;
548#if defined HAVE_ATEXIT
549        atexit(conio_fini);
550#endif
551    }
552}
553
554static void conio_refresh(void)
555{
556    refresh_ticks += _caca_getticks(&refresh_timer);
557    if(refresh_ticks > 10000)
558    {
559        caca_refresh_display(dp);
560        _caca_getticks(&refresh_timer);
561        refresh_ticks = 0;
562    }
563}
564
565static void conio_fini(void)
566{
567    caca_free_display(dp);
568    dp = NULL;
569    caca_free_canvas(cv);
570    cv = NULL;
571}
572
Note: See TracBrowser for help on using the repository browser.