• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* speakup.c
2  * review functions for the speakup screen review package.
3  * originally written by: Kirk Reiser and Andy Berdan.
4  *
5  * extensively modified by David Borowski.
6  *
7  ** Copyright (C) 1998  Kirk Reiser.
8  *  Copyright (C) 2003  David Borowski.
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 of the License, or
13  *  (at your option) 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; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24 
25 #include <linux/kernel.h>
26 #include <linux/vt.h>
27 #include <linux/tty.h>
28 #include <linux/mm.h>		/* __get_free_page() and friends */
29 #include <linux/vt_kern.h>
30 #include <linux/ctype.h>
31 #include <linux/selection.h>
32 #include <linux/unistd.h>
33 #include <linux/jiffies.h>
34 #include <linux/kthread.h>
35 #include <linux/keyboard.h>	/* for KT_SHIFT */
36 #include <linux/kbd_kern.h>	/* for vc_kbd_* and friends */
37 #include <linux/input.h>
38 #include <linux/kmod.h>
39 
40 #include <linux/bootmem.h>	/* for alloc_bootmem */
41 
42 /* speakup_*_selection */
43 #include <linux/module.h>
44 #include <linux/sched.h>
45 #include <linux/slab.h>
46 #include <linux/types.h>
47 #include <linux/consolemap.h>
48 
49 #include <linux/spinlock.h>
50 #include <linux/notifier.h>
51 
52 #include <linux/uaccess.h>	/* copy_from|to|user() and others */
53 
54 #include "spk_priv.h"
55 #include "speakup.h"
56 
57 #define MAX_DELAY msecs_to_jiffies(500)
58 #define MINECHOCHAR SPACE
59 
60 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
61 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
62 MODULE_DESCRIPTION("Speakup console speech");
63 MODULE_LICENSE("GPL");
64 MODULE_VERSION(SPEAKUP_VERSION);
65 
66 char *synth_name;
67 module_param_named(synth, synth_name, charp, S_IRUGO);
68 module_param_named(quiet, quiet_boot, bool, S_IRUGO);
69 
70 MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
71 MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
72 
73 special_func special_handler;
74 
75 short pitch_shift, synth_flags;
76 static char buf[256];
77 int attrib_bleep, bleeps, bleep_time = 10;
78 int no_intr, spell_delay;
79 int key_echo, say_word_ctl;
80 int say_ctrl, bell_pos;
81 short punc_mask;
82 int punc_level, reading_punc;
83 char str_caps_start[MAXVARLEN + 1] = "\0", str_caps_stop[MAXVARLEN + 1] = "\0";
84 const struct st_bits_data punc_info[] = {
85 	{"none", "", 0},
86 	{"some", "/$%&@", SOME},
87 	{"most", "$%&#()=+*/@^<>|\\", MOST},
88 	{"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
89 	{"delimiters", "", B_WDLM},
90 	{"repeats", "()", CH_RPT},
91 	{"extended numeric", "", B_EXNUM},
92 	{"symbols", "", B_SYM},
93 	{0, 0}
94 };
95 
96 static char mark_cut_flag;
97 #define MAX_KEY 160
98 u_char *our_keys[MAX_KEY], *shift_table;
99 u_char key_buf[600];
100 const u_char key_defaults[] = {
101 #include "speakupmap.h"
102 };
103 
104 /* Speakup Cursor Track Variables */
105 static int cursor_track = 1, prev_cursor_track = 1;
106 
107 /* cursor track modes, must be ordered same as cursor_msgs */
108 enum {
109 	CT_Off = 0,
110 	CT_On,
111 	CT_Highlight,
112 	CT_Window,
113 	CT_Max
114 };
115 #define read_all_mode CT_Max
116 
117 static struct tty_struct *tty;
118 
119 static void spkup_write(const char *in_buf, int count);
120 
121 static char *phonetic[] = {
122 	"alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
123 	"india", "juliett", "keelo", "leema", "mike", "november", "oscar",
124 	    "papa",
125 	"keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
126 	"x ray", "yankee", "zulu"
127 };
128 
129 /* array of 256 char pointers (one for each character description)
130  * initialized to default_chars and user selectable via
131  * /proc/speakup/characters */
132 char *characters[256];
133 
134 char *default_chars[256] = {
135 /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
136 /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
137 /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
138 /*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
139 	    "control",
140 /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
141 	    "tick",
142 /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
143 	    "dot",
144 	"slash",
145 /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
146 	"eight", "nine",
147 /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
148 /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
149 /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
150 /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
151 /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
152 	    "caret",
153 	"line",
154 /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
155 /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
156 /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
157 /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
158 /*127*/ "del", "control", "control", "control", "control", "control",
159 	    "control", "control", "control", "control", "control",
160 /*138*/ "control", "control", "control", "control", "control",
161 	    "control", "control", "control", "control", "control",
162 	    "control", "control",
163 /*150*/ "control", "control", "control", "control", "control",
164 	    "control", "control", "control", "control", "control",
165 /*160*/ "nbsp", "inverted bang",
166 /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
167 /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
168 /*172*/ "not", "soft hyphen", "registered", "macron",
169 /*176*/ "degrees", "plus or minus", "super two", "super three",
170 /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
171 /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
172 /*188*/ "one quarter", "one half", "three quarters",
173 	    "inverted question",
174 /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
175 	    "A RING",
176 /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
177 	    "E OOMLAUT",
178 /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
179 	    "N TILDE",
180 /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
181 /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
182 	    "U CIRCUMFLEX",
183 /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
184 /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
185 /*230*/ "ae", "c cidella", "e grave", "e acute",
186 /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
187 	    "i circumflex",
188 /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
189 	    "o circumflex",
190 /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
191 	    "u acute",
192 /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
193 };
194 
195 /* array of 256 u_short (one for each character)
196  * initialized to default_chartab and user selectable via
197  * /sys/module/speakup/parameters/chartab */
198 u_short spk_chartab[256];
199 
200 static u_short default_chartab[256] = {
201 	B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,	/* 0-7 */
202 	B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,	/* 8-15 */
203 	B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,	/*16-23 */
204 	B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,	/* 24-31 */
205 	WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,	/*  !"#$%&' */
206 	PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC,	/* ()*+, -./ */
207 	NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM,	/* 01234567 */
208 	NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,	/* 89:;<=>? */
209 	PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* @ABCDEFG */
210 	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* HIJKLMNO */
211 	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* PQRSTUVW */
212 	A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC,	/* XYZ[\]^_ */
213 	PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* `abcdefg */
214 	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* hijklmno */
215 	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* pqrstuvw */
216 	ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0,	/* xyz{|}~ */
217 	B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
218 	B_SYM,	/* 135 */
219 	B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
220 	B_CAPSYM,	/* 143 */
221 	B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
222 	B_SYM,	/* 151 */
223 	B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
224 	B_SYM,	/* 159 */
225 	WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
226 	B_SYM,	/* 167 */
227 	B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,	/* 168-175 */
228 	B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,	/* 176-183 */
229 	B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,	/* 184-191 */
230 	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* 192-199 */
231 	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* 200-207 */
232 	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM,	/* 208-215 */
233 	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA,	/* 216-223 */
234 	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* 224-231 */
235 	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* 232-239 */
236 	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM,	/* 240-247 */
237 	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA	/* 248-255 */
238 };
239 
240 struct task_struct *speakup_task;
241 struct bleep unprocessed_sound;
242 static int spk_keydown;
243 static u_char spk_lastkey, spk_close_press, keymap_flags;
244 static u_char last_keycode, this_speakup_key;
245 static u_long last_spk_jiffy;
246 
247 struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
248 
249 DEFINE_MUTEX(spk_mutex);
250 
251 static int keyboard_notifier_call(struct notifier_block *,
252 				  unsigned long code, void *param);
253 
254 struct notifier_block keyboard_notifier_block = {
255 	.notifier_call = keyboard_notifier_call,
256 };
257 
258 static int vt_notifier_call(struct notifier_block *,
259 			    unsigned long code, void *param);
260 
261 struct notifier_block vt_notifier_block = {
262 	.notifier_call = vt_notifier_call,
263 };
264 
get_attributes(u16 * pos)265 static unsigned char get_attributes(u16 *pos)
266 {
267 	return (u_char) (scr_readw(pos) >> 8);
268 }
269 
speakup_date(struct vc_data * vc)270 static void speakup_date(struct vc_data *vc)
271 {
272 	spk_x = spk_cx = vc->vc_x;
273 	spk_y = spk_cy = vc->vc_y;
274 	spk_pos = spk_cp = vc->vc_pos;
275 	spk_old_attr = spk_attr;
276 	spk_attr = get_attributes((u_short *) spk_pos);
277 }
278 
bleep(u_short val)279 static void bleep(u_short val)
280 {
281 	static const short vals[] = {
282 		350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
283 	};
284 	short freq;
285 	int time = bleep_time;
286 	freq = vals[val % 12];
287 	if (val > 11)
288 		freq *= (1 << (val / 12));
289 	unprocessed_sound.freq = freq;
290 	unprocessed_sound.jiffies = msecs_to_jiffies(time);
291 	unprocessed_sound.active = 1;
292 	/* We can only have 1 active sound at a time. */
293 }
294 
speakup_shut_up(struct vc_data * vc)295 static void speakup_shut_up(struct vc_data *vc)
296 {
297 	if (spk_killed)
298 		return;
299 	spk_shut_up |= 0x01;
300 	spk_parked &= 0xfe;
301 	speakup_date(vc);
302 	if (synth != NULL)
303 		do_flush();
304 }
305 
speech_kill(struct vc_data * vc)306 static void speech_kill(struct vc_data *vc)
307 {
308 	char val = synth->is_alive(synth);
309 	if (val == 0)
310 		return;
311 
312 	/* re-enables synth, if disabled */
313 	if (val == 2 || spk_killed) {
314 		/* dead */
315 		spk_shut_up &= ~0x40;
316 		synth_printf("%s\n", msg_get(MSG_IAM_ALIVE));
317 	} else {
318 		synth_printf("%s\n", msg_get(MSG_YOU_KILLED_SPEAKUP));
319 		spk_shut_up |= 0x40;
320 	}
321 }
322 
speakup_off(struct vc_data * vc)323 static void speakup_off(struct vc_data *vc)
324 {
325 	if (spk_shut_up & 0x80) {
326 		spk_shut_up &= 0x7f;
327 		synth_printf("%s\n", msg_get(MSG_HEY_THATS_BETTER));
328 	} else {
329 		spk_shut_up |= 0x80;
330 		synth_printf("%s\n", msg_get(MSG_YOU_TURNED_ME_OFF));
331 	}
332 	speakup_date(vc);
333 }
334 
speakup_parked(struct vc_data * vc)335 static void speakup_parked(struct vc_data *vc)
336 {
337 	if (spk_parked & 0x80) {
338 		spk_parked = 0;
339 		synth_printf("%s\n", msg_get(MSG_UNPARKED));
340 	} else {
341 		spk_parked |= 0x80;
342 		synth_printf("%s\n", msg_get(MSG_PARKED));
343 	}
344 }
345 
speakup_cut(struct vc_data * vc)346 static void speakup_cut(struct vc_data *vc)
347 {
348 	static const char err_buf[] = "set selection failed";
349 	int ret;
350 
351 	if (!mark_cut_flag) {
352 		mark_cut_flag = 1;
353 		xs = (u_short) spk_x;
354 		ys = (u_short) spk_y;
355 		spk_sel_cons = vc;
356 		synth_printf("%s\n", msg_get(MSG_MARK));
357 		return;
358 	}
359 	xe = (u_short) spk_x;
360 	ye = (u_short) spk_y;
361 	mark_cut_flag = 0;
362 	synth_printf("%s\n", msg_get(MSG_CUT));
363 
364 	speakup_clear_selection();
365 	ret = speakup_set_selection(tty);
366 
367 	switch (ret) {
368 	case 0:
369 		break;		/* no error */
370 	case -EFAULT:
371 		pr_warn("%sEFAULT\n", err_buf);
372 		break;
373 	case -EINVAL:
374 		pr_warn("%sEINVAL\n", err_buf);
375 		break;
376 	case -ENOMEM:
377 		pr_warn("%sENOMEM\n", err_buf);
378 		break;
379 	}
380 }
381 
speakup_paste(struct vc_data * vc)382 static void speakup_paste(struct vc_data *vc)
383 {
384 	if (mark_cut_flag) {
385 		mark_cut_flag = 0;
386 		synth_printf("%s\n", msg_get(MSG_MARK_CLEARED));
387 	} else {
388 		synth_printf("%s\n", msg_get(MSG_PASTE));
389 		speakup_paste_selection(tty);
390 	}
391 }
392 
say_attributes(struct vc_data * vc)393 static void say_attributes(struct vc_data *vc)
394 {
395 	int fg = spk_attr & 0x0f;
396 	int bg = spk_attr >> 4;
397 	if (fg > 8) {
398 		synth_printf("%s ", msg_get(MSG_BRIGHT));
399 		fg -= 8;
400 	}
401 	synth_printf("%s", msg_get(MSG_COLORS_START + fg));
402 	if (bg > 7) {
403 		synth_printf(" %s ", msg_get(MSG_ON_BLINKING));
404 		bg -= 8;
405 	} else
406 		synth_printf(" %s ", msg_get(MSG_ON));
407 	synth_printf("%s\n", msg_get(MSG_COLORS_START + bg));
408 }
409 
410 enum {
411 	edge_top = 1,
412 	edge_bottom,
413 	edge_left,
414 	edge_right,
415 	edge_quiet
416 };
417 
announce_edge(struct vc_data * vc,int msg_id)418 static void announce_edge(struct vc_data *vc, int msg_id)
419 {
420 	if (bleeps & 1)
421 		bleep(spk_y);
422 	if ((bleeps & 2) && (msg_id < edge_quiet))
423 		synth_printf("%s\n", msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
424 }
425 
speak_char(u_char ch)426 static void speak_char(u_char ch)
427 {
428 	char *cp = characters[ch];
429 	struct var_t *direct = get_var(DIRECT);
430 	if (direct && direct->u.n.value) {
431 		if (IS_CHAR(ch, B_CAP)) {
432 			pitch_shift++;
433 			synth_printf("%s", str_caps_start);
434 		}
435 		synth_printf("%c", ch);
436 		if (IS_CHAR(ch, B_CAP))
437 			synth_printf("%s", str_caps_stop);
438 		return;
439 	}
440 	if (cp == NULL) {
441 		pr_info("speak_char: cp == NULL!\n");
442 		return;
443 	}
444 	synth_buffer_add(SPACE);
445 	if (IS_CHAR(ch, B_CAP)) {
446 		pitch_shift++;
447 		synth_printf("%s", str_caps_start);
448 		synth_printf("%s", cp);
449 		synth_printf("%s", str_caps_stop);
450 	} else {
451 		if (*cp == '^') {
452 			synth_printf("%s", msg_get(MSG_CTRL));
453 			cp++;
454 		}
455 		synth_printf("%s", cp);
456 	}
457 	synth_buffer_add(SPACE);
458 }
459 
get_char(struct vc_data * vc,u16 * pos,u_char * attribs)460 static u16 get_char(struct vc_data *vc, u16 * pos, u_char * attribs)
461 {
462 	u16 ch = ' ';
463 	if (vc && pos) {
464 		u16 w = scr_readw(pos);
465 		u16 c = w & 0xff;
466 
467 		if (w & vc->vc_hi_font_mask)
468 			c |= 0x100;
469 
470 		ch = inverse_translate(vc, c, 0);
471 		*attribs = (w & 0xff00) >> 8;
472 	}
473 	return ch;
474 }
475 
say_char(struct vc_data * vc)476 static void say_char(struct vc_data *vc)
477 {
478 	u_short ch;
479 	spk_old_attr = spk_attr;
480 	ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
481 	if (spk_attr != spk_old_attr) {
482 		if (attrib_bleep & 1)
483 			bleep(spk_y);
484 		if (attrib_bleep & 2)
485 			say_attributes(vc);
486 	}
487 	speak_char(ch & 0xff);
488 }
489 
say_phonetic_char(struct vc_data * vc)490 static void say_phonetic_char(struct vc_data *vc)
491 {
492 	u_short ch;
493 	spk_old_attr = spk_attr;
494 	ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
495 	if (isascii(ch) && isalpha(ch)) {
496 		ch &= 0x1f;
497 		synth_printf("%s\n", phonetic[--ch]);
498 	} else {
499 		if (IS_CHAR(ch, B_NUM))
500 			synth_printf("%s ", msg_get(MSG_NUMBER));
501 		speak_char(ch);
502 	}
503 }
504 
say_prev_char(struct vc_data * vc)505 static void say_prev_char(struct vc_data *vc)
506 {
507 	spk_parked |= 0x01;
508 	if (spk_x == 0) {
509 		announce_edge(vc, edge_left);
510 		return;
511 	}
512 	spk_x--;
513 	spk_pos -= 2;
514 	say_char(vc);
515 }
516 
say_next_char(struct vc_data * vc)517 static void say_next_char(struct vc_data *vc)
518 {
519 	spk_parked |= 0x01;
520 	if (spk_x == vc->vc_cols - 1) {
521 		announce_edge(vc, edge_right);
522 		return;
523 	}
524 	spk_x++;
525 	spk_pos += 2;
526 	say_char(vc);
527 }
528 
529 /* get_word - will first check to see if the character under the
530  * reading cursor is a space and if say_word_ctl is true it will
531  * return the word space.  If say_word_ctl is not set it will check to
532  * see if there is a word starting on the next position to the right
533  * and return that word if it exists.  If it does not exist it will
534  * move left to the beginning of any previous word on the line or the
535  * beginning off the line whichever comes first.. */
536 
get_word(struct vc_data * vc)537 static u_long get_word(struct vc_data *vc)
538 {
539 	u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
540 	char ch;
541 	u_short attr_ch;
542 	u_char temp;
543 	spk_old_attr = spk_attr;
544 	ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
545 
546 /* decided to take out the sayword if on a space (mis-information */
547 	if (say_word_ctl && ch == SPACE) {
548 		*buf = '\0';
549 		synth_printf("%s\n", msg_get(MSG_SPACE));
550 		return 0;
551 	} else if ((tmpx < vc->vc_cols - 2)
552 		   && (ch == SPACE || ch == 0 || IS_WDLM(ch))
553 		   && ((char)get_char(vc, (u_short *) &tmp_pos + 1, &temp) >
554 		       SPACE)) {
555 		tmp_pos += 2;
556 		tmpx++;
557 	} else
558 		while (tmpx > 0) {
559 			ch = (char)get_char(vc, (u_short *) tmp_pos - 1, &temp);
560 			if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
561 			    && ((char)get_char(vc, (u_short *) tmp_pos, &temp) >
562 				SPACE))
563 				break;
564 			tmp_pos -= 2;
565 			tmpx--;
566 		}
567 	attr_ch = get_char(vc, (u_short *) tmp_pos, &spk_attr);
568 	buf[cnt++] = attr_ch & 0xff;
569 	while (tmpx < vc->vc_cols - 1) {
570 		tmp_pos += 2;
571 		tmpx++;
572 		ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
573 		if ((ch == SPACE) || ch == 0
574 		    || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
575 			break;
576 		buf[cnt++] = ch;
577 	}
578 	buf[cnt] = '\0';
579 	return cnt;
580 }
581 
say_word(struct vc_data * vc)582 static void say_word(struct vc_data *vc)
583 {
584 	u_long cnt = get_word(vc);
585 	u_short saved_punc_mask = punc_mask;
586 	if (cnt == 0)
587 		return;
588 	punc_mask = PUNC;
589 	buf[cnt++] = SPACE;
590 	spkup_write(buf, cnt);
591 	punc_mask = saved_punc_mask;
592 }
593 
say_prev_word(struct vc_data * vc)594 static void say_prev_word(struct vc_data *vc)
595 {
596 	u_char temp;
597 	char ch;
598 	u_short edge_said = 0, last_state = 0, state = 0;
599 	spk_parked |= 0x01;
600 
601 	if (spk_x == 0) {
602 		if (spk_y == 0) {
603 			announce_edge(vc, edge_top);
604 			return;
605 		}
606 		spk_y--;
607 		spk_x = vc->vc_cols;
608 		edge_said = edge_quiet;
609 	}
610 	while (1) {
611 		if (spk_x == 0) {
612 			if (spk_y == 0) {
613 				edge_said = edge_top;
614 				break;
615 			}
616 			if (edge_said != edge_quiet)
617 				edge_said = edge_left;
618 			if (state > 0)
619 				break;
620 			spk_y--;
621 			spk_x = vc->vc_cols - 1;
622 		} else
623 			spk_x--;
624 		spk_pos -= 2;
625 		ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
626 		if (ch == SPACE || ch == 0)
627 			state = 0;
628 		else if (IS_WDLM(ch))
629 			state = 1;
630 		else
631 			state = 2;
632 		if (state < last_state) {
633 			spk_pos += 2;
634 			spk_x++;
635 			break;
636 		}
637 		last_state = state;
638 	}
639 	if (spk_x == 0 && edge_said == edge_quiet)
640 		edge_said = edge_left;
641 	if (edge_said > 0 && edge_said < edge_quiet)
642 		announce_edge(vc, edge_said);
643 	say_word(vc);
644 }
645 
say_next_word(struct vc_data * vc)646 static void say_next_word(struct vc_data *vc)
647 {
648 	u_char temp;
649 	char ch;
650 	u_short edge_said = 0, last_state = 2, state = 0;
651 	spk_parked |= 0x01;
652 
653 	if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
654 		announce_edge(vc, edge_bottom);
655 		return;
656 	}
657 	while (1) {
658 		ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
659 		if (ch == SPACE || ch == 0)
660 			state = 0;
661 		else if (IS_WDLM(ch))
662 			state = 1;
663 		else
664 			state = 2;
665 		if (state > last_state)
666 			break;
667 		if (spk_x >= vc->vc_cols - 1) {
668 			if (spk_y == vc->vc_rows - 1) {
669 				edge_said = edge_bottom;
670 				break;
671 			}
672 			state = 0;
673 			spk_y++;
674 			spk_x = 0;
675 			edge_said = edge_right;
676 		} else
677 			spk_x++;
678 		spk_pos += 2;
679 		last_state = state;
680 	}
681 	if (edge_said > 0)
682 		announce_edge(vc, edge_said);
683 	say_word(vc);
684 }
685 
spell_word(struct vc_data * vc)686 static void spell_word(struct vc_data *vc)
687 {
688 	static char *delay_str[] = { "", ",", ".", ". .", ". . ." };
689 	char *cp = buf, *str_cap = str_caps_stop;
690 	char *cp1, *last_cap = str_caps_stop;
691 	u_char ch;
692 	if (!get_word(vc))
693 		return;
694 	while ((ch = (u_char) *cp)) {
695 		if (cp != buf)
696 			synth_printf(" %s ", delay_str[spell_delay]);
697 		if (IS_CHAR(ch, B_CAP)) {
698 			str_cap = str_caps_start;
699 			if (*str_caps_stop)
700 				pitch_shift++;
701 			else	/* synth has no pitch */
702 				last_cap = str_caps_stop;
703 		} else
704 			str_cap = str_caps_stop;
705 		if (str_cap != last_cap) {
706 			synth_printf("%s", str_cap);
707 			last_cap = str_cap;
708 		}
709 		if (this_speakup_key == SPELL_PHONETIC
710 		    && (isascii(ch) && isalpha(ch))) {
711 			ch &= 31;
712 			cp1 = phonetic[--ch];
713 		} else {
714 			cp1 = characters[ch];
715 			if (*cp1 == '^') {
716 				synth_printf("%s", msg_get(MSG_CTRL));
717 				cp1++;
718 			}
719 		}
720 		synth_printf("%s", cp1);
721 		cp++;
722 	}
723 	if (str_cap != str_caps_stop)
724 		synth_printf("%s", str_caps_stop);
725 }
726 
get_line(struct vc_data * vc)727 static int get_line(struct vc_data *vc)
728 {
729 	u_long tmp = spk_pos - (spk_x * 2);
730 	int i = 0;
731 	u_char tmp2;
732 
733 	spk_old_attr = spk_attr;
734 	spk_attr = get_attributes((u_short *) spk_pos);
735 	for (i = 0; i < vc->vc_cols; i++) {
736 		buf[i] = (u_char) get_char(vc, (u_short *) tmp, &tmp2);
737 		tmp += 2;
738 	}
739 	for (--i; i >= 0; i--)
740 		if (buf[i] != SPACE)
741 			break;
742 	return ++i;
743 }
744 
say_line(struct vc_data * vc)745 static void say_line(struct vc_data *vc)
746 {
747 	int i = get_line(vc);
748 	char *cp;
749 	u_short saved_punc_mask = punc_mask;
750 	if (i == 0) {
751 		synth_printf("%s\n", msg_get(MSG_BLANK));
752 		return;
753 	}
754 	buf[i++] = '\n';
755 	if (this_speakup_key == SAY_LINE_INDENT) {
756 		cp = buf;
757 		while (*cp == SPACE)
758 			cp++;
759 		synth_printf("%d, ", (cp - buf) + 1);
760 	}
761 	punc_mask = punc_masks[reading_punc];
762 	spkup_write(buf, i);
763 	punc_mask = saved_punc_mask;
764 }
765 
say_prev_line(struct vc_data * vc)766 static void say_prev_line(struct vc_data *vc)
767 {
768 	spk_parked |= 0x01;
769 	if (spk_y == 0) {
770 		announce_edge(vc, edge_top);
771 		return;
772 	}
773 	spk_y--;
774 	spk_pos -= vc->vc_size_row;
775 	say_line(vc);
776 }
777 
say_next_line(struct vc_data * vc)778 static void say_next_line(struct vc_data *vc)
779 {
780 	spk_parked |= 0x01;
781 	if (spk_y == vc->vc_rows - 1) {
782 		announce_edge(vc, edge_bottom);
783 		return;
784 	}
785 	spk_y++;
786 	spk_pos += vc->vc_size_row;
787 	say_line(vc);
788 }
789 
say_from_to(struct vc_data * vc,u_long from,u_long to,int read_punc)790 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
791 		       int read_punc)
792 {
793 	int i = 0;
794 	u_char tmp;
795 	u_short saved_punc_mask = punc_mask;
796 	spk_old_attr = spk_attr;
797 	spk_attr = get_attributes((u_short *) from);
798 	while (from < to) {
799 		buf[i++] = (char)get_char(vc, (u_short *) from, &tmp);
800 		from += 2;
801 		if (i >= vc->vc_size_row)
802 			break;
803 	}
804 	for (--i; i >= 0; i--)
805 		if (buf[i] != SPACE)
806 			break;
807 	buf[++i] = SPACE;
808 	buf[++i] = '\0';
809 	if (i < 1)
810 		return i;
811 	if (read_punc)
812 		punc_mask = punc_info[reading_punc].mask;
813 	spkup_write(buf, i);
814 	if (read_punc)
815 		punc_mask = saved_punc_mask;
816 	return i - 1;
817 }
818 
say_line_from_to(struct vc_data * vc,u_long from,u_long to,int read_punc)819 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
820 			     int read_punc)
821 {
822 	u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
823 	u_long end = start + (to * 2);
824 	start += from * 2;
825 	if (say_from_to(vc, start, end, read_punc) <= 0)
826 		if (cursor_track != read_all_mode)
827 			synth_printf("%s\n", msg_get(MSG_BLANK));
828 }
829 
830 /* Sentence Reading Commands */
831 
832 static int currsentence;
833 static int numsentences[2];
834 static char *sentbufend[2];
835 static char *sentmarks[2][10];
836 static int currbuf;
837 static int bn;
838 static char sentbuf[2][256];
839 
say_sentence_num(int num,int prev)840 static int say_sentence_num(int num, int prev)
841 {
842 	bn = currbuf;
843 	currsentence = num + 1;
844 	if (prev && --bn == -1)
845 		bn = 1;
846 
847 	if (num > numsentences[bn])
848 		return 0;
849 
850 	spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
851 	return 1;
852 }
853 
get_sentence_buf(struct vc_data * vc,int read_punc)854 static int get_sentence_buf(struct vc_data *vc, int read_punc)
855 {
856 	u_long start, end;
857 	int i, bn;
858 	u_char tmp;
859 
860 	currbuf++;
861 	if (currbuf == 2)
862 		currbuf = 0;
863 	bn = currbuf;
864 	start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
865 	end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
866 
867 	numsentences[bn] = 0;
868 	sentmarks[bn][0] = &sentbuf[bn][0];
869 	i = 0;
870 	spk_old_attr = spk_attr;
871 	spk_attr = get_attributes((u_short *) start);
872 
873 	while (start < end) {
874 		sentbuf[bn][i] = (char)get_char(vc, (u_short *) start, &tmp);
875 		if (i > 0) {
876 			if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
877 			    && numsentences[bn] < 9) {
878 				/* Sentence Marker */
879 				numsentences[bn]++;
880 				sentmarks[bn][numsentences[bn]] =
881 				    &sentbuf[bn][i];
882 			}
883 		}
884 		i++;
885 		start += 2;
886 		if (i >= vc->vc_size_row)
887 			break;
888 	}
889 
890 	for (--i; i >= 0; i--)
891 		if (sentbuf[bn][i] != SPACE)
892 			break;
893 
894 	if (i < 1)
895 		return -1;
896 
897 	sentbuf[bn][++i] = SPACE;
898 	sentbuf[bn][++i] = '\0';
899 
900 	sentbufend[bn] = &sentbuf[bn][i];
901 	return numsentences[bn];
902 }
903 
say_screen_from_to(struct vc_data * vc,u_long from,u_long to)904 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
905 {
906 	u_long start = vc->vc_origin, end;
907 	if (from > 0)
908 		start += from * vc->vc_size_row;
909 	if (to > vc->vc_rows)
910 		to = vc->vc_rows;
911 	end = vc->vc_origin + (to * vc->vc_size_row);
912 	for (from = start; from < end; from = to) {
913 		to = from + vc->vc_size_row;
914 		say_from_to(vc, from, to, 1);
915 	}
916 }
917 
say_screen(struct vc_data * vc)918 static void say_screen(struct vc_data *vc)
919 {
920 	say_screen_from_to(vc, 0, vc->vc_rows);
921 }
922 
speakup_win_say(struct vc_data * vc)923 static void speakup_win_say(struct vc_data *vc)
924 {
925 	u_long start, end, from, to;
926 	if (win_start < 2) {
927 		synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
928 		return;
929 	}
930 	start = vc->vc_origin + (win_top * vc->vc_size_row);
931 	end = vc->vc_origin + (win_bottom * vc->vc_size_row);
932 	while (start <= end) {
933 		from = start + (win_left * 2);
934 		to = start + (win_right * 2);
935 		say_from_to(vc, from, to, 1);
936 		start += vc->vc_size_row;
937 	}
938 }
939 
top_edge(struct vc_data * vc)940 static void top_edge(struct vc_data *vc)
941 {
942 	spk_parked |= 0x01;
943 	spk_pos = vc->vc_origin + 2 * spk_x;
944 	spk_y = 0;
945 	say_line(vc);
946 }
947 
bottom_edge(struct vc_data * vc)948 static void bottom_edge(struct vc_data *vc)
949 {
950 	spk_parked |= 0x01;
951 	spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
952 	spk_y = vc->vc_rows - 1;
953 	say_line(vc);
954 }
955 
left_edge(struct vc_data * vc)956 static void left_edge(struct vc_data *vc)
957 {
958 	spk_parked |= 0x01;
959 	spk_pos -= spk_x * 2;
960 	spk_x = 0;
961 	say_char(vc);
962 }
963 
right_edge(struct vc_data * vc)964 static void right_edge(struct vc_data *vc)
965 {
966 	spk_parked |= 0x01;
967 	spk_pos += (vc->vc_cols - spk_x - 1) * 2;
968 	spk_x = vc->vc_cols - 1;
969 	say_char(vc);
970 }
971 
say_first_char(struct vc_data * vc)972 static void say_first_char(struct vc_data *vc)
973 {
974 	int i, len = get_line(vc);
975 	u_char ch;
976 	spk_parked |= 0x01;
977 	if (len == 0) {
978 		synth_printf("%s\n", msg_get(MSG_BLANK));
979 		return;
980 	}
981 	for (i = 0; i < len; i++)
982 		if (buf[i] != SPACE)
983 			break;
984 	ch = buf[i];
985 	spk_pos -= (spk_x - i) * 2;
986 	spk_x = i;
987 	synth_printf("%d, ", ++i);
988 	speak_char(ch);
989 }
990 
say_last_char(struct vc_data * vc)991 static void say_last_char(struct vc_data *vc)
992 {
993 	int len = get_line(vc);
994 	u_char ch;
995 	spk_parked |= 0x01;
996 	if (len == 0) {
997 		synth_printf("%s\n", msg_get(MSG_BLANK));
998 		return;
999 	}
1000 	ch = buf[--len];
1001 	spk_pos -= (spk_x - len) * 2;
1002 	spk_x = len;
1003 	synth_printf("%d, ", ++len);
1004 	speak_char(ch);
1005 }
1006 
say_position(struct vc_data * vc)1007 static void say_position(struct vc_data *vc)
1008 {
1009 	synth_printf(msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1010 		     vc->vc_num + 1);
1011 	synth_printf("\n");
1012 }
1013 
1014 /* Added by brianb */
say_char_num(struct vc_data * vc)1015 static void say_char_num(struct vc_data *vc)
1016 {
1017 	u_char tmp;
1018 	u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
1019 	ch &= 0xff;
1020 	synth_printf(msg_get(MSG_CHAR_INFO), ch, ch);
1021 }
1022 
1023 /* these are stub functions to keep keyboard.c happy. */
1024 
say_from_top(struct vc_data * vc)1025 static void say_from_top(struct vc_data *vc)
1026 {
1027 	say_screen_from_to(vc, 0, spk_y);
1028 }
1029 
say_to_bottom(struct vc_data * vc)1030 static void say_to_bottom(struct vc_data *vc)
1031 {
1032 	say_screen_from_to(vc, spk_y, vc->vc_rows);
1033 }
1034 
say_from_left(struct vc_data * vc)1035 static void say_from_left(struct vc_data *vc)
1036 {
1037 	say_line_from_to(vc, 0, spk_x, 1);
1038 }
1039 
say_to_right(struct vc_data * vc)1040 static void say_to_right(struct vc_data *vc)
1041 {
1042 	say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1043 }
1044 
1045 /* end of stub functions. */
1046 
spkup_write(const char * in_buf,int count)1047 static void spkup_write(const char *in_buf, int count)
1048 {
1049 	static int rep_count;
1050 	static u_char ch = '\0', old_ch = '\0';
1051 	static u_short char_type, last_type;
1052 	int in_count = count;
1053 	spk_keydown = 0;
1054 	while (count--) {
1055 		if (cursor_track == read_all_mode) {
1056 			/* Insert Sentence Index */
1057 			if ((in_buf == sentmarks[bn][currsentence]) &&
1058 			    (currsentence <= numsentences[bn]))
1059 				synth_insert_next_index(currsentence++);
1060 		}
1061 		ch = (u_char) *in_buf++;
1062 		char_type = spk_chartab[ch];
1063 		if (ch == old_ch && !(char_type & B_NUM)) {
1064 			if (++rep_count > 2)
1065 				continue;
1066 		} else {
1067 			if ((last_type & CH_RPT) && rep_count > 2) {
1068 				synth_printf(" ");
1069 				synth_printf(msg_get(MSG_REPEAT_DESC),
1070 					     ++rep_count);
1071 				synth_printf(" ");
1072 			}
1073 			rep_count = 0;
1074 		}
1075 		if (ch == spk_lastkey) {
1076 			rep_count = 0;
1077 			if (key_echo == 1 && ch >= MINECHOCHAR)
1078 				speak_char(ch);
1079 		} else if (char_type & B_ALPHA) {
1080 			if ((synth_flags & SF_DEC) && (last_type & PUNC))
1081 				synth_buffer_add(SPACE);
1082 			synth_printf("%c", ch);
1083 		} else if (char_type & B_NUM) {
1084 			rep_count = 0;
1085 			synth_printf("%c", ch);
1086 		} else if (char_type & punc_mask) {
1087 			speak_char(ch);
1088 			char_type &= ~PUNC;	/* for dec nospell processing */
1089 		} else if (char_type & SYNTH_OK) {
1090 			/* these are usually puncts like . and , which synth
1091 			 * needs for expression.
1092 			 * suppress multiple to get rid of long pauses and
1093 			 * clear repeat count
1094 			 * so if someone has
1095 			 * repeats on you don't get nothing repeated count */
1096 			if (ch != old_ch)
1097 				synth_printf("%c", ch);
1098 			else
1099 				rep_count = 0;
1100 		} else {
1101 /* send space and record position, if next is num overwrite space */
1102 			if (old_ch != ch)
1103 				synth_buffer_add(SPACE);
1104 			else
1105 				rep_count = 0;
1106 		}
1107 		old_ch = ch;
1108 		last_type = char_type;
1109 	}
1110 	spk_lastkey = 0;
1111 	if (in_count > 2 && rep_count > 2) {
1112 		if (last_type & CH_RPT) {
1113 			synth_printf(" ");
1114 			synth_printf(msg_get(MSG_REPEAT_DESC2), ++rep_count);
1115 			synth_printf(" ");
1116 		}
1117 		rep_count = 0;
1118 	}
1119 }
1120 
1121 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1122 
1123 static void read_all_doc(struct vc_data *vc);
1124 static void cursor_done(u_long data);
1125 static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1126 
do_handle_shift(struct vc_data * vc,u_char value,char up_flag)1127 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1128 {
1129 	unsigned long flags;
1130 	if (synth == NULL || up_flag || spk_killed)
1131 		return;
1132 	spk_lock(flags);
1133 	if (cursor_track == read_all_mode) {
1134 		switch (value) {
1135 		case KVAL(K_SHIFT):
1136 			del_timer(&cursor_timer);
1137 			spk_shut_up &= 0xfe;
1138 			do_flush();
1139 			read_all_doc(vc);
1140 			break;
1141 		case KVAL(K_CTRL):
1142 			del_timer(&cursor_timer);
1143 			cursor_track = prev_cursor_track;
1144 			spk_shut_up &= 0xfe;
1145 			do_flush();
1146 			break;
1147 		}
1148 	} else {
1149 		spk_shut_up &= 0xfe;
1150 		do_flush();
1151 	}
1152 	if (say_ctrl && value < NUM_CTL_LABELS)
1153 		synth_printf("%s", msg_get(MSG_CTL_START + value));
1154 	spk_unlock(flags);
1155 }
1156 
do_handle_latin(struct vc_data * vc,u_char value,char up_flag)1157 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1158 {
1159 	unsigned long flags;
1160 	spk_lock(flags);
1161 	if (up_flag) {
1162 		spk_lastkey = spk_keydown = 0;
1163 		spk_unlock(flags);
1164 		return;
1165 	}
1166 	if (synth == NULL || spk_killed) {
1167 		spk_unlock(flags);
1168 		return;
1169 	}
1170 	spk_shut_up &= 0xfe;
1171 	spk_lastkey = value;
1172 	spk_keydown++;
1173 	spk_parked &= 0xfe;
1174 	if (key_echo == 2 && value >= MINECHOCHAR)
1175 		speak_char(value);
1176 	spk_unlock(flags);
1177 }
1178 
set_key_info(const u_char * key_info,u_char * k_buffer)1179 int set_key_info(const u_char *key_info, u_char *k_buffer)
1180 {
1181 	int i = 0, states, key_data_len;
1182 	const u_char *cp = key_info;
1183 	u_char *cp1 = k_buffer;
1184 	u_char ch, version, num_keys;
1185 	version = *cp++;
1186 	if (version != KEY_MAP_VER)
1187 		return -1;
1188 	num_keys = *cp;
1189 	states = (int)cp[1];
1190 	key_data_len = (states + 1) * (num_keys + 1);
1191 	if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(key_buf))
1192 		return -2;
1193 	memset(k_buffer, 0, SHIFT_TBL_SIZE);
1194 	memset(our_keys, 0, sizeof(our_keys));
1195 	shift_table = k_buffer;
1196 	our_keys[0] = shift_table;
1197 	cp1 += SHIFT_TBL_SIZE;
1198 	memcpy(cp1, cp, key_data_len + 3);
1199 	/* get num_keys, states and data */
1200 	cp1 += 2;		/* now pointing at shift states */
1201 	for (i = 1; i <= states; i++) {
1202 		ch = *cp1++;
1203 		if (ch >= SHIFT_TBL_SIZE)
1204 			return -3;
1205 		shift_table[ch] = i;
1206 	}
1207 	keymap_flags = *cp1++;
1208 	while ((ch = *cp1)) {
1209 		if (ch >= MAX_KEY)
1210 			return -4;
1211 		our_keys[ch] = cp1;
1212 		cp1 += states + 1;
1213 	}
1214 	return 0;
1215 }
1216 
1217 static struct var_t spk_vars[] = {
1218 	/* bell must be first to set high limit */
1219 	{BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1220 	{SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1221 	{ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1222 	{BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1223 	{BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1224 	{PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1225 	{READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1226 	{CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1227 	{SAY_CONTROL, TOGGLE_0},
1228 	{SAY_WORD_CTL, TOGGLE_0},
1229 	{NO_INTERRUPT, TOGGLE_0},
1230 	{KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1231 	V_LAST_VAR
1232 };
1233 
toggle_cursoring(struct vc_data * vc)1234 static void toggle_cursoring(struct vc_data *vc)
1235 {
1236 	if (cursor_track == read_all_mode)
1237 		cursor_track = prev_cursor_track;
1238 	if (++cursor_track >= CT_Max)
1239 		cursor_track = 0;
1240 	synth_printf("%s\n", msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1241 }
1242 
reset_default_chars(void)1243 void reset_default_chars(void)
1244 {
1245 	int i;
1246 
1247 	/* First, free any non-default */
1248 	for (i = 0; i < 256; i++) {
1249 		if ((characters[i] != NULL)
1250 		    && (characters[i] != default_chars[i]))
1251 			kfree(characters[i]);
1252 	}
1253 
1254 	memcpy(characters, default_chars, sizeof(default_chars));
1255 }
1256 
reset_default_chartab(void)1257 void reset_default_chartab(void)
1258 {
1259 	memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1260 }
1261 
1262 static const struct st_bits_data *pb_edit;
1263 
edit_bits(struct vc_data * vc,u_char type,u_char ch,u_short key)1264 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1265 {
1266 	short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1267 	if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1268 		return -1;
1269 	if (ch == SPACE) {
1270 		synth_printf("%s\n", msg_get(MSG_EDIT_DONE));
1271 		special_handler = NULL;
1272 		return 1;
1273 	}
1274 	if (mask < PUNC && !(ch_type & PUNC))
1275 		return -1;
1276 	spk_chartab[ch] ^= mask;
1277 	speak_char(ch);
1278 	synth_printf(" %s\n",
1279 		     (spk_chartab[ch] & mask) ? msg_get(MSG_ON) :
1280 		     msg_get(MSG_OFF));
1281 	return 1;
1282 }
1283 
1284 /* Allocation concurrency is protected by the console semaphore */
speakup_allocate(struct vc_data * vc)1285 int speakup_allocate(struct vc_data *vc)
1286 {
1287 	int vc_num;
1288 
1289 	vc_num = vc->vc_num;
1290 	if (speakup_console[vc_num] == NULL) {
1291 		speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1292 						  GFP_ATOMIC);
1293 		if (speakup_console[vc_num] == NULL)
1294 			return -ENOMEM;
1295 		speakup_date(vc);
1296 	} else if (!spk_parked)
1297 		speakup_date(vc);
1298 
1299 	return 0;
1300 }
1301 
speakup_deallocate(struct vc_data * vc)1302 void speakup_deallocate(struct vc_data *vc)
1303 {
1304 	int vc_num;
1305 
1306 	vc_num = vc->vc_num;
1307 	kfree(speakup_console[vc_num]);
1308 	speakup_console[vc_num] = NULL;
1309 }
1310 
1311 static u_char is_cursor;
1312 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1313 static int cursor_con;
1314 
1315 static void reset_highlight_buffers(struct vc_data *);
1316 
1317 static int read_all_key;
1318 
1319 static void start_read_all_timer(struct vc_data *vc, int command);
1320 
1321 enum {
1322 	RA_NOTHING,
1323 	RA_NEXT_SENT,
1324 	RA_PREV_LINE,
1325 	RA_NEXT_LINE,
1326 	RA_PREV_SENT,
1327 	RA_DOWN_ARROW,
1328 	RA_TIMER,
1329 	RA_FIND_NEXT_SENT,
1330 	RA_FIND_PREV_SENT,
1331 };
1332 
kbd_fakekey2(struct vc_data * vc,int command)1333 static void kbd_fakekey2(struct vc_data *vc, int command)
1334 {
1335 	del_timer(&cursor_timer);
1336 	speakup_fake_down_arrow();
1337 	start_read_all_timer(vc, command);
1338 }
1339 
read_all_doc(struct vc_data * vc)1340 static void read_all_doc(struct vc_data *vc)
1341 {
1342 	if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1343 		return;
1344 	if (!synth_supports_indexing())
1345 		return;
1346 	if (cursor_track != read_all_mode)
1347 		prev_cursor_track = cursor_track;
1348 	cursor_track = read_all_mode;
1349 	reset_index_count(0);
1350 	if (get_sentence_buf(vc, 0) == -1)
1351 		kbd_fakekey2(vc, RA_DOWN_ARROW);
1352 	else {
1353 		say_sentence_num(0, 0);
1354 		synth_insert_next_index(0);
1355 		start_read_all_timer(vc, RA_TIMER);
1356 	}
1357 }
1358 
stop_read_all(struct vc_data * vc)1359 static void stop_read_all(struct vc_data *vc)
1360 {
1361 	del_timer(&cursor_timer);
1362 	cursor_track = prev_cursor_track;
1363 	spk_shut_up &= 0xfe;
1364 	do_flush();
1365 }
1366 
start_read_all_timer(struct vc_data * vc,int command)1367 static void start_read_all_timer(struct vc_data *vc, int command)
1368 {
1369 	struct var_t *cursor_timeout;
1370 
1371 	cursor_con = vc->vc_num;
1372 	read_all_key = command;
1373 	cursor_timeout = get_var(CURSOR_TIME);
1374 	mod_timer(&cursor_timer,
1375 		  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1376 }
1377 
handle_cursor_read_all(struct vc_data * vc,int command)1378 static void handle_cursor_read_all(struct vc_data *vc, int command)
1379 {
1380 	int indcount, sentcount, rv, sn;
1381 
1382 	switch (command) {
1383 	case RA_NEXT_SENT:
1384 		/* Get Current Sentence */
1385 		get_index_count(&indcount, &sentcount);
1386 		/*printk("%d %d  ", indcount, sentcount); */
1387 		reset_index_count(sentcount + 1);
1388 		if (indcount == 1) {
1389 			if (!say_sentence_num(sentcount + 1, 0)) {
1390 				kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1391 				return;
1392 			}
1393 			synth_insert_next_index(0);
1394 		} else {
1395 			sn = 0;
1396 			if (!say_sentence_num(sentcount + 1, 1)) {
1397 				sn = 1;
1398 				reset_index_count(sn);
1399 			} else
1400 				synth_insert_next_index(0);
1401 			if (!say_sentence_num(sn, 0)) {
1402 				kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1403 				return;
1404 			}
1405 			synth_insert_next_index(0);
1406 		}
1407 		start_read_all_timer(vc, RA_TIMER);
1408 		break;
1409 	case RA_PREV_SENT:
1410 		break;
1411 	case RA_NEXT_LINE:
1412 		read_all_doc(vc);
1413 		break;
1414 	case RA_PREV_LINE:
1415 		break;
1416 	case RA_DOWN_ARROW:
1417 		if (get_sentence_buf(vc, 0) == -1) {
1418 			kbd_fakekey2(vc, RA_DOWN_ARROW);
1419 		} else {
1420 			say_sentence_num(0, 0);
1421 			synth_insert_next_index(0);
1422 			start_read_all_timer(vc, RA_TIMER);
1423 		}
1424 		break;
1425 	case RA_FIND_NEXT_SENT:
1426 		rv = get_sentence_buf(vc, 0);
1427 		if (rv == -1)
1428 			read_all_doc(vc);
1429 		if (rv == 0)
1430 			kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1431 		else {
1432 			say_sentence_num(1, 0);
1433 			synth_insert_next_index(0);
1434 			start_read_all_timer(vc, RA_TIMER);
1435 		}
1436 		break;
1437 	case RA_FIND_PREV_SENT:
1438 		break;
1439 	case RA_TIMER:
1440 		get_index_count(&indcount, &sentcount);
1441 		if (indcount < 2)
1442 			kbd_fakekey2(vc, RA_DOWN_ARROW);
1443 		else
1444 			start_read_all_timer(vc, RA_TIMER);
1445 		break;
1446 	}
1447 }
1448 
pre_handle_cursor(struct vc_data * vc,u_char value,char up_flag)1449 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1450 {
1451 	unsigned long flags;
1452 	spk_lock(flags);
1453 	if (cursor_track == read_all_mode) {
1454 		spk_parked &= 0xfe;
1455 		if (synth == NULL || up_flag || spk_shut_up) {
1456 			spk_unlock(flags);
1457 			return NOTIFY_STOP;
1458 		}
1459 		del_timer(&cursor_timer);
1460 		spk_shut_up &= 0xfe;
1461 		do_flush();
1462 		start_read_all_timer(vc, value + 1);
1463 		spk_unlock(flags);
1464 		return NOTIFY_STOP;
1465 	}
1466 	spk_unlock(flags);
1467 	return NOTIFY_OK;
1468 }
1469 
do_handle_cursor(struct vc_data * vc,u_char value,char up_flag)1470 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1471 {
1472 	unsigned long flags;
1473 	struct var_t *cursor_timeout;
1474 
1475 	spk_lock(flags);
1476 	spk_parked &= 0xfe;
1477 	if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1478 		spk_unlock(flags);
1479 		return;
1480 	}
1481 	spk_shut_up &= 0xfe;
1482 	if (no_intr)
1483 		do_flush();
1484 /* the key press flushes if !no_inter but we want to flush on cursor
1485  * moves regardless of no_inter state */
1486 	is_cursor = value + 1;
1487 	old_cursor_pos = vc->vc_pos;
1488 	old_cursor_x = vc->vc_x;
1489 	old_cursor_y = vc->vc_y;
1490 	speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1491 	cursor_con = vc->vc_num;
1492 	if (cursor_track == CT_Highlight)
1493 		reset_highlight_buffers(vc);
1494 	cursor_timeout = get_var(CURSOR_TIME);
1495 	mod_timer(&cursor_timer,
1496 		  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1497 	spk_unlock(flags);
1498 }
1499 
update_color_buffer(struct vc_data * vc,const char * ic,int len)1500 static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
1501 {
1502 	int i, bi, hi;
1503 	int vc_num = vc->vc_num;
1504 
1505 	bi = ((vc->vc_attr & 0x70) >> 4);
1506 	hi = speakup_console[vc_num]->ht.highsize[bi];
1507 
1508 	i = 0;
1509 	if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1510 		speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1511 		speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1512 		speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1513 	}
1514 	while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1515 		if ((ic[i] > 32) && (ic[i] < 127)) {
1516 			speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1517 			hi++;
1518 		} else if ((ic[i] == 32) && (hi != 0)) {
1519 			if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1520 			    32) {
1521 				speakup_console[vc_num]->ht.highbuf[bi][hi] =
1522 				    ic[i];
1523 				hi++;
1524 			}
1525 		}
1526 		i++;
1527 	}
1528 	speakup_console[vc_num]->ht.highsize[bi] = hi;
1529 }
1530 
reset_highlight_buffers(struct vc_data * vc)1531 static void reset_highlight_buffers(struct vc_data *vc)
1532 {
1533 	int i;
1534 	int vc_num = vc->vc_num;
1535 	for (i = 0; i < 8; i++)
1536 		speakup_console[vc_num]->ht.highsize[i] = 0;
1537 }
1538 
count_highlight_color(struct vc_data * vc)1539 static int count_highlight_color(struct vc_data *vc)
1540 {
1541 	int i, bg;
1542 	int cc;
1543 	int vc_num = vc->vc_num;
1544 	u16 ch;
1545 	u16 *start = (u16 *) vc->vc_origin;
1546 
1547 	for (i = 0; i < 8; i++)
1548 		speakup_console[vc_num]->ht.bgcount[i] = 0;
1549 
1550 	for (i = 0; i < vc->vc_rows; i++) {
1551 		u16 *end = start + vc->vc_cols * 2;
1552 		u16 *ptr;
1553 		for (ptr = start; ptr < end; ptr++) {
1554 			ch = get_attributes(ptr);
1555 			bg = (ch & 0x70) >> 4;
1556 			speakup_console[vc_num]->ht.bgcount[bg]++;
1557 		}
1558 		start += vc->vc_size_row;
1559 	}
1560 
1561 	cc = 0;
1562 	for (i = 0; i < 8; i++)
1563 		if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1564 			cc++;
1565 	return cc;
1566 }
1567 
get_highlight_color(struct vc_data * vc)1568 static int get_highlight_color(struct vc_data *vc)
1569 {
1570 	int i, j;
1571 	unsigned int cptr[8], tmp;
1572 	int vc_num = vc->vc_num;
1573 
1574 	for (i = 0; i < 8; i++)
1575 		cptr[i] = i;
1576 
1577 	for (i = 0; i < 7; i++)
1578 		for (j = i + 1; j < 8; j++)
1579 			if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1580 			    speakup_console[vc_num]->ht.bgcount[cptr[j]]) {
1581 				tmp = cptr[i];
1582 				cptr[i] = cptr[j];
1583 				cptr[j] = tmp;
1584 			}
1585 
1586 	for (i = 0; i < 8; i++)
1587 		if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1588 			if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1589 				return cptr[i];
1590 	return -1;
1591 }
1592 
speak_highlight(struct vc_data * vc)1593 static int speak_highlight(struct vc_data *vc)
1594 {
1595 	int hc, d;
1596 	int vc_num = vc->vc_num;
1597 	if (count_highlight_color(vc) == 1)
1598 		return 0;
1599 	hc = get_highlight_color(vc);
1600 	if (hc != -1) {
1601 		d = vc->vc_y - speakup_console[vc_num]->ht.cy;
1602 		if ((d == 1) || (d == -1))
1603 			if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1604 				return 0;
1605 		spk_parked |= 0x01;
1606 		do_flush();
1607 		spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1608 			    speakup_console[vc_num]->ht.highsize[hc]);
1609 		spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1610 		spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1611 		spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1612 		return 1;
1613 	}
1614 	return 0;
1615 }
1616 
cursor_done(u_long data)1617 static void cursor_done(u_long data)
1618 {
1619 	struct vc_data *vc = vc_cons[cursor_con].d;
1620 	unsigned long flags;
1621 	del_timer(&cursor_timer);
1622 	spk_lock(flags);
1623 	if (cursor_con != fg_console) {
1624 		is_cursor = 0;
1625 		goto out;
1626 	}
1627 	speakup_date(vc);
1628 	if (win_enabled) {
1629 		if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1630 		    vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1631 			spk_keydown = is_cursor = 0;
1632 			goto out;
1633 		}
1634 	}
1635 	if (cursor_track == read_all_mode) {
1636 		handle_cursor_read_all(vc, read_all_key);
1637 		goto out;
1638 	}
1639 	if (cursor_track == CT_Highlight) {
1640 		if (speak_highlight(vc)) {
1641 			spk_keydown = is_cursor = 0;
1642 			goto out;
1643 		}
1644 	}
1645 	if (cursor_track == CT_Window)
1646 		speakup_win_say(vc);
1647 	else if (is_cursor == 1 || is_cursor == 4)
1648 		say_line_from_to(vc, 0, vc->vc_cols, 0);
1649 	else
1650 		say_char(vc);
1651 	spk_keydown = is_cursor = 0;
1652 out:
1653 	spk_unlock(flags);
1654 }
1655 
1656 /* called by: vt_notifier_call() */
speakup_bs(struct vc_data * vc)1657 static void speakup_bs(struct vc_data *vc)
1658 {
1659 	unsigned long flags;
1660 	if (!speakup_console[vc->vc_num])
1661 		return;
1662 	if (!spk_trylock(flags))
1663 		/* Speakup output, discard */
1664 		return;
1665 	if (!spk_parked)
1666 		speakup_date(vc);
1667 	if (spk_shut_up || synth == NULL) {
1668 		spk_unlock(flags);
1669 		return;
1670 	}
1671 	if (vc->vc_num == fg_console && spk_keydown) {
1672 		spk_keydown = 0;
1673 		if (!is_cursor)
1674 			say_char(vc);
1675 	}
1676 	spk_unlock(flags);
1677 }
1678 
1679 /* called by: vt_notifier_call() */
speakup_con_write(struct vc_data * vc,const char * str,int len)1680 static void speakup_con_write(struct vc_data *vc, const char *str, int len)
1681 {
1682 	unsigned long flags;
1683 	if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1684 		return;
1685 	if (!spk_trylock(flags))
1686 		/* Speakup output, discard */
1687 		return;
1688 	if (bell_pos && spk_keydown && (vc->vc_x == bell_pos - 1))
1689 		bleep(3);
1690 	if ((is_cursor) || (cursor_track == read_all_mode)) {
1691 		if (cursor_track == CT_Highlight)
1692 			update_color_buffer(vc, str, len);
1693 		spk_unlock(flags);
1694 		return;
1695 	}
1696 	if (win_enabled) {
1697 		if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1698 		    vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1699 			spk_unlock(flags);
1700 			return;
1701 		}
1702 	}
1703 
1704 	spkup_write(str, len);
1705 	spk_unlock(flags);
1706 }
1707 
speakup_con_update(struct vc_data * vc)1708 void speakup_con_update(struct vc_data *vc)
1709 {
1710 	unsigned long flags;
1711 	if (speakup_console[vc->vc_num] == NULL || spk_parked)
1712 		return;
1713 	if (!spk_trylock(flags))
1714 		/* Speakup output, discard */
1715 		return;
1716 	speakup_date(vc);
1717 	spk_unlock(flags);
1718 }
1719 
do_handle_spec(struct vc_data * vc,u_char value,char up_flag)1720 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1721 {
1722 	unsigned long flags;
1723 	int on_off = 2;
1724 	char *label;
1725 	if (synth == NULL || up_flag || spk_killed)
1726 		return;
1727 	spk_lock(flags);
1728 	spk_shut_up &= 0xfe;
1729 	if (no_intr)
1730 		do_flush();
1731 	switch (value) {
1732 	case KVAL(K_CAPS):
1733 		label = msg_get(MSG_KEYNAME_CAPSLOCK);
1734 		on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1735 		break;
1736 	case KVAL(K_NUM):
1737 		label = msg_get(MSG_KEYNAME_NUMLOCK);
1738 		on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1739 		break;
1740 	case KVAL(K_HOLD):
1741 		label = msg_get(MSG_KEYNAME_SCROLLLOCK);
1742 		on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1743 		if (speakup_console[vc->vc_num])
1744 			speakup_console[vc->vc_num]->tty_stopped = on_off;
1745 		break;
1746 	default:
1747 		spk_parked &= 0xfe;
1748 		spk_unlock(flags);
1749 		return;
1750 	}
1751 	if (on_off < 2)
1752 		synth_printf("%s %s\n",
1753 			     label, msg_get(MSG_STATUS_START + on_off));
1754 	spk_unlock(flags);
1755 }
1756 
inc_dec_var(u_char value)1757 static int inc_dec_var(u_char value)
1758 {
1759 	struct st_var_header *p_header;
1760 	struct var_t *var_data;
1761 	char num_buf[32];
1762 	char *cp = num_buf;
1763 	char *pn;
1764 	int var_id = (int)value - VAR_START;
1765 	int how = (var_id & 1) ? E_INC : E_DEC;
1766 	var_id = var_id / 2 + FIRST_SET_VAR;
1767 	p_header = get_var_header(var_id);
1768 	if (p_header == NULL)
1769 		return -1;
1770 	if (p_header->var_type != VAR_NUM)
1771 		return -1;
1772 	var_data = p_header->data;
1773 	if (set_num_var(1, p_header, how) != 0)
1774 		return -1;
1775 	if (!spk_close_press) {
1776 		for (pn = p_header->name; *pn; pn++) {
1777 			if (*pn == '_')
1778 				*cp = SPACE;
1779 			else
1780 				*cp++ = *pn;
1781 		}
1782 	}
1783 	snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1784 		 var_data->u.n.value);
1785 	synth_printf("%s", num_buf);
1786 	return 0;
1787 }
1788 
speakup_win_set(struct vc_data * vc)1789 static void speakup_win_set(struct vc_data *vc)
1790 {
1791 	char info[40];
1792 	if (win_start > 1) {
1793 		synth_printf("%s\n", msg_get(MSG_WINDOW_ALREADY_SET));
1794 		return;
1795 	}
1796 	if (spk_x < win_left || spk_y < win_top) {
1797 		synth_printf("%s\n", msg_get(MSG_END_BEFORE_START));
1798 		return;
1799 	}
1800 	if (win_start && spk_x == win_left && spk_y == win_top) {
1801 		win_left = 0;
1802 		win_right = vc->vc_cols - 1;
1803 		win_bottom = spk_y;
1804 		snprintf(info, sizeof(info), msg_get(MSG_WINDOW_LINE),
1805 			 (int)win_top + 1);
1806 	} else {
1807 		if (!win_start) {
1808 			win_top = spk_y;
1809 			win_left = spk_x;
1810 		} else {
1811 			win_bottom = spk_y;
1812 			win_right = spk_x;
1813 		}
1814 		snprintf(info, sizeof(info), msg_get(MSG_WINDOW_BOUNDARY),
1815 			 (win_start) ? msg_get(MSG_END) : msg_get(MSG_START),
1816 			 (int)spk_y + 1, (int)spk_x + 1);
1817 	}
1818 	synth_printf("%s\n", info);
1819 	win_start++;
1820 }
1821 
speakup_win_clear(struct vc_data * vc)1822 static void speakup_win_clear(struct vc_data *vc)
1823 {
1824 	win_top = win_bottom = 0;
1825 	win_left = win_right = 0;
1826 	win_start = 0;
1827 	synth_printf("%s\n", msg_get(MSG_WINDOW_CLEARED));
1828 }
1829 
speakup_win_enable(struct vc_data * vc)1830 static void speakup_win_enable(struct vc_data *vc)
1831 {
1832 	if (win_start < 2) {
1833 		synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
1834 		return;
1835 	}
1836 	win_enabled ^= 1;
1837 	if (win_enabled)
1838 		synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCED));
1839 	else
1840 		synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCE_DISABLED));
1841 }
1842 
speakup_bits(struct vc_data * vc)1843 static void speakup_bits(struct vc_data *vc)
1844 {
1845 	int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1846 	if (special_handler != NULL || val < 1 || val > 6) {
1847 		synth_printf("%s\n", msg_get(MSG_ERROR));
1848 		return;
1849 	}
1850 	pb_edit = &punc_info[val];
1851 	synth_printf(msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1852 	special_handler = edit_bits;
1853 }
1854 
handle_goto(struct vc_data * vc,u_char type,u_char ch,u_short key)1855 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1856 {
1857 	static u_char goto_buf[8];
1858 	static int num;
1859 	int maxlen, go_pos;
1860 	char *cp;
1861 	if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1862 		goto do_goto;
1863 	if (type == KT_LATIN && ch == '\n')
1864 		goto do_goto;
1865 	if (type != 0)
1866 		goto oops;
1867 	if (ch == 8) {
1868 		if (num == 0)
1869 			return -1;
1870 		ch = goto_buf[--num];
1871 		goto_buf[num] = '\0';
1872 		spkup_write(&ch, 1);
1873 		return 1;
1874 	}
1875 	if (ch < '+' || ch > 'y')
1876 		goto oops;
1877 	goto_buf[num++] = ch;
1878 	goto_buf[num] = '\0';
1879 	spkup_write(&ch, 1);
1880 	maxlen = (*goto_buf >= '0') ? 3 : 4;
1881 	if ((ch == '+' || ch == '-') && num == 1)
1882 		return 1;
1883 	if (ch >= '0' && ch <= '9' && num < maxlen)
1884 		return 1;
1885 	if (num < maxlen - 1 || num > maxlen)
1886 		goto oops;
1887 	if (ch < 'x' || ch > 'y') {
1888 oops:
1889 		if (!spk_killed)
1890 			synth_printf(" %s\n", msg_get(MSG_GOTO_CANCELED));
1891 		goto_buf[num = 0] = '\0';
1892 		special_handler = NULL;
1893 		return 1;
1894 	}
1895 	cp = speakup_s2i(goto_buf, &go_pos);
1896 	goto_pos = (u_long) go_pos;
1897 	if (*cp == 'x') {
1898 		if (*goto_buf < '0')
1899 			goto_pos += spk_x;
1900 		else
1901 			goto_pos--;
1902 		if (goto_pos < 0)
1903 			goto_pos = 0;
1904 		if (goto_pos >= vc->vc_cols)
1905 			goto_pos = vc->vc_cols - 1;
1906 		goto_x = 1;
1907 	} else {
1908 		if (*goto_buf < '0')
1909 			goto_pos += spk_y;
1910 		else
1911 			goto_pos--;
1912 		if (goto_pos < 0)
1913 			goto_pos = 0;
1914 		if (goto_pos >= vc->vc_rows)
1915 			goto_pos = vc->vc_rows - 1;
1916 		goto_x = 0;
1917 	}
1918 	goto_buf[num = 0] = '\0';
1919 do_goto:
1920 	special_handler = NULL;
1921 	spk_parked |= 0x01;
1922 	if (goto_x) {
1923 		spk_pos -= spk_x * 2;
1924 		spk_x = goto_pos;
1925 		spk_pos += goto_pos * 2;
1926 		say_word(vc);
1927 	} else {
1928 		spk_y = goto_pos;
1929 		spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1930 		say_line(vc);
1931 	}
1932 	return 1;
1933 }
1934 
speakup_goto(struct vc_data * vc)1935 static void speakup_goto(struct vc_data *vc)
1936 {
1937 	if (special_handler != NULL) {
1938 		synth_printf("%s\n", msg_get(MSG_ERROR));
1939 		return;
1940 	}
1941 	synth_printf("%s\n", msg_get(MSG_GOTO));
1942 	special_handler = handle_goto;
1943 	return;
1944 }
1945 
speakup_help(struct vc_data * vc)1946 static void speakup_help(struct vc_data *vc)
1947 {
1948 	handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1949 }
1950 
do_nothing(struct vc_data * vc)1951 static void do_nothing(struct vc_data *vc)
1952 {
1953 	return;			/* flush done in do_spkup */
1954 }
1955 
1956 static u_char key_speakup, spk_key_locked;
1957 
speakup_lock(struct vc_data * vc)1958 static void speakup_lock(struct vc_data *vc)
1959 {
1960 	if (!spk_key_locked)
1961 		spk_key_locked = key_speakup = 16;
1962 	else
1963 		spk_key_locked = key_speakup = 0;
1964 }
1965 
1966 typedef void (*spkup_hand) (struct vc_data *);
1967 spkup_hand spkup_handler[] = {
1968 	/* must be ordered same as defines in speakup.h */
1969 	do_nothing, speakup_goto, speech_kill, speakup_shut_up,
1970 	speakup_cut, speakup_paste, say_first_char, say_last_char,
1971 	say_char, say_prev_char, say_next_char,
1972 	say_word, say_prev_word, say_next_word,
1973 	say_line, say_prev_line, say_next_line,
1974 	top_edge, bottom_edge, left_edge, right_edge,
1975 	spell_word, spell_word, say_screen,
1976 	say_position, say_attributes,
1977 	speakup_off, speakup_parked, say_line,	/* this is for indent */
1978 	say_from_top, say_to_bottom,
1979 	say_from_left, say_to_right,
1980 	say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
1981 	speakup_bits, speakup_bits, speakup_bits,
1982 	speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
1983 	speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
1984 };
1985 
do_spkup(struct vc_data * vc,u_char value)1986 static void do_spkup(struct vc_data *vc, u_char value)
1987 {
1988 	if (spk_killed && value != SPEECH_KILL)
1989 		return;
1990 	spk_keydown = 0;
1991 	spk_lastkey = 0;
1992 	spk_shut_up &= 0xfe;
1993 	this_speakup_key = value;
1994 	if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
1995 		do_flush();
1996 		(*spkup_handler[value]) (vc);
1997 	} else {
1998 		if (inc_dec_var(value) < 0)
1999 			bleep(9);
2000 	}
2001 }
2002 
2003 static const char *pad_chars = "0123456789+-*/\015,.?()";
2004 
2005 int
speakup_key(struct vc_data * vc,int shift_state,int keycode,u_short keysym,int up_flag)2006 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2007 	    int up_flag)
2008 {
2009 	unsigned long flags;
2010 	int kh;
2011 	u_char *key_info;
2012 	u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2013 	u_char shift_info, offset;
2014 	int ret = 0;
2015 	if (synth == NULL)
2016 		return 0;
2017 
2018 	spk_lock(flags);
2019 	tty = vc->port.tty;
2020 	if (type >= 0xf0)
2021 		type -= 0xf0;
2022 	if (type == KT_PAD
2023 		&& (vt_get_leds(fg_console, VC_NUMLOCK))) {
2024 		if (up_flag) {
2025 			spk_keydown = 0;
2026 			goto out;
2027 		}
2028 		value = spk_lastkey = pad_chars[value];
2029 		spk_keydown++;
2030 		spk_parked &= 0xfe;
2031 		goto no_map;
2032 	}
2033 	if (keycode >= MAX_KEY)
2034 		goto no_map;
2035 	key_info = our_keys[keycode];
2036 	if (key_info == 0)
2037 		goto no_map;
2038 	/* Check valid read all mode keys */
2039 	if ((cursor_track == read_all_mode) && (!up_flag)) {
2040 		switch (value) {
2041 		case KVAL(K_DOWN):
2042 		case KVAL(K_UP):
2043 		case KVAL(K_LEFT):
2044 		case KVAL(K_RIGHT):
2045 		case KVAL(K_PGUP):
2046 		case KVAL(K_PGDN):
2047 			break;
2048 		default:
2049 			stop_read_all(vc);
2050 			break;
2051 		}
2052 	}
2053 	shift_info = (shift_state & 0x0f) + key_speakup;
2054 	offset = shift_table[shift_info];
2055 	if (offset) {
2056 		new_key = key_info[offset];
2057 		if (new_key) {
2058 			ret = 1;
2059 			if (new_key == SPK_KEY) {
2060 				if (!spk_key_locked)
2061 					key_speakup = (up_flag) ? 0 : 16;
2062 				if (up_flag || spk_killed)
2063 					goto out;
2064 				spk_shut_up &= 0xfe;
2065 				do_flush();
2066 				goto out;
2067 			}
2068 			if (up_flag)
2069 				goto out;
2070 			if (last_keycode == keycode &&
2071 			    last_spk_jiffy + MAX_DELAY > jiffies) {
2072 				spk_close_press = 1;
2073 				offset = shift_table[shift_info + 32];
2074 				/* double press? */
2075 				if (offset && key_info[offset])
2076 					new_key = key_info[offset];
2077 			}
2078 			last_keycode = keycode;
2079 			last_spk_jiffy = jiffies;
2080 			type = KT_SPKUP;
2081 			value = new_key;
2082 		}
2083 	}
2084 no_map:
2085 	if (type == KT_SPKUP && special_handler == NULL) {
2086 		do_spkup(vc, new_key);
2087 		spk_close_press = 0;
2088 		ret = 1;
2089 		goto out;
2090 	}
2091 	if (up_flag || spk_killed || type == KT_SHIFT)
2092 		goto out;
2093 	spk_shut_up &= 0xfe;
2094 	kh = (value == KVAL(K_DOWN))
2095 	    || (value == KVAL(K_UP))
2096 	    || (value == KVAL(K_LEFT))
2097 	    || (value == KVAL(K_RIGHT));
2098 	if ((cursor_track != read_all_mode) || !kh)
2099 		if (!no_intr)
2100 			do_flush();
2101 	if (special_handler) {
2102 		if (type == KT_SPEC && value == 1) {
2103 			value = '\n';
2104 			type = KT_LATIN;
2105 		} else if (type == KT_LETTER)
2106 			type = KT_LATIN;
2107 		else if (value == 0x7f)
2108 			value = 8;	/* make del = backspace */
2109 		ret = (*special_handler) (vc, type, value, keycode);
2110 		spk_close_press = 0;
2111 		if (ret < 0)
2112 			bleep(9);
2113 		goto out;
2114 	}
2115 	last_keycode = 0;
2116 out:
2117 	spk_unlock(flags);
2118 	return ret;
2119 }
2120 
keyboard_notifier_call(struct notifier_block * nb,unsigned long code,void * _param)2121 static int keyboard_notifier_call(struct notifier_block *nb,
2122 				  unsigned long code, void *_param)
2123 {
2124 	struct keyboard_notifier_param *param = _param;
2125 	struct vc_data *vc = param->vc;
2126 	int up = !param->down;
2127 	int ret = NOTIFY_OK;
2128 	static int keycode;	/* to hold the current keycode */
2129 
2130 	if (vc->vc_mode == KD_GRAPHICS)
2131 		return ret;
2132 
2133 	/*
2134 	 * First, determine whether we are handling a fake keypress on
2135 	 * the current processor.  If we are, then return NOTIFY_OK,
2136 	 * to pass the keystroke up the chain.  This prevents us from
2137 	 * trying to take the Speakup lock while it is held by the
2138 	 * processor on which the simulated keystroke was generated.
2139 	 * Also, the simulated keystrokes should be ignored by Speakup.
2140 	 */
2141 
2142 	if (speakup_fake_key_pressed())
2143 		return ret;
2144 
2145 	switch (code) {
2146 	case KBD_KEYCODE:
2147 		/* speakup requires keycode and keysym currently */
2148 		keycode = param->value;
2149 		break;
2150 	case KBD_UNBOUND_KEYCODE:
2151 		/* not used yet */
2152 		break;
2153 	case KBD_UNICODE:
2154 		/* not used yet */
2155 		break;
2156 	case KBD_KEYSYM:
2157 		if (speakup_key(vc, param->shift, keycode, param->value, up))
2158 			ret = NOTIFY_STOP;
2159 		else if (KTYP(param->value) == KT_CUR)
2160 			ret = pre_handle_cursor(vc, KVAL(param->value), up);
2161 		break;
2162 	case KBD_POST_KEYSYM:{
2163 			unsigned char type = KTYP(param->value) - 0xf0;
2164 			unsigned char val = KVAL(param->value);
2165 			switch (type) {
2166 			case KT_SHIFT:
2167 				do_handle_shift(vc, val, up);
2168 				break;
2169 			case KT_LATIN:
2170 			case KT_LETTER:
2171 				do_handle_latin(vc, val, up);
2172 				break;
2173 			case KT_CUR:
2174 				do_handle_cursor(vc, val, up);
2175 				break;
2176 			case KT_SPEC:
2177 				do_handle_spec(vc, val, up);
2178 				break;
2179 			}
2180 			break;
2181 		}
2182 	}
2183 	return ret;
2184 }
2185 
vt_notifier_call(struct notifier_block * nb,unsigned long code,void * _param)2186 static int vt_notifier_call(struct notifier_block *nb,
2187 			    unsigned long code, void *_param)
2188 {
2189 	struct vt_notifier_param *param = _param;
2190 	struct vc_data *vc = param->vc;
2191 	switch (code) {
2192 	case VT_ALLOCATE:
2193 		if (vc->vc_mode == KD_TEXT)
2194 			speakup_allocate(vc);
2195 		break;
2196 	case VT_DEALLOCATE:
2197 		speakup_deallocate(vc);
2198 		break;
2199 	case VT_WRITE:
2200 		if (param->c == '\b')
2201 			speakup_bs(vc);
2202 		else if (param->c < 0x100) {
2203 			char d = param->c;
2204 			speakup_con_write(vc, &d, 1);
2205 		}
2206 		break;
2207 	case VT_UPDATE:
2208 		speakup_con_update(vc);
2209 		break;
2210 	}
2211 	return NOTIFY_OK;
2212 }
2213 
2214 /* called by: module_exit() */
speakup_exit(void)2215 static void __exit speakup_exit(void)
2216 {
2217 	int i;
2218 
2219 	unregister_keyboard_notifier(&keyboard_notifier_block);
2220 	unregister_vt_notifier(&vt_notifier_block);
2221 	speakup_unregister_devsynth();
2222 	del_timer(&cursor_timer);
2223 	kthread_stop(speakup_task);
2224 	speakup_task = NULL;
2225 	mutex_lock(&spk_mutex);
2226 	synth_release();
2227 	mutex_unlock(&spk_mutex);
2228 
2229 	speakup_kobj_exit();
2230 
2231 	for (i = 0; i < MAX_NR_CONSOLES; i++)
2232 		kfree(speakup_console[i]);
2233 
2234 	speakup_remove_virtual_keyboard();
2235 
2236 	for (i = 0; i < MAXVARS; i++)
2237 		speakup_unregister_var(i);
2238 
2239 	for (i = 0; i < 256; i++) {
2240 		if (characters[i] != default_chars[i])
2241 			kfree(characters[i]);
2242 	}
2243 
2244 	free_user_msgs();
2245 }
2246 
2247 /* call by: module_init() */
speakup_init(void)2248 static int __init speakup_init(void)
2249 {
2250 	int i;
2251 	long err = 0;
2252 	struct st_spk_t *first_console;
2253 	struct vc_data *vc = vc_cons[fg_console].d;
2254 	struct var_t *var;
2255 
2256 	/* These first few initializations cannot fail. */
2257 	initialize_msgs();	/* Initialize arrays for i18n. */
2258 	reset_default_chars();
2259 	reset_default_chartab();
2260 	strlwr(synth_name);
2261 	spk_vars[0].u.n.high = vc->vc_cols;
2262 	for (var = spk_vars; var->var_id != MAXVARS; var++)
2263 		speakup_register_var(var);
2264 	for (var = synth_time_vars;
2265 	     (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2266 		speakup_register_var(var);
2267 	for (i = 1; punc_info[i].mask != 0; i++)
2268 		set_mask_bits(0, i, 2);
2269 
2270 	set_key_info(key_defaults, key_buf);
2271 
2272 	/* From here on out, initializations can fail. */
2273 	err = speakup_add_virtual_keyboard();
2274 	if (err)
2275 		goto error_virtkeyboard;
2276 
2277 	first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2278 	if (!first_console) {
2279 		err = -ENOMEM;
2280 		goto error_alloc;
2281 	}
2282 
2283 	speakup_console[vc->vc_num] = first_console;
2284 	speakup_date(vc);
2285 
2286 	for (i = 0; i < MAX_NR_CONSOLES; i++)
2287 		if (vc_cons[i].d) {
2288 			err = speakup_allocate(vc_cons[i].d);
2289 			if (err)
2290 				goto error_kobjects;
2291 		}
2292 
2293 	if (quiet_boot)
2294 		spk_shut_up |= 0x01;
2295 
2296 	err = speakup_kobj_init();
2297 	if (err)
2298 		goto error_kobjects;
2299 
2300 	synth_init(synth_name);
2301 	speakup_register_devsynth();
2302 	/*
2303 	 * register_devsynth might fail, but this error is not fatal.
2304 	 * /dev/synth is an extra feature; the rest of Speakup
2305 	 * will work fine without it.
2306 	 */
2307 
2308 	err = register_keyboard_notifier(&keyboard_notifier_block);
2309 	if (err)
2310 		goto error_kbdnotifier;
2311 	err = register_vt_notifier(&vt_notifier_block);
2312 	if (err)
2313 		goto error_vtnotifier;
2314 
2315 	speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2316 
2317 	if (IS_ERR(speakup_task)) {
2318 		err = PTR_ERR(speakup_task);
2319 		goto error_task;
2320 	}
2321 
2322 	set_user_nice(speakup_task, 10);
2323 	wake_up_process(speakup_task);
2324 
2325 	pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2326 	pr_info("synth name on entry is: %s\n", synth_name);
2327 	goto out;
2328 
2329 error_task:
2330 	unregister_vt_notifier(&vt_notifier_block);
2331 
2332 error_vtnotifier:
2333 	unregister_keyboard_notifier(&keyboard_notifier_block);
2334 	del_timer(&cursor_timer);
2335 
2336 error_kbdnotifier:
2337 	speakup_unregister_devsynth();
2338 	mutex_lock(&spk_mutex);
2339 	synth_release();
2340 	mutex_unlock(&spk_mutex);
2341 	speakup_kobj_exit();
2342 
2343 error_kobjects:
2344 	for (i = 0; i < MAX_NR_CONSOLES; i++)
2345 		kfree(speakup_console[i]);
2346 
2347 error_alloc:
2348 	speakup_remove_virtual_keyboard();
2349 
2350 error_virtkeyboard:
2351 	for (i = 0; i < MAXVARS; i++)
2352 		speakup_unregister_var(i);
2353 
2354 	for (i = 0; i < 256; i++) {
2355 		if (characters[i] != default_chars[i])
2356 			kfree(characters[i]);
2357 	}
2358 
2359 	free_user_msgs();
2360 
2361 out:
2362 	return err;
2363 }
2364 
2365 module_init(speakup_init);
2366 module_exit(speakup_exit);
2367