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