You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

573 lines
12 KiB

  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright (c) 2002-2009 Sam Hocevar <sam@hocevar.net>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  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. * This file contains a full conio.h reimplementation. More information
  16. * on conio.h can be found on http://poli.cs.vsb.cz/c/help/conio.htm
  17. */
  18. #include "config.h"
  19. #if !defined(__KERNEL__)
  20. # include <stdio.h>
  21. # include <stdlib.h>
  22. #endif
  23. #include "caca.h"
  24. #include "caca_internals.h"
  25. #include "caca_conio.h"
  26. static caca_canvas_t *cv;
  27. static caca_display_t *dp;
  28. static caca_timer_t refresh_timer = {0, 0};
  29. static uint64_t refresh_ticks;
  30. static int unget_ch = -1;
  31. static int kbhit_ch = -1;
  32. static char pass_buffer[8 + 1];
  33. static void conio_init(void);
  34. static void conio_refresh(void);
  35. static void conio_fini(void);
  36. int caca_conio_directvideo = 0;
  37. int caca_conio__wscroll = 1;
  38. /** \brief DOS conio.h cgets() equivalent */
  39. char * caca_conio_cgets(char *str)
  40. {
  41. int len = ((uint8_t *)str)[0];
  42. int pos = 0;
  43. conio_init();
  44. while (pos < len)
  45. {
  46. int ch = caca_conio_getch();
  47. if (ch == '\n' || ch == '\r')
  48. break;
  49. str[2 + pos] = (char)(uint8_t)ch;
  50. /* FIXME: handle scrolling */
  51. caca_put_char(cv, caca_wherex(cv), caca_wherey(cv), ch);
  52. caca_gotoxy(cv, caca_wherex(cv) + 1, caca_wherey(cv));
  53. pos++;
  54. }
  55. str[2 + pos] = '\0';
  56. str[1] = (char)(uint8_t)pos;
  57. conio_refresh();
  58. return str + 2;
  59. }
  60. /** \brief DOS conio.h clreol() equivalent */
  61. void caca_conio_clreol(void)
  62. {
  63. conio_init();
  64. /* FIXME: must work within the currently active text window */
  65. caca_fill_box(cv, caca_wherex(cv), caca_wherey(cv),
  66. caca_get_canvas_width(cv), caca_wherey(cv), ' ');
  67. conio_refresh();
  68. }
  69. /** \brief DOS conio.h clrscr() equivalent */
  70. void caca_conio_clrscr(void)
  71. {
  72. conio_init();
  73. /* FIXME: must work within the currently active text window */
  74. caca_clear_canvas(cv);
  75. caca_gotoxy(cv, 0, 0);
  76. conio_refresh();
  77. }
  78. /** \brief DOS conio.h cprintf() equivalent */
  79. int caca_conio_cprintf(const char *format, ...)
  80. {
  81. va_list args;
  82. int ret;
  83. conio_init();
  84. /* FIXME: handle scrolling */
  85. va_start(args, format);
  86. ret = caca_vprintf(cv, caca_wherex(cv), caca_wherey(cv), format, args);
  87. va_end(args);
  88. caca_gotoxy(cv, caca_wherex(cv) + ret, caca_wherey(cv));
  89. conio_refresh();
  90. return ret;
  91. }
  92. /** \brief DOS conio.h cputs() equivalent */
  93. int caca_conio_cputs(const char *str)
  94. {
  95. int ch;
  96. conio_init();
  97. while ((ch = (uint8_t)*str++))
  98. {
  99. /* FIXME: handle windows, scrolling, '\n' and '\r' */
  100. caca_put_char(cv, caca_wherex(cv), caca_wherey(cv), ch);
  101. caca_gotoxy(cv, caca_wherex(cv) + 1, caca_wherey(cv));
  102. }
  103. conio_refresh();
  104. return ch;
  105. }
  106. /** \brief DOS stdio.h cscanf() equivalent */
  107. int caca_conio_cscanf(char *format, ...)
  108. {
  109. conio_init();
  110. /* TODO: implement this function */
  111. return 0;
  112. }
  113. /** \brief DOS dos.h delay() equivalent */
  114. void caca_conio_delay(unsigned int milliseconds)
  115. {
  116. int64_t usec = (int64_t)milliseconds * 1000;
  117. caca_timer_t timer = {0, 0};
  118. conio_init();
  119. _caca_getticks(&timer);
  120. /* Refresh screen as long as we have enough time */
  121. while(usec > 5000)
  122. {
  123. conio_refresh();
  124. _caca_sleep(5000);
  125. usec -= _caca_getticks(&timer);
  126. }
  127. if(usec > 0)
  128. _caca_sleep(usec);
  129. conio_refresh();
  130. }
  131. /** \brief DOS conio.h delline() equivalent */
  132. void caca_conio_delline(void)
  133. {
  134. conio_init();
  135. /* TODO: implement this function */
  136. }
  137. /** \brief DOS conio.h getch() equivalent */
  138. int caca_conio_getch(void)
  139. {
  140. caca_event_t ev;
  141. int ret;
  142. conio_init();
  143. if(unget_ch >= 0)
  144. {
  145. int tmp = unget_ch;
  146. unget_ch = -1;
  147. return tmp;
  148. }
  149. if(kbhit_ch >= 0)
  150. {
  151. int tmp = kbhit_ch;
  152. kbhit_ch = -1;
  153. return tmp;
  154. }
  155. while(caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, 1000) == 0)
  156. conio_refresh();
  157. ret = caca_get_event_key_ch(&ev);
  158. conio_refresh();
  159. return ret;
  160. }
  161. /** \brief DOS conio.h getche() equivalent */
  162. int caca_conio_getche(void)
  163. {
  164. /* conio_init() is called here. */
  165. int tmp = caca_conio_getch();
  166. /* conio_refresh() is called here. */
  167. caca_conio_printf("%c", tmp);
  168. return tmp;
  169. }
  170. /** \brief DOS conio.h getpass() equivalent */
  171. char * caca_conio_getpass(const char *prompt)
  172. {
  173. int pos = 0;
  174. conio_init();
  175. while (pos < 8)
  176. {
  177. int ch = caca_conio_getch();
  178. if (ch == '\n' || ch == '\r')
  179. break;
  180. pass_buffer[pos] = (char)(uint8_t)ch;
  181. pos++;
  182. }
  183. pass_buffer[pos] = '\0';
  184. conio_refresh();
  185. return pass_buffer;
  186. }
  187. /** \brief DOS conio.h gettext() equivalent */
  188. int caca_conio_gettext(int left, int top, int right, int bottom, void *destin)
  189. {
  190. conio_init();
  191. /* TODO: implement this function */
  192. return 0;
  193. }
  194. /** \brief DOS conio.h gettextinfo() equivalent */
  195. void caca_conio_gettextinfo(struct caca_conio_text_info *r)
  196. {
  197. conio_init();
  198. /* TODO: implement this function */
  199. }
  200. /** \brief DOS conio.h gotoxy() equivalent */
  201. void caca_conio_gotoxy(int x, int y)
  202. {
  203. conio_init();
  204. caca_gotoxy(cv, x - 1, y - 1);
  205. conio_refresh();
  206. }
  207. /** \brief DOS conio.h highvideo() equivalent */
  208. void caca_conio_highvideo(void)
  209. {
  210. conio_init();
  211. /* TODO: implement this function */
  212. }
  213. /** \brief DOS conio.h insline() equivalent */
  214. void caca_conio_insline(void)
  215. {
  216. conio_init();
  217. /* TODO: implement this function */
  218. }
  219. /** \brief DOS conio.h kbhit() equivalent */
  220. int caca_conio_kbhit(void)
  221. {
  222. static caca_timer_t timer = {0, 0};
  223. static int last_failed = 0;
  224. caca_event_t ev;
  225. conio_init();
  226. /* If last call failed and this call is made less than 100µs
  227. * afterwards, we assume the caller is in a busy loop and we
  228. * delay it slightly to avoid resource leakage. */
  229. if(last_failed && _caca_getticks(&timer) < 100)
  230. {
  231. _caca_sleep(1000);
  232. conio_refresh();
  233. }
  234. last_failed = 0;
  235. if(kbhit_ch >= 0)
  236. return 1;
  237. if(caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, 0))
  238. {
  239. kbhit_ch = caca_get_event_key_ch(&ev);
  240. return 1;
  241. }
  242. last_failed = 1;
  243. return 0;
  244. }
  245. /** \brief DOS conio.h lowvideo() equivalent */
  246. void caca_conio_lowvideo(void)
  247. {
  248. conio_init();
  249. /* TODO: implement this function */
  250. }
  251. /** \brief DOS conio.h movetext() equivalent */
  252. int caca_conio_movetext(int left, int top, int right, int bottom,
  253. int destleft, int desttop)
  254. {
  255. caca_canvas_t *tmp;
  256. conio_init();
  257. if (left < 1 || top < 1 || left > right || top > bottom
  258. || destleft < 1 || desttop < 1 || destleft > right
  259. || desttop > bottom || right > caca_get_canvas_width(cv)
  260. || bottom > caca_get_canvas_width(cv))
  261. return 0;
  262. tmp = caca_create_canvas(right - left + 1, bottom - top + 1);
  263. caca_blit(tmp, 1 - left, 1 - top, cv, NULL);
  264. caca_blit(cv, destleft - 1, desttop - 1, tmp, NULL);
  265. conio_refresh();
  266. return 1;
  267. }
  268. /** \brief DOS conio.h normvideo() equivalent */
  269. void caca_conio_normvideo(void)
  270. {
  271. conio_init();
  272. /* TODO: implement this function */
  273. }
  274. /** \brief DOS dos.h nosound() equivalent */
  275. void caca_conio_nosound(void)
  276. {
  277. conio_init();
  278. /* TODO: implement this function */
  279. }
  280. /** \brief DOS stdio.h printf() equivalent */
  281. int caca_conio_printf(const char *format, ...)
  282. {
  283. va_list args;
  284. int ret;
  285. conio_init();
  286. va_start(args, format);
  287. ret = caca_vprintf(cv, caca_wherex(cv), caca_wherey(cv), format, args);
  288. va_end(args);
  289. caca_gotoxy(cv, caca_wherex(cv) + ret, caca_wherey(cv));
  290. conio_refresh();
  291. return 0;
  292. }
  293. /** \brief DOS conio.h putch() equivalent */
  294. int caca_conio_putch(int ch)
  295. {
  296. conio_init();
  297. /* FIXME: handle scrolling, windows */
  298. caca_put_char(cv, caca_wherex(cv), caca_wherey(cv), ch);
  299. caca_gotoxy(cv, caca_wherex(cv) + 1, caca_wherey(cv));
  300. return ch;
  301. }
  302. /** \brief DOS conio.h puttext() equivalent */
  303. int caca_conio_puttext(int left, int top, int right, int bottom, void *destin)
  304. {
  305. conio_init();
  306. /* TODO: implement this function */
  307. return 0;
  308. }
  309. /** \brief DOS conio.h _setcursortype() equivalent */
  310. void caca_conio__setcursortype(int cur_t)
  311. {
  312. conio_init();
  313. switch(cur_t)
  314. {
  315. case CACA_CONIO__NOCURSOR:
  316. caca_set_cursor(dp, 0);
  317. break;
  318. case CACA_CONIO__SOLIDCURSOR:
  319. case CACA_CONIO__NORMALCURSOR:
  320. caca_set_cursor(dp, 1);
  321. break;
  322. }
  323. conio_refresh();
  324. }
  325. /** \brief DOS dos.h sleep() equivalent */
  326. void caca_conio_sleep(unsigned int seconds)
  327. {
  328. int64_t usec = (int64_t)seconds * 1000000;
  329. caca_timer_t timer = {0, 0};
  330. conio_init();
  331. _caca_getticks(&timer);
  332. /* Refresh screen as long as we have enough time */
  333. while(usec > 5000)
  334. {
  335. conio_refresh();
  336. _caca_sleep(5000);
  337. usec -= _caca_getticks(&timer);
  338. }
  339. if(usec > 0)
  340. _caca_sleep(usec);
  341. conio_refresh();
  342. }
  343. /** \brief DOS dos.h sound() equivalent */
  344. void caca_conio_sound(unsigned int frequency)
  345. {
  346. conio_init();
  347. /* TODO: implement this function */
  348. }
  349. /** \brief DOS conio.h textattr() equivalent */
  350. void caca_conio_textattr(int newattr)
  351. {
  352. conio_init();
  353. /* TODO: implement this function */
  354. }
  355. /** \brief DOS conio.h textbackground() equivalent */
  356. void caca_conio_textbackground(int newcolor)
  357. {
  358. conio_init();
  359. caca_set_color_ansi(cv, caca_attr_to_ansi_fg(caca_get_attr(cv, -1, -1)),
  360. newcolor);
  361. }
  362. /** \brief DOS conio.h textcolor() equivalent */
  363. void caca_conio_textcolor(int newcolor)
  364. {
  365. conio_init();
  366. caca_set_color_ansi(cv, newcolor,
  367. caca_attr_to_ansi_bg(caca_get_attr(cv, -1, -1)));
  368. }
  369. /** \brief DOS conio.h textmode() equivalent */
  370. void caca_conio_textmode(int newmode)
  371. {
  372. conio_init();
  373. /* TODO: implement this function */
  374. }
  375. /** \brief DOS conio.h ungetch() equivalent */
  376. int caca_conio_ungetch(int ch)
  377. {
  378. conio_init();
  379. if(unget_ch >= 0)
  380. return EOF;
  381. unget_ch = ch;
  382. return ch;
  383. }
  384. /** \brief DOS conio.h wherex() equivalent */
  385. int caca_conio_wherex(void)
  386. {
  387. conio_init();
  388. return caca_wherex(cv) + 1;
  389. }
  390. /** \brief DOS conio.h wherey() equivalent */
  391. int caca_conio_wherey(void)
  392. {
  393. conio_init();
  394. return caca_wherey(cv) + 1;
  395. }
  396. /** \brief DOS conio.h window() equivalent */
  397. void caca_conio_window(int left, int top, int right, int bottom)
  398. {
  399. conio_init();
  400. /* TODO: implement this function */
  401. }
  402. /* XXX: the following functions are local. */
  403. static void conio_init(void)
  404. {
  405. if(!cv)
  406. cv = caca_create_canvas(80, 25);
  407. if(!dp)
  408. {
  409. dp = caca_create_display(cv);
  410. caca_refresh_display(dp);
  411. caca_set_cursor(dp, 1);
  412. _caca_getticks(&refresh_timer);
  413. refresh_ticks = 0;
  414. #if defined HAVE_ATEXIT
  415. atexit(conio_fini);
  416. #endif
  417. }
  418. }
  419. static void conio_refresh(void)
  420. {
  421. refresh_ticks += _caca_getticks(&refresh_timer);
  422. if(refresh_ticks > 10000)
  423. {
  424. caca_refresh_display(dp);
  425. _caca_getticks(&refresh_timer);
  426. refresh_ticks = 0;
  427. }
  428. }
  429. static void conio_fini(void)
  430. {
  431. caca_free_display(dp);
  432. dp = NULL;
  433. caca_free_canvas(cv);
  434. cv = NULL;
  435. }