1
0

main.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <event.h>
  5. #include <bio.h>
  6. #include <keyboard.h>
  7. #include "cons.h"
  8. enum{
  9. Ehost = 4,
  10. };
  11. char *menutext2[] = {
  12. "backup",
  13. "forward",
  14. "reset",
  15. "clear",
  16. "send",
  17. "page",
  18. 0
  19. };
  20. char *menutext3[] = {
  21. "24x80",
  22. "crnl",
  23. "nl",
  24. "raw",
  25. "exit",
  26. 0
  27. };
  28. /* variables associated with the screen */
  29. int x, y; /* character positions */
  30. char *backp;
  31. int backc;
  32. int atend;
  33. int nbacklines;
  34. int xmax, ymax;
  35. int blocked;
  36. int resize_flag;
  37. int pagemode;
  38. int olines;
  39. int peekc;
  40. int cursoron = 1;
  41. Menu menu2;
  42. Menu menu3;
  43. char *histp;
  44. char hist[HISTSIZ];
  45. int yscrmin, yscrmax;
  46. int bckcolor, frgcolor;
  47. int attribute;
  48. Image *bordercol;
  49. Image *cursback;
  50. Image *black;
  51. Image *white;
  52. Image *red;
  53. Image *green;
  54. Image *blue;
  55. Image *cyan;
  56. Image *magenta;
  57. Image *yellow;
  58. Image *grey;
  59. Image *colortab[8];
  60. /* terminal control */
  61. struct ttystate ttystate[2] = { {0, 1}, {0, 1} };
  62. int NS;
  63. int CW;
  64. Consstate *cs;
  65. Mouse mouse;
  66. int outfd = -1;
  67. Biobuf *snarffp = 0;
  68. char *host_buf;
  69. char *hostp; /* input from host */
  70. int host_bsize = 2*BSIZE;
  71. int hostlength; /* amount of input from host */
  72. char echo_input[BSIZE];
  73. char *echop = echo_input; /* characters to echo, after canon */
  74. char sendbuf[BSIZE]; /* hope you can't type ahead more than BSIZE chars */
  75. char *sendp = sendbuf;
  76. /* functions */
  77. void initialize(int, char **);
  78. void ebegin(int);
  79. int waitchar(void);
  80. int rcvchar(void);
  81. void set_input(char *);
  82. void set_host(Event *);
  83. void bigscroll(void);
  84. void readmenu(void);
  85. void eresized(int);
  86. void resize(void);
  87. void send_interrupt(void);
  88. int alnum(int);
  89. void escapedump(int,uchar *,int);
  90. char *term;
  91. struct funckey *fk;
  92. int debug;
  93. int logfd = -1;
  94. void
  95. main(int argc, char **argv)
  96. {
  97. initialize(argc, argv);
  98. emulate();
  99. }
  100. void
  101. useage(void)
  102. {
  103. fprint(2, "usage: %s [-2s] [-l logfile]\n", argv0);
  104. exits("usage");
  105. }
  106. void
  107. initialize(int argc, char **argv)
  108. {
  109. int dayglo = 1;
  110. char *p;
  111. rfork(RFENVG|RFNAMEG|RFNOTEG);
  112. term = "vt100";
  113. fk = vt100fk;
  114. ARGBEGIN{
  115. case 'a':
  116. term = "ansi";
  117. fk = ansifk;
  118. break;
  119. case '2':
  120. term = "vt220";
  121. fk = vt220fk;
  122. break;
  123. case 's': /* for sape */
  124. dayglo = 0;
  125. break;
  126. case 'l':
  127. p = ARGF();
  128. if(p == 0)
  129. useage();
  130. logfd = create(p, OWRITE, 0666);
  131. if(logfd < 0)
  132. sysfatal("could not create log file: %s: %r", p);
  133. break;
  134. }ARGEND;
  135. host_buf = malloc(host_bsize);
  136. hostp = host_buf;
  137. hostlength = 0;
  138. if(initdraw(0,0,term) < 0){
  139. fprint(2, "%s: initdraw failed: %r\n", term);
  140. exits("initdraw");
  141. }
  142. ebegin(Ehost);
  143. histp = hist;
  144. menu2.item = menutext2;
  145. menu3.item = menutext3;
  146. pagemode = 0;
  147. blocked = 0;
  148. NS = font->height ;
  149. CW = stringwidth(font, "m");
  150. bordercol = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCCC);
  151. cursback = allocimage(display, Rect(0, 0, CW+1, NS+1), screen->chan, 0, DNofill);
  152. black = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DBlack);
  153. white = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DWhite);
  154. red = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DRed);
  155. green = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DGreen);
  156. yellow = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DYellow);
  157. blue = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DBlue);
  158. magenta = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DMagenta);
  159. cyan = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DCyan);
  160. grey = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DPalegreygreen);
  161. colortab[0] = black;
  162. colortab[1] = red;
  163. colortab[2] = green;
  164. colortab[3] = yellow;
  165. colortab[4] = blue;
  166. colortab[5] = magenta;
  167. colortab[6] = cyan;
  168. colortab[7] = grey;
  169. if(dayglo) {
  170. bckcolor = 0;
  171. frgcolor = 7;
  172. } else {
  173. bckcolor = 7;
  174. frgcolor = 0;
  175. colortab[7] = white;
  176. }
  177. eresized(0);
  178. if(argc > 0) {
  179. sendnchars(strlen(argv[0]),argv[0]);
  180. sendnchars(1,"\n");
  181. }
  182. }
  183. void
  184. clear(Rectangle r)
  185. {
  186. draw(screen, r, colortab[bckcolor], nil, ZP);
  187. }
  188. void
  189. newline(void)
  190. {
  191. nbacklines--;
  192. if(y >= yscrmax) {
  193. y = yscrmax;
  194. if(pagemode && olines >= yscrmax) {
  195. blocked = 1;
  196. return;
  197. }
  198. scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
  199. } else
  200. y++;
  201. olines++;
  202. }
  203. void
  204. cursoff(void)
  205. {
  206. draw(screen, Rpt(pt(x, y), addpt(pt(x, y), Pt(CW,NS))),
  207. cursback, nil, cursback->r.min);
  208. }
  209. void
  210. curson(int bl)
  211. {
  212. Image *col;
  213. if(!cursoron){
  214. cursoff();
  215. return;
  216. }
  217. draw(cursback, cursback->r, screen, nil, pt(x, y));
  218. if(bl)
  219. col = red;
  220. else
  221. col = bordercol;
  222. border(screen, Rpt(pt(x, y), addpt(pt(x, y), Pt(CW,NS))), 2, col, ZP);
  223. }
  224. int
  225. get_next_char(void)
  226. {
  227. int c = peekc;
  228. uchar buf[1];
  229. peekc = 0;
  230. if(c > 0)
  231. return(c);
  232. while(c <= 0) {
  233. if(backp) {
  234. c = *backp;
  235. if(c && nbacklines >= 0) {
  236. backp++;
  237. if(backp >= &hist[HISTSIZ])
  238. backp = hist;
  239. return(c);
  240. }
  241. backp = 0;
  242. }
  243. c = (uchar)waitchar();
  244. if(c > 0 && logfd >= 0) {
  245. buf[0] = c;
  246. write(logfd, buf, 1);
  247. }
  248. }
  249. *histp++ = c;
  250. if(histp >= &hist[HISTSIZ])
  251. histp = hist;
  252. *histp = '\0';
  253. return(c);
  254. }
  255. int
  256. canon(char *ep, int c)
  257. {
  258. if(c&0200)
  259. return(SCROLL);
  260. switch(c) {
  261. case '\b':
  262. if(sendp > sendbuf)
  263. sendp--;
  264. *ep++ = '\b';
  265. *ep++ = ' ';
  266. *ep++ = '\b';
  267. break;
  268. case 0x15: /* ^U line kill */
  269. sendp = sendbuf;
  270. *ep++ = '^';
  271. *ep++ = 'U';
  272. *ep++ = '\n';
  273. break;
  274. case 0x17: /* ^W word kill */
  275. while(sendp > sendbuf && !alnum(*sendp)) {
  276. *ep++ = '\b';
  277. *ep++ = ' ';
  278. *ep++ = '\b';
  279. sendp--;
  280. }
  281. while(sendp > sendbuf && alnum(*sendp)) {
  282. *ep++ = '\b';
  283. *ep++ = ' ';
  284. *ep++ = '\b';
  285. sendp--;
  286. }
  287. break;
  288. case '\177': /* interrupt */
  289. sendp = sendbuf;
  290. send_interrupt();
  291. return(NEWLINE);
  292. case '\021': /* quit */
  293. case '\r':
  294. case '\n':
  295. if(sendp < &sendbuf[512])
  296. *sendp++ = '\n';
  297. sendnchars((int)(sendp-sendbuf), sendbuf);
  298. sendp = sendbuf;
  299. if(c == '\n' || c == '\r') {
  300. *ep++ = '\n';
  301. }
  302. *ep = 0;
  303. return(NEWLINE);
  304. case '\004': /* EOT */
  305. if(sendp == sendbuf) {
  306. sendnchars(0,sendbuf);
  307. *ep = 0;
  308. return(NEWLINE);
  309. }
  310. /* fall through */
  311. default:
  312. if(sendp < &sendbuf[512])
  313. *sendp++ = c;
  314. *ep++ = c;
  315. break;
  316. }
  317. *ep = 0;
  318. return(OTHER);
  319. }
  320. void
  321. sendfk(char *name)
  322. {
  323. int i;
  324. static int fd;
  325. for(i=0; fk[i].name; i++)
  326. if(strcmp(name, fk[i].name)==0){
  327. sendnchars2(strlen(fk[i].sequence), fk[i].sequence);
  328. return;
  329. }
  330. }
  331. int
  332. waitchar(void)
  333. {
  334. Event e;
  335. int c;
  336. char c2;
  337. int newmouse;
  338. int wasblocked;
  339. int kbdchar = -1;
  340. char echobuf[3*BSIZE];
  341. static int lastc = -1;
  342. for(;;) {
  343. if(resize_flag)
  344. resize();
  345. wasblocked = blocked;
  346. if(backp)
  347. return(0);
  348. if(ecanmouse() && (button2() || button3()))
  349. readmenu();
  350. if(snarffp) {
  351. if((c = Bgetc(snarffp)) < 0) {
  352. if(lastc != '\n')
  353. write(outfd,"\n",1);
  354. Bterm(snarffp);
  355. snarffp = 0;
  356. if(lastc != '\n') {
  357. lastc = -1;
  358. return('\n');
  359. }
  360. lastc = -1;
  361. continue;
  362. }
  363. lastc = c;
  364. c2 = c;
  365. write(outfd, &c2, 1);
  366. return(c);
  367. }
  368. if(!blocked && host_avail())
  369. return(rcvchar());
  370. if(kbdchar > 0) {
  371. if(blocked)
  372. resize();
  373. if(cs->raw) {
  374. switch(kbdchar){
  375. case Kup:
  376. sendfk("up key");
  377. break;
  378. case Kdown:
  379. sendfk("down key");
  380. break;
  381. case Kleft:
  382. sendfk("left key");
  383. break;
  384. case Kright:
  385. sendfk("right key");
  386. break;
  387. case KF|1:
  388. sendfk("F1");
  389. break;
  390. case KF|2:
  391. sendfk("F2");
  392. break;
  393. case KF|3:
  394. sendfk("F3");
  395. break;
  396. case KF|4:
  397. sendfk("F4");
  398. break;
  399. case KF|5:
  400. sendfk("F5");
  401. break;
  402. case KF|6:
  403. sendfk("F6");
  404. break;
  405. case KF|7:
  406. sendfk("F7");
  407. break;
  408. case KF|8:
  409. sendfk("F8");
  410. break;
  411. case KF|9:
  412. sendfk("F9");
  413. break;
  414. case KF|10:
  415. sendfk("F10");
  416. break;
  417. case KF|11:
  418. sendfk("F11");
  419. break;
  420. case KF|12:
  421. sendfk("F12");
  422. break;
  423. case '\n':
  424. echobuf[0] = '\r';
  425. sendnchars(1, echobuf);
  426. break;
  427. case '\r':
  428. echobuf[0] = '\n';
  429. sendnchars(1, echobuf);
  430. break;
  431. default:
  432. echobuf[0] = kbdchar;
  433. sendnchars(1, echobuf);
  434. break;
  435. }
  436. } else if(canon(echobuf,kbdchar) == SCROLL) {
  437. if(!blocked)
  438. bigscroll();
  439. } else
  440. strcat(echo_input,echobuf);
  441. blocked = 0;
  442. kbdchar = -1;
  443. continue;
  444. }
  445. curson(wasblocked); /* turn on cursor while we're waiting */
  446. do {
  447. newmouse = 0;
  448. switch(eread(blocked ? Emouse|Ekeyboard :
  449. Emouse|Ekeyboard|Ehost, &e)) {
  450. case Emouse:
  451. mouse = e.mouse;
  452. if(button2() || button3())
  453. readmenu();
  454. else if(resize_flag == 0) {
  455. /* eresized() is triggered by special mouse event */
  456. newmouse = 1;
  457. }
  458. break;
  459. case Ekeyboard:
  460. kbdchar = e.kbdc;
  461. break;
  462. case Ehost:
  463. set_host(&e);
  464. break;
  465. default:
  466. perror("protocol violation");
  467. exits("protocol violation");
  468. }
  469. } while(newmouse == 1);
  470. cursoff(); /* turn cursor back off */
  471. }
  472. return 1; /* to shut up compiler */
  473. }
  474. void
  475. eresized(int new)
  476. {
  477. resize_flag = 1+new;
  478. }
  479. void
  480. exportsize(void)
  481. {
  482. int fd;
  483. char buf[10];
  484. if((fd = create("/env/LINES", OWRITE, 0644)) > 0) {
  485. sprint(buf,"%d",ymax+1);
  486. write(fd,buf,strlen(buf));
  487. close(fd);
  488. }
  489. if((fd = create("/env/COLS", OWRITE, 0644)) > 0) {
  490. sprint(buf,"%d",xmax+1);
  491. write(fd,buf,strlen(buf));
  492. close(fd);
  493. }
  494. if((fd = create("/env/TERM", OWRITE, 0644)) > 0) {
  495. fprint(fd, "%s", term);
  496. close(fd);
  497. }
  498. }
  499. void
  500. resize(void)
  501. {
  502. if(resize_flag > 1 && getwindow(display, Refnone) < 0){
  503. fprint(2, "can't reattach to window: %r\n");
  504. exits("can't reattach to window");
  505. }
  506. xmax = (Dx(screen->r)-2*XMARGIN)/CW-1;
  507. ymax = (Dy(screen->r)-2*YMARGIN)/NS-1;
  508. if(xmax == 0 || ymax == 0)
  509. exits("window gone");
  510. x = 0;
  511. y = 0;
  512. yscrmin = 0;
  513. yscrmax = ymax;
  514. olines = 0;
  515. exportsize();
  516. clear(screen->r);
  517. resize_flag = 0;
  518. }
  519. void
  520. setdim(int ht, int wid)
  521. {
  522. int fd;
  523. Rectangle r;
  524. if(ht != -1)
  525. ymax = ht-1;
  526. if(wid != -1)
  527. xmax = wid-1;
  528. r.min = screen->r.min;
  529. r.max = addpt(screen->r.min,
  530. Pt((xmax+1)*CW+2*XMARGIN+2*INSET,
  531. (ymax+1)*NS+2*YMARGIN+2*INSET));
  532. fd = open("/dev/wctl", OWRITE);
  533. if(fd < 0 || fprint(fd, "resize -dx %d -dy %d\n", Dx(r)+2*Borderwidth, Dy(r)+2*Borderwidth) < 0){
  534. border(screen, r, INSET, bordercol, ZP);
  535. exportsize();
  536. }
  537. if(fd >= 0)
  538. close(fd);
  539. }
  540. void
  541. readmenu(void)
  542. {
  543. if(button3()) {
  544. menu3.item[1] = ttystate[cs->raw].crnl ? "cr" : "crnl";
  545. menu3.item[2] = ttystate[cs->raw].nlcr ? "nl" : "nlcr";
  546. menu3.item[3] = cs->raw ? "cooked" : "raw";
  547. switch(emenuhit(3, &mouse, &menu3)) {
  548. case 0: /* 24x80 */
  549. setdim(24, 80);
  550. return;
  551. case 1: /* newline after cr? */
  552. ttystate[cs->raw].crnl = !ttystate[cs->raw].crnl;
  553. return;
  554. case 2: /* cr after newline? */
  555. ttystate[cs->raw].nlcr = !ttystate[cs->raw].nlcr;
  556. return;
  557. case 3: /* switch raw mode */
  558. cs->raw = !cs->raw;
  559. return;
  560. case 4:
  561. exits(0);
  562. }
  563. return;
  564. }
  565. menu2.item[5] = pagemode? "scroll": "page";
  566. switch(emenuhit(2, &mouse, &menu2)) {
  567. case 0: /* back up */
  568. if(atend == 0) {
  569. backc++;
  570. backup(backc);
  571. }
  572. return;
  573. case 1: /* move forward */
  574. backc--;
  575. if(backc >= 0)
  576. backup(backc);
  577. else
  578. backc = 0;
  579. return;
  580. case 2: /* reset */
  581. backc = 0;
  582. backup(0);
  583. return;
  584. case 3: /* clear screen */
  585. eresized(0);
  586. return;
  587. case 4: /* send the snarf buffer */
  588. snarffp = Bopen("/dev/snarf",OREAD);
  589. return;
  590. case 5: /* pause and clear at end of screen */
  591. pagemode = 1-pagemode;
  592. if(blocked && !pagemode) {
  593. eresized(0);
  594. blocked = 0;
  595. }
  596. return;
  597. }
  598. }
  599. void
  600. backup(int count)
  601. {
  602. register n;
  603. register char *cp;
  604. eresized(0);
  605. n = 3*(count+1)*ymax/4;
  606. cp = histp;
  607. atend = 0;
  608. while (n >= 0) {
  609. cp--;
  610. if(cp < hist)
  611. cp = &hist[HISTSIZ-1];
  612. if(*cp == '\0') {
  613. atend = 1;
  614. break;
  615. }
  616. if(*cp == '\n')
  617. n--;
  618. }
  619. cp++;
  620. if(cp >= &hist[HISTSIZ])
  621. cp = hist;
  622. backp = cp;
  623. nbacklines = ymax-2;
  624. }
  625. Point
  626. pt(int x, int y)
  627. {
  628. return addpt(screen->r.min, Pt(x*CW+XMARGIN,y*NS+YMARGIN));
  629. }
  630. void
  631. scroll(int sy, int ly, int dy, int cy) /* source, limit, dest, which line to clear */
  632. {
  633. draw(screen, Rpt(pt(0, dy), pt(xmax+1, dy+ly-sy)), screen, nil, pt(0, sy));
  634. clear(Rpt(pt(0, cy), pt(xmax+1, cy+1)));
  635. }
  636. void
  637. bigscroll(void) /* scroll up half a page */
  638. {
  639. int half = ymax/3;
  640. if(x == 0 && y == 0)
  641. return;
  642. if(y < half) {
  643. clear(Rpt(pt(0,0),pt(xmax+1,ymax+1)));
  644. x = y = 0;
  645. return;
  646. }
  647. draw(screen, Rpt(pt(0, 0), pt(xmax+1, ymax+1)), screen, nil, pt(0, half));
  648. clear(Rpt(pt(0,y-half+1),pt(xmax+1,ymax+1)));
  649. y -= half;
  650. if(olines)
  651. olines -= half;
  652. }
  653. int
  654. number(char *p, int *got)
  655. {
  656. int c, n = 0;
  657. if(got)
  658. *got = 0;
  659. while ((c = get_next_char()) >= '0' && c <= '9'){
  660. if(got)
  661. *got = 1;
  662. n = n*10 + c - '0';
  663. }
  664. *p = c;
  665. return(n);
  666. }
  667. /* stubs */
  668. void
  669. sendnchars(int n,char *p)
  670. {
  671. sendnchars2(n, p);
  672. p[n+1] = 0;
  673. }
  674. void
  675. sendnchars2(int n,char *p)
  676. {
  677. if(write(outfd,p,n) < 0) {
  678. close(outfd);
  679. close(0);
  680. close(1);
  681. close(2);
  682. exits("write");
  683. }
  684. }
  685. int
  686. host_avail(void)
  687. {
  688. return(*echop || ((hostp - host_buf) < hostlength));
  689. }
  690. int
  691. rcvchar(void)
  692. {
  693. int c;
  694. if(*echop) {
  695. c = *echop++;
  696. if(!*echop) {
  697. echop = echo_input;
  698. *echop = 0;
  699. }
  700. return c;
  701. }
  702. return *hostp++;
  703. }
  704. void
  705. set_host(Event *e)
  706. {
  707. hostlength = e->n;
  708. if(hostlength > host_bsize) {
  709. host_bsize *= 2;
  710. host_buf = realloc(host_buf,host_bsize);
  711. }
  712. hostp = host_buf;
  713. memmove(host_buf,e->data,hostlength);
  714. host_buf[hostlength]=0;
  715. }
  716. void
  717. ringbell(void){
  718. }
  719. int
  720. alnum(int c)
  721. {
  722. if(c >= 'a' && c <= 'z')
  723. return 1;
  724. if(c >= 'A' && c <= 'Z')
  725. return 1;
  726. if(c >= '0' && c <= '9')
  727. return 1;
  728. return 0;
  729. }
  730. void
  731. escapedump(int fd,uchar *str,int len)
  732. {
  733. int i;
  734. for(i = 0; i < len; i++) {
  735. if((str[i] < ' ' || str[i] > '\177') &&
  736. str[i] != '\n' && str[i] != '\t') fprint(fd,"^%c",str[i]+64);
  737. else if(str[i] == '\177') fprint(fd,"^$");
  738. else if(str[i] == '\n') fprint(fd,"^J\n");
  739. else fprint(fd,"%c",str[i]);
  740. }
  741. }
  742. void
  743. funckey(int key)
  744. {
  745. if(key >= NKEYS)
  746. return;
  747. if(fk[key].name == 0)
  748. return;
  749. sendnchars2(strlen(fk[key].sequence), fk[key].sequence);
  750. }
  751. void
  752. drawstring(Point p, char *str, int attribute)
  753. {
  754. Image *txt, *bg;
  755. if(!(attribute & TReverse)) {
  756. txt = colortab[frgcolor];
  757. bg = colortab[bckcolor];
  758. } else {
  759. txt = colortab[bckcolor];
  760. bg = colortab[frgcolor];
  761. }
  762. if(attribute & THighIntensity)
  763. txt = white;
  764. draw(screen, Rpt(p, addpt(p, stringsize(font, str))), bg, nil, p);
  765. string(screen, p, txt, ZP, font, str);
  766. }