2 * A braille interface to unix tty terminals
4 * Authors: Hadi Bargi Rangin bargi@dots.physics.orst.edu
5 * Bill Barry barryb@dots.physics.orst.edu
7 * Copyright (c) 1995 by Science Access Project, Oregon State University.
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)
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.
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 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 ****************************************************************
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));
44 extern struct layer
*flayer
;
45 extern struct display
*displays
, *display
;
51 /* global variables */
53 struct braille_display bd
;
57 int (*init
) __P((void));
60 static struct bd_type bd_typelist
[] =
62 {"powerbraille_40", bd_init_powerbraille_40
},
63 {"powerbraille_80", bd_init_powerbraille_80
},
64 {"navigator_40" , bd_init_navigator_40
}
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 *));
86 static unsigned char btable_local
[] =
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
125 bd
.bd_start_braille
=0;
127 bd
.bd_braille_table
= SaveStr("internal us-braille.tbl");
139 bd
.bd_using_braille
= 0;
142 bcopy((char *)btable_local
, bd
.bd_btable
, 256);
146 initialize_braille_display_type(s
)
151 for (i
= 0; i
< sizeof(bd_typelist
)/sizeof(*bd_typelist
); i
++)
152 if (!strcmp(s
, bd_typelist
[i
].name
))
154 if (i
== sizeof(bd_typelist
)/sizeof(*bd_typelist
))
156 Msg(0, "No entry for bd_type: %s ", s
);
159 bd
.bd_type
= bd_typelist
[i
].name
;
160 if ((*bd_typelist
[i
].init
)())
164 bd
.bd_width
= bd
.bd_ncells
;
172 bd
.bd_dpy
= displays
;
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;
180 if (!bd
.bd_start_braille
)
183 if (bd
.bd_type
== 0 || bd
.bd_port
== 0)
186 if (bd
.bd_fd
< 0 && open_braille_device())
188 Msg(0, "bd_port turned off");
194 /* check if braille display is connected and turned on */
195 if (bd
.bd_response_test())
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;
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
);
223 load_braille_table(tablename
)
228 char buffer
[80], a
[10];
230 if ((fp
= secfopen(tablename
, "r")) == 0)
232 Msg(errno
, "Braille table not found: %s ", tablename
);
235 bzero(bd
.bd_btable
, 256);
237 * Dec Hex Braille Description
238 * 7 07 (12-45--8) BEL
240 while (fgets(buffer
, sizeof(buffer
), fp
))
242 if (buffer
[0] == '#')
244 sscanf(buffer
,"%d %x %8s", &i
, &j
, a
);
245 if (i
< 0 || i
> 255)
247 for (j
=1, p
=1, c
=0; j
<9; j
++, p
*=2)
258 open_braille_device(s
)
263 sprintf(str
, "%d cs8 -istrip ixon ixoff", bd
.bd_baud
);
264 bd
.bd_fd
= OpenTTY(bd
.bd_port
, str
);
267 Msg(errno
, "open comm port failed: %s ", bd
.bd_port
);
270 fcntl(bd
.bd_fd
, F_SETFL
, FNBLOCK
);
276 position_braille_cursor()
279 int bx
= BD_FORE
->w_bd_x
;
280 int eol
= BD_FORE
->w_width
;
284 bx
= sx
- w
+ bd
.bd_ncrc
; /* keep rc centered in window */
286 bx
= w
* (int)(sx
/ w
); /* increase bc in integral steps */
292 BD_FORE
->w_bd_x
= bx
;
293 BD_FORE
->w_bd_y
= bd
.bd_sy
;
303 if (!bd
.bd_using_braille
)
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
;
313 if ((D_obufp
!= D_obuf
) && bd
.bd_link
)
315 /* jump to real cursor */
316 debug("calling position_braille_cursor\n");
317 position_braille_cursor();
319 bclear(bd
.bd_line
, bd
.bd_ncells
);
322 xs
= BD_FORE
->w_bd_x
;
326 sprintf(bd
.bd_line
, "%02d%02d", (BD_FORE
->w_bd_x
+ 1) % 100, (BD_FORE
->w_bd_y
+ 1) % 100);
331 sprintf(bd
.bd_line
+ bd
.bd_ncells
- 4, "%02d%02d",(bd
.bd_sx
+1) % 100, (bd
.bd_sy
+1) % 100);
334 xe
= xs
+ bd
.bd_width
- 1;
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;
343 sprintf(bd
.bd_line
, "**%-*.*s", bd
.bd_ncells
- 2, bd
.bd_ncells
- 2, D_status_lastmsg
? D_status_lastmsg
: "unknown msg");
348 LayRedisplayLine(-1, xs
, xe
, 1);
349 LayRedisplayLine(y
, xs
, xe
, 1);
352 debug1("Braille: got >%s<\n", bd
.bd_line
);
354 bd
.bd_refreshing
= 0;
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);
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
])
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
;
369 /**********************************************************************
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!)
386 if (D_obufp
!= D_obuf
)
396 bd_do_search(y
, xs
, xe
)
399 int oy
= BD_FORE
->w_bd_y
;
401 if (!bd
.bd_skip
) /* no skip mode, found it */
405 bd
.bd_searchmin
= xs
;
406 bd
.bd_searchmax
= xe
;
409 flayer
= bd
.bd_dpy
->d_forecv
->c_layer
;
410 bd
.bd_searchmax
= -1;
411 bd
.bd_searchmin
= flayer
->l_width
;
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
;
423 return bd
.bd_searchmax
>= 0;
430 if (x
> BD_FORE
->w_width
- bd
.bd_width
)
431 x
= BD_FORE
->w_width
- bd
.bd_width
;
439 if (y
>= BD_FORE
->w_height
)
442 y
= BD_FORE
->w_height
- 1;
444 if (x
!= BD_FORE
->w_bd_x
|| y
!= BD_FORE
->w_bd_y
)
453 int bx
= BD_FORE
->w_bd_x
, by
= BD_FORE
->w_bd_y
;
458 for (; by
>= 0; by
--)
460 if (bd_do_search(by
, 0, ex
))
462 if (!bd
.bd_skip
&& by
!= BD_FORE
->w_bd_y
)
464 bx
= bd
.bd_searchmax
+ 1 - bd
.bd_width
;
467 ex
= BD_FORE
->w_width
- 1;
469 bd_normalize(bx
, by
);
475 int bx
= BD_FORE
->w_bd_x
, by
= BD_FORE
->w_bd_y
;
478 sx
= bx
+ bd
.bd_width
;
479 bx
= BD_FORE
->w_width
- bd
.bd_width
;
480 for (; by
< BD_FORE
->w_height
; by
++)
482 if (bd_do_search(by
, sx
, BD_FORE
->w_width
- 1))
484 if (!bd
.bd_skip
&& by
!= BD_FORE
->w_bd_y
)
486 bx
= bd
.bd_searchmin
;
491 bd_normalize(bx
, by
);
497 int bx
= BD_FORE
->w_bd_x
, by
= BD_FORE
->w_bd_y
;
499 for (by
--; by
>= 0; by
--)
500 if (bd_do_search(by
, bx
, bx
+ bd
.bd_width
- 1))
502 bd_normalize(bx
, by
);
508 int bx
= BD_FORE
->w_bd_x
, by
= BD_FORE
->w_bd_y
;
510 for (by
++; by
< BD_FORE
->w_height
; by
++)
511 if (bd_do_search(by
, bx
, bx
+ bd
.bd_width
- 1))
513 bd_normalize(bx
, by
);
527 bd_normalize(BD_FORE
->w_width
- bd
.bd_width
, 0);
534 bd_normalize(0, BD_FORE
->w_height
- 1);
541 bd_normalize(BD_FORE
->w_width
- bd
.bd_width
, BD_FORE
->w_height
-1);
544 /**********************************************************************
555 if (x
< bd
.bd_searchstart
|| x
> bd
.bd_searchend
)
557 if (x
> bd
.bd_searchmax
)
559 if (x
< bd
.bd_searchmin
)
575 BCDisplayLine(la
, ml
, y
, xs
, xe
, isblank
)
585 if (y
!= BD_FORE
->w_bd_y
)
589 for (x
= xs
; x
<= xe
; x
++)
590 bd_check(x
, ml
->image
[x
]);
594 sx
= BD_FORE
->w_bd_x
;
595 ex
= sx
+ bd
.bd_width
- 1;
598 for (x
= xs
; x
<= xe
; x
++)
599 if (x
>= sx
&& x
<= ex
)
600 l
[x
- sx
] = ml
->image
[x
];
605 BPutChar(la
, c
, x
, y
)
613 if (y
!= BD_FORE
->w_bd_y
)
617 bd_check(x
, c
->image
);
621 sx
= BD_FORE
->w_bd_x
;
622 ex
= sx
+ bd
.bd_width
- 1;
625 if (x
>= sx
&& x
<= ex
)
626 l
[x
- sx
] = c
->image
;
631 BPutStr(la
, s
, n
, r
, x
, y
)
641 if (y
!= BD_FORE
->w_bd_y
)
645 for (; n
> 0; n
--, s
++, x
++)
650 sx
= BD_FORE
->w_bd_x
;
651 ex
= sx
+ bd
.bd_width
- 1;
654 for (; n
> 0; n
--, s
++, x
++)
655 if (x
>= sx
&& x
<= ex
)
661 /**********************************************************************
665 static char *infonames
[] = {"none", "bc", "sc", "bc+sc"};
668 DoBrailleAction(act
, msgok
)
679 dosig
= display
&& !*rc_name
;
684 if (ParseSwitch(act
, &bd
.bd_bell
) || !msgok
)
689 Msg(0, bd
.bd_bell
? "bd_bell is on." : "bd_bell is off.");
693 if (ParseSwitch(act
, &bd
.bd_eightdot
) || !msgok
)
695 Msg(0, "switched to %d-dots system.", bd
.bd_eightdot
? 8 : 6);
702 if (strlen(*args
) == 4)
703 n
= args
[0][n
] - '0';
704 else if (ParseNum(act
, &n
))
709 Msg(0, "Out of range; 0 <= bd_info >= 3 ");
712 /* bd_width at the beginning is unknown */
713 if (bd
.bd_width
== 0)
716 o
= (bd
.bd_info
* 2 + 2) & 12;
717 l
= (n
* 2 + 2) & 12;
718 if (l
>= bd
.bd_ncells
)
720 Msg(0, "bd_info is too large for braille display.");
723 if (l
>= bd
.bd_width
+ o
)
725 Msg(0, "bd_info is too large for bd_width.");
728 bd
.bd_width
+= o
- l
;
732 Msg(0, "bd_info is %s.", infonames
[n
]);
733 position_braille_cursor();
737 if (*args
== 0 && bd
.bd_moved
)
739 if (ParseSwitch(act
, &bd
.bd_link
))
746 position_braille_cursor();
749 Msg(0, bd
.bd_link
? "bd_link is on." : "bd_link is off.");
753 if (ParseSwitch(act
, &bd
.bd_skip
))
755 if (bd
.bd_skip
&& dosig
)
758 Msg(0, bd
.bd_skip
? "bd_skip is on." : "bd_skip is off.");
762 if (ParseSwitch(act
, &bd
.bd_scroll
) || !msgok
)
764 position_braille_cursor();
767 Msg(0, bd
.bd_scroll
? "bd_scroll is on." : "bd_scroll is off.");
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
))
781 if (n
< 1 || n
> bd
.bd_width
)
783 Msg(0, "Out of range; 1 <= bd_ncrc >= %d", bd
.bd_width
);
788 Msg(0, "bd_ncrc status is: %d ", bd
.bd_ncrc
);
789 position_braille_cursor();
792 case RC_BD_BRAILLE_TABLE
:
796 if (ParseSaveStr(act
, &s
))
798 if (load_braille_table(s
))
803 if (bd
.bd_braille_table
)
804 free(bd
.bd_braille_table
);
805 bd
.bd_braille_table
= s
;
808 Msg(0, "bd_braille_table is: %s ", bd
.bd_braille_table
);
815 if (ParseSaveStr(act
, &s
))
818 if (stat(s
, &st
) || !S_ISCHR(st
.st_mode
) || access(s
, R_OK
|W_OK
))
820 Msg(0, "Cannot access braille device port %s", s
);
832 Msg(0, "bd_port is: %s ", bd
.bd_port
? bd
.bd_port
: "not set");
839 if (ParseSaveStr(act
, &s
) || initialize_braille_display_type(s
))
842 Msg(0, "bd_type is: %s ", bd
.bd_type
? bd
.bd_type
: "not set");
846 case RC_BD_START_BRAILLE
:
847 if (ParseSwitch(act
, &bd
.bd_start_braille
))
850 Msg(0, bd
.bd_start_braille
? "bd_start_braille is on." : "bd_start_braille is off.");
858 if (ParseNum(act
, &n
))
863 Msg(0, "Invalid value for bd_width: %d ", n
);
866 l
= (bd
.bd_info
* 2 + 2) & 12;
867 if (n
> bd
.bd_ncells
- l
|| n
< l
)
869 Msg(0, "bd_info is too large for bd_width.");
874 Msg(0, "bd_width is: %d ", bd
.bd_width
);
893 case RC_BD_UPPER_LEFT
:
897 case RC_BD_UPPER_RIGHT
:
901 case RC_BD_LOWER_LEFT
:
905 case RC_BD_LOWER_RIGHT
:
915 bd_readev_fn(ev
, data
)
923 bd_writeev_fn(ev
, data
)
929 if (bd
.bd_obuflen
== 0)
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
);
938 bd_selectev_fn(ev
, data
)
945 #endif /* HAVE_BRAILLE */