1 /*
2  * A braille interface to unix tty terminals
3  *
4  * Authors:  Hadi Bargi Rangin  bargi@dots.physics.orst.edu
5  *           Bill Barry         barryb@dots.physics.orst.edu
6  *
7  * Copyright (c) 1995 by Science Access Project, Oregon State University.
8  *
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3, or (at your option)
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program (see the file COPYING); if not, see
22  * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
24  *
25  ****************************************************************
26  */
27 
28 #include <stdio.h>
29 #include <fcntl.h>
30 #include <sys/stat.h>
31 
32 #include "config.h"
33 #include "screen.h"
34 #include "extern.h"
35 #include "braille.h"
36 
37 #ifdef HAVE_BRAILLE
38 
39 
40 extern int bd_init_powerbraille_40 __P((void));
41 extern int bd_init_powerbraille_80 __P((void));
42 extern int bd_init_navigator_40 __P((void));
43 
44 extern struct layer *flayer;
45 extern struct display *displays, *display;
46 extern char *rc_name;
47 
48 
49 
50 
51 /* global variables */
52 
53 struct braille_display bd;
54 
55 struct bd_type {
56   char *name;
57   int (*init) __P((void));
58 };
59 
60 static struct bd_type bd_typelist[] =
61 {
62   {"powerbraille_40", bd_init_powerbraille_40},
63   {"powerbraille_80", bd_init_powerbraille_80},
64   {"navigator_40"   , bd_init_navigator_40}
65 };
66 
67 static void position_braille_cursor __P((void));
68 static int  initialize_braille_display_type __P((char *));
69 static int  open_braille_device __P(());
70 static int  load_braille_table __P((char *));
71 static void bd_signal __P((void));
72 static void bd_bc_left __P((void));
73 static void bd_bc_right __P((void));
74 static void bd_bc_up __P((void));
75 static void bd_bc_down __P((void));
76 static void bd_upper_left __P((void));
77 static void bd_upper_right __P((void));
78 static void bd_lower_left __P((void));
79 static void bd_lower_right __P((void));
80 static int  bd_do_search __P((int, int, int));
81 static void bd_normalize __P((int, int));
82 static void bd_readev_fn __P((struct event *, char *));
83 static void bd_writeev_fn __P((struct event *, char *));
84 static void bd_selectev_fn __P((struct event *, char *));
85 
86 static unsigned char btable_local [] =
87 {
88   0xC8,0xC1,0xC3,0xC9,0xD9,0xD1,0xCB,0xDB,
89   0xD3,0xCA,0xDA,0xC5,0xC7,0xCD,0xDD,0xD5,
90   0xCF,0xDF,0xD7,0xCE,0xDE,0xE5,0xE7,0xFA,
91   0xED,0xFD,0xF5,0xEA,0xF3,0xFB,0xD8,0xF8,
92   0x00,0x2E,0x10,0x3C,0x2B,0x29,0x2F,0x04,
93   0x37,0x3E,0x21,0x2C,0x20,0x24,0x28,0x0C,
94   0x34,0x02,0x06,0x12,0x32,0x22,0x16,0x36,
95   0x26,0x14,0x31,0x30,0x23,0x3F,0x1C,0x39,
96   0x48,0x41,0x43,0x49,0x59,0x51,0x4B,0x5B,
97   0x53,0x4A,0x5A,0x45,0x47,0x4D,0x5D,0x55,
98   0x4F,0x5F,0x57,0x4E,0x5E,0x65,0x67,0x7A,
99   0x6D,0x7D,0x75,0x6A,0x73,0x7B,0x58,0x38,
100   0x08,0x01,0x03,0x09,0x19,0x11,0x0B,0x1B,
101   0x13,0x0A,0x1A,0x05,0x07,0x0D,0x1D,0x15,
102   0x0F,0x1F,0x17,0x0E,0x1E,0x25,0x27,0x3A,
103   0x2D,0x3D,0x35,0x2A,0x33,0x3B,0x18,0x78,
104   0x88,0x81,0x83,0x89,0x99,0x91,0x8B,0x9B,
105   0x93,0x8A,0x9A,0x85,0x87,0x8D,0x9D,0x95,
106   0x8F,0x9F,0x97,0x8E,0x9E,0xA5,0xA7,0xBA,
107   0xAD,0xBD,0xB5,0xAA,0xB3,0xBB,0x98,0xB8,
108   0x40,0x6E,0x50,0x7C,0x6B,0x69,0x6F,0x44,
109   0x77,0x7E,0x61,0x6C,0x60,0x64,0x68,0x4C,
110   0x74,0x42,0x46,0x52,0x72,0x62,0x56,0x76,
111   0x66,0x54,0x71,0x70,0x63,0x7F,0x5C,0x79,
112   0xC0,0xEE,0xD0,0xFC,0xEB,0xE9,0xEF,0xC4,
113   0xF7,0xFE,0xE1,0xEC,0xE0,0xE4,0xE8,0xCC,
114   0xF4,0xC2,0xC6,0xD2,0xF2,0xE2,0xD6,0xF6,
115   0xE6,0xD4,0xF1,0xF0,0xE3,0xFF,0xDC,0xF9,
116   0x80,0xAE,0x90,0xBC,0xAB,0xA9,0xAF,0x84,
117   0xB7,0xBE,0xA1,0xAC,0xA0,0xA4,0xA8,0x8C,
118   0xB4,0x82,0x86,0x92,0xB2,0xA2,0x96,0xB6,
119   0xA6,0x94,0xB1,0xB0,0xA3,0xBF,0x9C,0xB9
120 };
121 
122 void
InitBraille()123 InitBraille()
124 {
125   bd.bd_start_braille=0;
126   bd.bd_port = 0;
127   bd.bd_braille_table = SaveStr("internal us-braille.tbl");
128   bd.bd_type = 0;
129   bd.bd_baud = 9600;
130   bd.bd_bell = 1;
131   bd.bd_eightdot = 1;
132   bd.bd_info = 0;
133   bd.bd_link = 1;
134   bd.bd_ncells = 0;
135   bd.bd_width = 0;
136   bd.bd_ncrc = 1;
137   bd.bd_scroll = 1;
138   bd.bd_skip = 0;
139   bd.bd_using_braille = 0;
140   bd.bd_obuflen = 0;
141   bd.bd_fd = -1;
142   bcopy((char *)btable_local, bd.bd_btable, 256);
143 }
144 
145 static int
initialize_braille_display_type(s)146 initialize_braille_display_type(s)
147 char *s;
148 {
149   int i;
150 
151   for (i = 0; i < sizeof(bd_typelist)/sizeof(*bd_typelist); i++)
152     if (!strcmp(s, bd_typelist[i].name))
153       break;
154   if (i == sizeof(bd_typelist)/sizeof(*bd_typelist))
155     {
156       Msg(0, "No entry for bd_type: %s ", s);
157       return -1;
158     }
159   bd.bd_type = bd_typelist[i].name;
160   if ((*bd_typelist[i].init)())
161     return -1;
162 
163   if (!bd.bd_width)
164     bd.bd_width = bd.bd_ncells;
165 
166   return 0;
167 }
168 
169 void
StartBraille()170 StartBraille()
171 {
172   bd.bd_dpy = displays;
173 
174   debug("StartBraille called\n");
175   evdeq(&bd.bd_readev);
176   evdeq(&bd.bd_writeev);
177   evdeq(&bd.bd_selectev);
178   bd.bd_using_braille = 0;
179 
180   if (!bd.bd_start_braille)
181     return;
182 
183   if (bd.bd_type == 0 || bd.bd_port == 0)
184     return;
185 
186   if (bd.bd_fd < 0 && open_braille_device())
187     {
188       Msg(0, "bd_port turned off");
189       free(bd.bd_port);
190       bd.bd_port = 0;
191       return;
192     }
193 
194   /* check if braille display is connected and turned on */
195   if (bd.bd_response_test())
196     {
197       Msg(0, "Make sure that braille display is connected and turned on. ");
198       Msg(0, "start_braille turned off");
199       bd.bd_start_braille = 0;
200     }
201   else
202     {
203       bd.bd_using_braille = 1;
204       bd.bd_readev.fd = bd.bd_writeev.fd = bd.bd_fd;
205       bd.bd_readev.type  = EV_READ;
206       bd.bd_writeev.type = EV_WRITE;
207       bd.bd_selectev.type = EV_ALWAYS;
208       bd.bd_readev.data = bd.bd_writeev.data = bd.bd_selectev.data = (char *)&bd;
209       bd.bd_readev.handler  = bd_readev_fn;
210       bd.bd_writeev.handler = bd_writeev_fn;
211       bd.bd_selectev.handler = bd_selectev_fn;
212       evenq(&bd.bd_readev);
213       bd.bd_writeev.condpos = &bd.bd_obuflen;
214       bd.bd_writeev.condneg = 0;
215       evenq(&bd.bd_writeev);
216       bd.bd_selectev.pri = -20;
217       evenq(&bd.bd_selectev);
218     }
219 }
220 
221 
222 static int
load_braille_table(tablename)223 load_braille_table(tablename)
224 char *tablename;
225 {
226   int i, j, c, p;
227   FILE *fp;
228   char buffer[80], a[10];
229 
230   if ((fp = secfopen(tablename, "r")) == 0)
231     {
232       Msg(errno, "Braille table not found: %s ", tablename);
233       return -1;
234     }
235   bzero(bd.bd_btable, 256);
236   /* format:
237    * Dec  Hex    Braille      Description
238    *  7   07    (12-45--8)    BEL
239    */
240   while (fgets(buffer, sizeof(buffer), fp))
241     {
242       if (buffer[0] == '#')
243 	continue;
244       sscanf(buffer,"%d %x %8s", &i, &j, a);
245       if (i < 0 || i > 255)
246 	continue;
247       for (j=1, p=1, c=0; j<9; j++, p*=2)
248 	if (a[j] == '0' + j)
249 	  c += p;
250       bd.bd_btable[i] = c;
251     }
252   fclose(fp);
253   return 0;
254 }
255 
256 
257 static int
open_braille_device(s)258 open_braille_device(s)
259 char *s;
260 {
261   char str[256];
262 
263   sprintf(str, "%d cs8 -istrip ixon ixoff", bd.bd_baud);
264   bd.bd_fd = OpenTTY(bd.bd_port, str);
265   if (bd.bd_fd == -1)
266     {
267       Msg(errno, "open comm port failed: %s ", bd.bd_port);
268       return -1;
269     }
270   fcntl(bd.bd_fd, F_SETFL, FNBLOCK);
271   return 0;
272 }
273 
274 
275 static void
position_braille_cursor()276 position_braille_cursor()
277 {
278   int  sx = bd.bd_sx;
279   int  bx = BD_FORE->w_bd_x;
280   int  eol = BD_FORE->w_width;
281   int  w = bd.bd_width;
282 
283   if (bd.bd_scroll)
284     bx = sx - w + bd.bd_ncrc;	/* keep rc centered in window */
285   else
286     bx = w * (int)(sx / w);	/* increase bc in integral steps */
287 
288   if (bx > eol - w)
289     bx = eol - w;
290   if (bx < 0)
291     bx = 0;
292   BD_FORE->w_bd_x = bx;
293   BD_FORE->w_bd_y = bd.bd_sy;
294 }
295 
296 
297 void
RefreshBraille()298 RefreshBraille()
299 {
300   int i, y, xs, xe;
301   int cursor_pos;
302 
303   if (!bd.bd_using_braille)
304     return;
305   if (!BD_FORE)
306     return;
307   bcopy(bd.bd_line, bd.bd_oline, bd.bd_ncells);
308   bd.bd_refreshing = 1;
309   flayer = bd.bd_dpy->d_forecv->c_layer;
310   bd.bd_sx = flayer->l_x;
311   bd.bd_sy = flayer->l_y;
312   display = bd.bd_dpy;
313   if ((D_obufp != D_obuf) && bd.bd_link)
314     {
315       /* jump to real cursor */
316       debug("calling position_braille_cursor\n");
317       position_braille_cursor();
318     }
319   bclear(bd.bd_line, bd.bd_ncells);
320 
321   y = BD_FORE->w_bd_y;
322   xs = BD_FORE->w_bd_x;
323 
324   if (bd.bd_info & 1)
325     {
326       sprintf(bd.bd_line, "%02d%02d", (BD_FORE->w_bd_x + 1) % 100, (BD_FORE->w_bd_y + 1) % 100);
327       bd.bd_line[4] = ' ';
328     }
329   if (bd.bd_info & 2)
330     {
331       sprintf(bd.bd_line + bd.bd_ncells - 4, "%02d%02d",(bd.bd_sx +1) % 100, (bd.bd_sy +1) % 100);
332     }
333 
334   xe = xs + bd.bd_width - 1;
335 
336   if (xs > flayer->l_width - 1)
337     xs = flayer->l_width - 1;
338   if (xe > flayer->l_width - 1)
339     xe = flayer->l_width - 1;
340 
341   if (D_status)
342     {
343       sprintf(bd.bd_line, "**%-*.*s", bd.bd_ncells - 2, bd.bd_ncells - 2, D_status_lastmsg ? D_status_lastmsg : "unknown msg");
344       xs = xe = -1;
345     }
346   else if (xs <= xe)
347     {
348       LayRedisplayLine(-1, xs, xe, 1);
349       LayRedisplayLine(y, xs, xe, 1);
350     }
351 
352   debug1("Braille: got >%s<\n", bd.bd_line);
353 
354   bd.bd_refreshing = 0;
355 
356   if (y == bd.bd_sy && xs <= bd.bd_sx && bd.bd_sx <= xe)
357     cursor_pos = bd.bd_sx - xs + (bd.bd_info & 1 ? 4 : 0);
358   else
359     cursor_pos = bd.bd_ncells;
360   for (i = 0; i < bd.bd_ncells; i++)
361     if (bd.bd_line[i] != bd.bd_oline[i])
362       break;
363   if (bd.bd_cursorpos != cursor_pos || i < bd.bd_ncells)
364     bd.write_line_braille(bd.bd_line, bd.bd_ncells, cursor_pos);
365   bd.bd_cursorpos = cursor_pos;
366 }
367 
368 
369 /**********************************************************************
370  *
371  */
372 
373 /*
374  * So, why is there a Flush() down below? The reason is simple: the
375  * cursor warp (if bd_link is on) checks the obuf to see if something
376  * happened. If there would be no Flush, screen would warp the
377  * bd cursor if a bd movement command tries to ring the bell.
378  * (In other words: this is a gross hack!)
379  */
380 static void
bd_signal()381 bd_signal()
382 {
383   if (!bd.bd_bell)
384     return;
385   display = bd.bd_dpy;
386   if (D_obufp != D_obuf)
387     AddCStr(D_BL);
388   else
389     {
390       AddCStr(D_BL);
391       Flush(0);
392     }
393 }
394 
395 static int
bd_do_search(y,xs,xe)396 bd_do_search(y, xs, xe)
397 int y, xs, xe;
398 {
399   int oy = BD_FORE->w_bd_y;
400 
401   if (!bd.bd_skip)	/* no skip mode, found it */
402     {
403       if (xs > xe)
404 	return 0;
405       bd.bd_searchmin = xs;
406       bd.bd_searchmax = xe;
407       return 1;
408     }
409   flayer = bd.bd_dpy->d_forecv->c_layer;
410   bd.bd_searchmax = -1;
411   bd.bd_searchmin = flayer->l_width;
412   if (xs <= xe)
413     {
414       BD_FORE->w_bd_y = y;	/* stupid hack */
415       bd.bd_refreshing = bd.bd_searching = 1;
416       bd.bd_searchstart = xs;
417       bd.bd_searchend   = xe;
418       LayRedisplayLine(-1, xs, xe, 1);
419       LayRedisplayLine(y, xs, xe, 1);
420       bd.bd_refreshing = bd.bd_searching = 0;
421       BD_FORE->w_bd_y = oy;
422     }
423   return bd.bd_searchmax >= 0;
424 }
425 
426 static void
bd_normalize(x,y)427 bd_normalize(x, y)
428 int x, y;
429 {
430   if (x > BD_FORE->w_width - bd.bd_width)
431     x = BD_FORE->w_width - bd.bd_width;
432   if (x < 0)
433     x = 0;
434   if (y < 0)
435     {
436       bd_signal();
437       y = 0;
438     }
439   if (y >= BD_FORE->w_height)
440     {
441       bd_signal();
442       y = BD_FORE->w_height - 1;
443     }
444   if (x != BD_FORE->w_bd_x || y != BD_FORE->w_bd_y)
445     bd.bd_moved = 1;
446   BD_FORE->w_bd_x = x;
447   BD_FORE->w_bd_y = y;
448 }
449 
450 static void
bd_bc_left()451 bd_bc_left()
452 {
453   int bx = BD_FORE->w_bd_x, by = BD_FORE->w_bd_y;
454   int ex;
455 
456   ex = bx - 1;
457   bx = 0;
458   for (; by >= 0; by--)
459     {
460       if (bd_do_search(by, 0, ex))
461 	{
462 	  if (!bd.bd_skip && by != BD_FORE->w_bd_y)
463 	    bd_signal();
464 	  bx = bd.bd_searchmax + 1 - bd.bd_width;
465 	  break;
466 	}
467       ex = BD_FORE->w_width - 1;
468     }
469   bd_normalize(bx, by);
470 }
471 
472 static void
bd_bc_right()473 bd_bc_right()
474 {
475   int bx = BD_FORE->w_bd_x, by = BD_FORE->w_bd_y;
476   int sx;
477 
478   sx = bx + bd.bd_width;
479   bx = BD_FORE->w_width - bd.bd_width;
480   for (; by < BD_FORE->w_height; by++)
481     {
482       if (bd_do_search(by, sx, BD_FORE->w_width - 1))
483 	{
484 	  if (!bd.bd_skip && by != BD_FORE->w_bd_y)
485 	    bd_signal();
486 	  bx = bd.bd_searchmin;
487 	  break;
488 	}
489       sx = 0;
490     }
491   bd_normalize(bx, by);
492 }
493 
494 static void
bd_bc_up()495 bd_bc_up()
496 {
497   int bx = BD_FORE->w_bd_x, by = BD_FORE->w_bd_y;
498 
499   for (by--; by >= 0; by--)
500     if (bd_do_search(by, bx, bx + bd.bd_width - 1))
501       break;
502   bd_normalize(bx, by);
503 }
504 
505 static void
bd_bc_down()506 bd_bc_down()
507 {
508   int bx = BD_FORE->w_bd_x, by = BD_FORE->w_bd_y;
509 
510   for (by++; by < BD_FORE->w_height; by++)
511     if (bd_do_search(by, bx, bx + bd.bd_width - 1))
512       break;
513   bd_normalize(bx, by);
514 }
515 
516 
517 static void
bd_upper_left()518 bd_upper_left()
519 {
520   bd_normalize(0, 0);
521 }
522 
523 
524 static void
bd_upper_right()525 bd_upper_right()
526 {
527   bd_normalize(BD_FORE->w_width - bd.bd_width, 0);
528 }
529 
530 
531 static void
bd_lower_left()532 bd_lower_left()
533 {
534   bd_normalize(0, BD_FORE->w_height - 1);
535 }
536 
537 
538 static void
bd_lower_right()539 bd_lower_right()
540 {
541   bd_normalize(BD_FORE->w_width - bd.bd_width, BD_FORE->w_height -1);
542 }
543 
544 /**********************************************************************
545  *
546  */
547 
548 
549 static void
bd_check(x,c)550 bd_check(x, c)
551 int x, c;
552 {
553   if (c == ' ')
554     return;
555   if (x < bd.bd_searchstart || x > bd.bd_searchend)
556     return;
557   if (x > bd.bd_searchmax)
558     bd.bd_searchmax = x;
559   if (x < bd.bd_searchmin)
560     bd.bd_searchmin = x;
561 }
562 
563 
564 
565 /*ARGSUSED*/
566 void
BGotoPos(la,x,y)567 BGotoPos(la, x, y)
568 struct layer *la;
569 int x, y;
570 {
571 }
572 
573 /*ARGSUSED*/
574 void
BCDisplayLine(la,ml,y,xs,xe,isblank)575 BCDisplayLine(la, ml, y, xs, xe, isblank)
576 struct layer *la;
577 struct mline *ml;
578 int y, xs, xe;
579 int isblank;
580 {
581   int x;
582   int sx, ex;
583   char *l;
584 
585   if (y != BD_FORE->w_bd_y)
586     return;
587   if (bd.bd_searching)
588     {
589       for (x = xs; x <= xe; x++)
590 	bd_check(x, ml->image[x]);
591       return;
592     }
593   l = bd.bd_line;
594   sx = BD_FORE->w_bd_x;
595   ex = sx + bd.bd_width - 1;
596   if (bd.bd_info & 1)
597     l += 4;
598   for (x = xs; x <= xe; x++)
599     if (x >= sx && x <= ex)
600       l[x - sx] = ml->image[x];
601 }
602 
603 /*ARGSUSED*/
604 void
BPutChar(la,c,x,y)605 BPutChar(la, c, x, y)
606 struct layer *la;
607 struct mchar *c;
608 int x, y;
609 {
610   int sx, ex;
611   char *l;
612 
613   if (y != BD_FORE->w_bd_y)
614     return;
615   if (bd.bd_searching)
616     {
617       bd_check(x, c->image);
618       return;
619     }
620   l = bd.bd_line;
621   sx = BD_FORE->w_bd_x;
622   ex = sx + bd.bd_width - 1;
623   if (bd.bd_info & 1)
624     l += 4;
625   if (x >= sx && x <= ex)
626     l[x - sx] = c->image;
627 }
628 
629 /*ARGSUSED*/
630 void
BPutStr(la,s,n,r,x,y)631 BPutStr(la, s, n, r, x, y)
632 struct layer *la;
633 char *s;
634 int n;
635 struct mchar *r;
636 int x, y;
637 {
638   int sx, ex;
639   char *l;
640 
641   if (y != BD_FORE->w_bd_y)
642     return;
643   if (bd.bd_searching)
644     {
645       for (; n > 0; n--, s++, x++)
646 	bd_check(x, *s);
647       return;
648     }
649   l = bd.bd_line;
650   sx = BD_FORE->w_bd_x;
651   ex = sx + bd.bd_width - 1;
652   if (bd.bd_info & 1)
653     l += 4;
654   for (; n > 0; n--, s++, x++)
655     if (x >= sx && x <= ex)
656       l[x - sx] = *s;
657 }
658 
659 
660 
661 /**********************************************************************
662  *
663  */
664 
665 static char *infonames[] = {"none", "bc", "sc", "bc+sc"};
666 
667 void
DoBrailleAction(act,msgok)668 DoBrailleAction(act, msgok)
669 struct action *act;
670 int msgok;
671 {
672   int nr, dosig;
673   int n, l, o;
674   char *s, **args;
675   struct stat st;
676 
677   nr = act->nr;
678   args = act->args;
679   dosig = display && !*rc_name;
680 
681   switch(nr)
682     {
683     case RC_BD_BELL:
684       if (ParseSwitch(act, &bd.bd_bell) || !msgok)
685 	{
686 	  bd_signal();
687 	  break;
688 	}
689       Msg(0, bd.bd_bell ? "bd_bell is on." : "bd_bell is off.");
690       break;
691 
692     case RC_BD_EIGHTDOT:
693       if (ParseSwitch(act, &bd.bd_eightdot) || !msgok)
694 	break;
695       Msg(0, "switched to %d-dots system.", bd.bd_eightdot ? 8 : 6);
696       break;
697 
698     case RC_BD_INFO:
699       n = bd.bd_info;
700       if (*args)
701 	{
702 	  if (strlen(*args) == 4)
703 	    n = args[0][n] - '0';
704 	  else if (ParseNum(act, &n))
705 	    break;
706 	}
707       if (n < 0 || n > 3)
708 	{
709           Msg(0, "Out of range; 0 <= bd_info >= 3 ");
710 	  break;
711 	}
712       /* bd_width at the beginning is unknown */
713       if (bd.bd_width == 0)
714         break;
715 
716       o = (bd.bd_info * 2 + 2) & 12;
717       l = (n * 2 + 2) & 12;
718       if (l >= bd.bd_ncells)
719 	{
720 	  Msg(0, "bd_info is too large for braille display.");
721 	  break;
722 	}
723       if (l >= bd.bd_width + o)
724 	{
725 	  Msg(0, "bd_info is too large for bd_width.");
726 	  break;
727 	}
728       bd.bd_width += o - l;
729       bd.bd_info = n;
730 
731       if (msgok)
732 	Msg(0, "bd_info is %s.", infonames[n]);
733       position_braille_cursor();
734       break;
735 
736     case RC_BD_LINK:
737       if (*args == 0 && bd.bd_moved)
738 	bd.bd_link = 0;
739       if (ParseSwitch(act, &bd.bd_link))
740 	break;
741       if (bd.bd_link)
742 	{
743 	  bd.bd_moved = 0;
744 	  if (dosig)
745 	    bd_signal();
746 	  position_braille_cursor();
747 	}
748       if (msgok)
749         Msg(0, bd.bd_link ? "bd_link is on." : "bd_link is off.");
750       break;
751 
752     case RC_BD_SKIP:
753       if (ParseSwitch(act, &bd.bd_skip))
754 	break;
755       if (bd.bd_skip && dosig)
756 	bd_signal();
757       if (msgok)
758         Msg(0, bd.bd_skip ? "bd_skip is on." : "bd_skip is off.");
759       break;
760 
761     case RC_BD_SCROLL:
762       if (ParseSwitch(act, &bd.bd_scroll) || !msgok)
763 	{
764 	  position_braille_cursor();
765           break;
766 	}
767       Msg(0, bd.bd_scroll ? "bd_scroll is on." : "bd_scroll is off.");
768       break;
769 
770     case RC_BD_NCRC:
771       n = bd.bd_ncrc;
772       if (*args)
773 	{
774 	  if (args[0][0] == '+')
775 	    n = (n + atoi(*args + 1)) % bd.bd_width + 1;
776 	  else if (args[0][0] == '-')
777 	    n = (n - atoi(*args + 1)) % bd.bd_width + 1;
778 	  else if (ParseNum(act, &n))
779 	    break;
780 	}
781       if (n < 1 ||  n > bd.bd_width)
782 	{
783 	  Msg(0, "Out of range; 1 <= bd_ncrc >= %d", bd.bd_width);
784 	  break;
785 	}
786       bd.bd_ncrc = n;
787       if (msgok)
788 	Msg(0, "bd_ncrc status is: %d ", bd.bd_ncrc);
789       position_braille_cursor();
790       break;
791 
792     case RC_BD_BRAILLE_TABLE:
793       s = 0;
794       if (*args)
795 	{
796 	  if (ParseSaveStr(act, &s))
797 	    break;
798 	  if (load_braille_table(s))
799 	    {
800 	      free(s);
801 	      break;
802 	    }
803 	  if (bd.bd_braille_table)
804 	    free(bd.bd_braille_table);
805 	  bd.bd_braille_table = s;
806 	}
807       if (msgok)
808 	Msg(0, "bd_braille_table is: %s ", bd.bd_braille_table);
809       break;
810 
811     case RC_BD_PORT:
812       s = 0;
813       if (*args)
814 	{
815           if (ParseSaveStr(act, &s))
816 	    break;
817 
818 	  if (stat(s, &st) || !S_ISCHR(st.st_mode) || access(s, R_OK|W_OK))
819 	    {
820 	      Msg(0, "Cannot access braille device port %s", s);
821 	      free(s);
822 	      break;
823 	    }
824 	  if (bd.bd_fd >= 0)
825 	    close(bd.bd_fd);
826 	  bd.bd_fd = -1;
827 	  if (bd.bd_port)
828 	    free(bd.bd_port);
829 	  bd.bd_port = s;
830 	}
831       if (msgok)
832 	Msg(0, "bd_port is: %s ", bd.bd_port ? bd.bd_port : "not set");
833       StartBraille();
834       break;
835 
836     case RC_BD_TYPE:
837       s = 0;
838       if (*args)
839         if (ParseSaveStr(act, &s) || initialize_braille_display_type(s))
840 	  break;
841       if (msgok)
842 	Msg(0, "bd_type is: %s ", bd.bd_type ? bd.bd_type : "not set");
843       StartBraille();
844       break;
845 
846     case RC_BD_START_BRAILLE:
847       if (ParseSwitch(act, &bd.bd_start_braille))
848 	break;
849       if (msgok)
850         Msg(0, bd.bd_start_braille ? "bd_start_braille is on." : "bd_start_braille is off.");
851       StartBraille();
852       break;
853 
854     case RC_BD_WIDTH:
855       n = bd.bd_width;
856       if (*args)
857 	{
858 	  if (ParseNum(act, &n))
859 	    break;
860 	}
861       if (n <= 0)
862 	{
863 	  Msg(0, "Invalid value for bd_width: %d ", n);
864 	  break;
865 	}
866       l = (bd.bd_info * 2 + 2) & 12;
867       if (n > bd.bd_ncells - l || n < l)
868 	{
869 	  Msg(0, "bd_info is too large for bd_width.");
870 	  break;
871 	}
872       bd.bd_width = n;
873       if (msgok)
874 	Msg(0, "bd_width is: %d ", bd.bd_width);
875       break;
876 
877     case RC_BD_BC_LEFT:
878       bd_bc_left();
879       break;
880 
881     case RC_BD_BC_RIGHT:
882       bd_bc_right();
883       break;
884 
885     case RC_BD_BC_UP:
886       bd_bc_up();
887       break;
888 
889     case RC_BD_BC_DOWN:
890       bd_bc_down();
891       break;
892 
893     case RC_BD_UPPER_LEFT:
894       bd_upper_left();
895       break;
896 
897     case RC_BD_UPPER_RIGHT:
898       bd_upper_right();
899       break;
900 
901     case RC_BD_LOWER_LEFT:
902       bd_lower_left();
903       break;
904 
905     case RC_BD_LOWER_RIGHT:
906       bd_lower_right();
907       break;
908 
909     default:
910       break;
911     }
912 }
913 
914 static void
bd_readev_fn(ev,data)915 bd_readev_fn(ev, data)
916 struct event *ev;
917 char *data;
918 {
919   bd.buttonpress();
920 }
921 
922 static void
bd_writeev_fn(ev,data)923 bd_writeev_fn(ev, data)
924 struct event *ev;
925 char *data;
926 {
927   int len;
928 
929   if (bd.bd_obuflen == 0)
930     return;
931   if ((len = write(bd.bd_fd, bd.bd_obuf, bd.bd_obuflen)) < 0)
932     len = bd.bd_obuflen;	/* dead braille display */
933   if ((bd.bd_obuflen -= len))
934     bcopy(bd.bd_obuf + len, bd.bd_obuf, bd.bd_obuflen);
935 }
936 
937 static void
bd_selectev_fn(ev,data)938 bd_selectev_fn(ev, data)
939 struct event *ev;
940 char *data;
941 {
942   RefreshBraille();
943 }
944 
945 #endif /* HAVE_BRAILLE */
946