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