~ubuntu-branches/ubuntu/trusty/screen/trusty-backports

1 by Nathaniel McCallum
Import upstream version 4.0.2
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 2, 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, write to the
22
 * Free Software Foundation, Inc.,
23
 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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
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 
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
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 
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 
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
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
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
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();
392
    }
393
}
394
395
static int
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
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
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
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
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
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
518
bd_upper_left()
519
{
520
  bd_normalize(0, 0);
521
}
522
523
524
static void
525
bd_upper_right()
526
{
527
  bd_normalize(BD_FORE->w_width - bd.bd_width, 0);
528
}
529
530
531
static void
532
bd_lower_left()
533
{
534
  bd_normalize(0, BD_FORE->w_height - 1);
535
}
536
537
538
static void
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
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
567
BGotoPos(la, x, y)
568
struct layer *la;
569
int x, y;
570
{
571
}
572
573
/*ARGSUSED*/
574
void
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
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
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
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
915
bd_readev_fn(ev, data)
916
struct event *ev;
917
char *data;
918
{
919
  bd.buttonpress();
920
}
921
922
static void
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
938
bd_selectev_fn(ev, data)
939
struct event *ev;
940
char *data;
941
{
942
  RefreshBraille();
943
}
944
945
#endif /* HAVE_BRAILLE */