/*****************************************************************************/ /* */ /* */ /* CP/M emulator version 0.1 */ /* */ /* written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de) */ /* June-1994 */ /* */ /* This file is distributed under the GNU COPYRIGHT */ /* see COPYRIGHT.GNU for Copyright details */ /* */ /* */ /*****************************************************************************/ #include "cpmemu.h" #undef HAVE_RAW_IO /* magic for character I/O */ #include #include #include #include #ifdef HAVE_RAW_IO #include #include static int rawmode = 0; #endif #define SWITCHMODES /* switch between polled & sleeping */ #define POLLING 1 /* conin() loops */ #define SLEEPING 2 /* conin() sleeps until character found */ static int currentmode = POLLING; static int ifd, ofd; static struct termios iold, iraw; static struct termios oold, oraw; static void restore_modes(void) { tcsetattr(ifd,TCSAFLUSH,&iold); if (ifd != ofd) tcsetattr(ofd,TCSAFLUSH,&oold); } int setup_io(const char *tty) { if (tty) { ofd = ifd = open(tty, O_RDWR); if (ofd < 0) { fprintf(stderr, "cpm: cannot open tty %s\n", tty); exit(1); } } else { ifd = STDIN_FILENO; ofd = STDOUT_FILENO; } if (tcgetattr(ifd, &iold)) return 0; /* no chance */ iraw = iold; iraw.c_lflag &= ~ECHO & ~ECHONL & ~ICANON & ~ISIG; iraw.c_iflag &= ~(ICRNL | IGNCR | IXON | IXOFF); iraw.c_cc[VMIN] = 0; /* input: return without waiting */ iraw.c_cc[VTIME] = 0; if (ifd != ofd) { if (tcgetattr(ofd, &oold)) return 0; /* no chance */ oraw = oold; oraw.c_oflag &= ~OPOST; if (tcsetattr(ofd,TCSADRAIN,&oraw)) return 0; } else iraw.c_oflag &= ~OPOST; /* now, register atexit function */ atexit(restore_modes); if (tcsetattr(ifd,TCSADRAIN,&iraw)) return 0; return 1; } int waiting = -1; static void poll(void) { waiting = 0; #ifdef HAVE_RAW_IO /* nasty undocumented stuff to prepare for tandy I memory mapped keyboard emulation (need key release events) */ if (z80mem[4] == 0x5f && !rawmode) { ioctl(ifd, KDSKBMODE, K_RAW); rawmode = 1; } else if (z80mem[4] != 0x5f && rawmode) { ioctl(ifd, KDSKBMODE, K_XLATE); rawmode = 0; } #endif if (read(ifd, &waiting, 1) < 1) waiting = -1; } void putch(int c) { /* output character without postprocessing */ write(ofd, &c, 1); } void putmes(const char *s) { write(ofd, s, strlen(s)); } void vt52(int c) { /* simple vt52,adm3a => ANSI conversion */ static int state = 0, x, y; char buff[32]; #if 0 static FILE *log = NULL; if (!log) log = fopen("cpm.out", "w"); fputc(c, log); #endif switch (state) { case 0: switch (c) { case 0x7f: /* DEL: echo BS, space, BS */ putmes("\b \b"); break; case 0x1a: /* adm3a clear screen */ case 0x0c: /* vt52 clear screen */ putmes("\033[H\033[2J"); break; case 0x1e: /* adm3a cursor home */ putmes("\033[H"); break; case 0x1b: state = 1; /* esc-prefix */ break; case 1: state = 2; /* cursor motion prefix */ break; case 2: /* insert line */ putmes("\033[L"); break; case 3: /* delete line */ putmes("\033[M"); break; case 5: /* clear to eol */ putmes("\033[K"); break; case 18: case 19: break; default: putch(c); } break; case 1: /* esc was sent */ switch (c) { case '=': case 'Y': state = 2; break; default: /* some true ANSI sequence? */ state = 0; putch(0x1b); putch(c); } break; case 2: y = c - ' '+1; state = 3; break; case 3: x = c - ' '+1; state = 0; sprintf(buff, "\033[%d;%dH", y, x); putmes(buff); break; } } int getch(void) { /* return a character, or -1 if none ready */ if (waiting < 0) { /* must read character from keyboard */ /* this part switches to sleeping mode */ if (currentmode == POLLING) { iraw.c_cc[VMIN] = 1; currentmode = SLEEPING; tcsetattr(ifd,TCSADRAIN,&iraw); } poll(); } if (waiting >= 0) { int c; c = waiting & 0xff; waiting = -1; return c; } return -1; } int kbhit(void) { if (waiting < 0) { /* really ask keyboard */ /* this part switches to polling mode */ if (currentmode != POLLING) { iraw.c_cc[VMIN] = 0; currentmode = POLLING; tcsetattr(ifd,TCSADRAIN,&iraw); } poll(); } return waiting >= 0; }