1c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* speakup.c
216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * review functions for the speakup screen review package.
316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * originally written by: Kirk Reiser and Andy Berdan.
416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *
516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * extensively modified by David Borowski.
616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *
716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs ** Copyright (C) 1998  Kirk Reiser.
816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  Copyright (C) 2003  David Borowski.
916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *
1016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  This program is free software; you can redistribute it and/or modify
1116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  it under the terms of the GNU General Public License as published by
1216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  the Free Software Foundation; either version 2 of the License, or
1316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  (at your option) any later version.
1416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *
1516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  This program is distributed in the hope that it will be useful,
1616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  GNU General Public License for more details.
1916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *
2016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  You should have received a copy of the GNU General Public License
2116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  along with this program; if not, write to the Free Software
2216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs*/
24c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
25c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/kernel.h>
26c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/vt.h>
27c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/tty.h>
2816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs#include <linux/mm.h>		/* __get_free_page() and friends */
29c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/vt_kern.h>
30c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/ctype.h>
31c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/selection.h>
32c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/unistd.h>
33c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/jiffies.h>
34c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/kthread.h>
35c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/keyboard.h>	/* for KT_SHIFT */
3616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs#include <linux/kbd_kern.h>	/* for vc_kbd_* and friends */
37c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/input.h>
38c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/kmod.h>
39c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
40c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/bootmem.h>	/* for alloc_bootmem */
41c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
42c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* speakup_*_selection */
43c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/module.h>
44c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/sched.h>
45c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/slab.h>
46c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/types.h>
47c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/consolemap.h>
48c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
49c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/spinlock.h>
50c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/notifier.h>
51c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
5216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs#include <linux/uaccess.h>	/* copy_from|to|user() and others */
53c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
54c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include "spk_priv.h"
55c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include "speakup.h"
56c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
57c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#define MAX_DELAY msecs_to_jiffies(500)
58c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#define MINECHOCHAR SPACE
59c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
60c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
61c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
62c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_DESCRIPTION("Speakup console speech");
63c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_LICENSE("GPL");
64c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_VERSION(SPEAKUP_VERSION);
65c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
66c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbschar *synth_name;
67c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsmodule_param_named(synth, synth_name, charp, S_IRUGO);
68c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsmodule_param_named(quiet, quiet_boot, bool, S_IRUGO);
69c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
70c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
71c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
72c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
73c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsspecial_func special_handler;
74c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
75c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsshort pitch_shift, synth_flags;
76c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic char buf[256];
77c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsint attrib_bleep, bleeps, bleep_time = 10;
78c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsint no_intr, spell_delay;
79c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsint key_echo, say_word_ctl;
80c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsint say_ctrl, bell_pos;
81c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsshort punc_mask;
82c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsint punc_level, reading_punc;
8316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbschar str_caps_start[MAXVARLEN + 1] = "\0", str_caps_stop[MAXVARLEN + 1] = "\0";
84c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsconst struct st_bits_data punc_info[] = {
8516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"none", "", 0},
8616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"some", "/$%&@", SOME},
8716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"most", "$%&#()=+*/@^<>|\\", MOST},
8816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
8916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"delimiters", "", B_WDLM},
9016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"repeats", "()", CH_RPT},
9116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"extended numeric", "", B_EXNUM},
9216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"symbols", "", B_SYM},
9316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{0, 0}
94c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
9516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs
96c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic char mark_cut_flag;
97c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#define MAX_KEY 160
98c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsu_char *our_keys[MAX_KEY], *shift_table;
99c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsu_char key_buf[600];
100c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsconst u_char key_defaults[] = {
101c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include "speakupmap.h"
102c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
103c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
104c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* Speakup Cursor Track Variables */
105c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int cursor_track = 1, prev_cursor_track = 1;
106c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
107c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* cursor track modes, must be ordered same as cursor_msgs */
108c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsenum {
109c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	CT_Off = 0,
110c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	CT_On,
111c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	CT_Highlight,
112c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	CT_Window,
113c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	CT_Max
114c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
115c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#define read_all_mode CT_Max
116c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
117c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic struct tty_struct *tty;
118c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
119c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void spkup_write(const char *in_buf, int count);
120c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
121c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic char *phonetic[] = {
122c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	"alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
12316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	"india", "juliett", "keelo", "leema", "mike", "november", "oscar",
12416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "papa",
125c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	"keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
126c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	"x ray", "yankee", "zulu"
127c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
128c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
129c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* array of 256 char pointers (one for each character description)
130c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs * initialized to default_chars and user selectable via
131c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs * /proc/speakup/characters */
132c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbschar *characters[256];
133c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
134c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbschar *default_chars[256] = {
13516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
136c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
137c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
13816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
13916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "control",
14016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
14116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "tick",
14216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
14316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "dot",
144c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	"slash",
145c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
146c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	"eight", "nine",
147c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
148c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
149c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
150c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
15116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
15216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "caret",
153c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	"line",
154c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
155c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
156c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
157c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
15816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*127*/ "del", "control", "control", "control", "control", "control",
15916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "control", "control", "control", "control", "control",
16016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*138*/ "control", "control", "control", "control", "control",
16116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "control", "control", "control", "control", "control",
16216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "control", "control",
16316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*150*/ "control", "control", "control", "control", "control",
16416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "control", "control", "control", "control", "control",
165c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*160*/ "nbsp", "inverted bang",
16616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
16716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
168c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*172*/ "not", "soft hyphen", "registered", "macron",
16916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*176*/ "degrees", "plus or minus", "super two", "super three",
17016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*180*/ "acute accent", "micro", "pilcrow", "middle dot",
171c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*184*/ "cedilla", "super one", "male ordinal", "double right angle",
17216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*188*/ "one quarter", "one half", "three quarters",
17316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "inverted question",
17416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
17516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "A RING",
17616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
17716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "E OOMLAUT",
17816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
17916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "N TILDE",
180c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
18116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
18216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "U CIRCUMFLEX",
183c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
184c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
185c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*230*/ "ae", "c cidella", "e grave", "e acute",
18616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
18716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "i circumflex",
18816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
18916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "o circumflex",
19016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
19116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "u acute",
192c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
193c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
194c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
195c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* array of 256 u_short (one for each character)
196c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs * initialized to default_chartab and user selectable via
197c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs * /sys/module/speakup/parameters/chartab */
198c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsu_short spk_chartab[256];
199c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
200c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_short default_chartab[256] = {
20116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,	/* 0-7 */
20216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,	/* 8-15 */
20316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,	/*16-23 */
20416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,	/* 24-31 */
20516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,	/*  !"#$%&' */
20616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC,	/* ()*+, -./ */
20716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM,	/* 01234567 */
20816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,	/* 89:;<=>? */
20916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* @ABCDEFG */
21016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* HIJKLMNO */
21116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* PQRSTUVW */
21216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC,	/* XYZ[\]^_ */
21316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* `abcdefg */
21416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* hijklmno */
21516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* pqrstuvw */
21616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0,	/* xyz{|}~ */
21716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
21816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM,	/* 135 */
21916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
22016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CAPSYM,	/* 143 */
22116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
22216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM,	/* 151 */
22316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
22416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM,	/* 159 */
22516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
22616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM,	/* 167 */
22716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,	/* 168-175 */
22816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,	/* 176-183 */
22916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,	/* 184-191 */
23016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* 192-199 */
23116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* 200-207 */
23216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM,	/* 208-215 */
23316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA,	/* 216-223 */
23416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* 224-231 */
23516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* 232-239 */
23616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM,	/* 240-247 */
23716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA	/* 248-255 */
238c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
239c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
240c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstruct task_struct *speakup_task;
241c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstruct bleep unprocessed_sound;
242c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int spk_keydown;
243c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_char spk_lastkey, spk_close_press, keymap_flags;
244c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_char last_keycode, this_speakup_key;
245c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_long last_spk_jiffy;
246c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
247c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstruct st_spk_t *speakup_console[MAX_NR_CONSOLES];
248c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
249c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsDEFINE_MUTEX(spk_mutex);
250c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
251c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int keyboard_notifier_call(struct notifier_block *,
252c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				  unsigned long code, void *param);
253c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
254c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstruct notifier_block keyboard_notifier_block = {
255c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	.notifier_call = keyboard_notifier_call,
256c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
257c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
258c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int vt_notifier_call(struct notifier_block *,
259c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			    unsigned long code, void *param);
260c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
261c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstruct notifier_block vt_notifier_block = {
262c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	.notifier_call = vt_notifier_call,
263c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
264c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
265c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic unsigned char get_attributes(u16 *pos)
266c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
26716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	return (u_char) (scr_readw(pos) >> 8);
268c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
269c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
270c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_date(struct vc_data *vc)
271c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
272c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x = spk_cx = vc->vc_x;
273c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_y = spk_cy = vc->vc_y;
274c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos = spk_cp = vc->vc_pos;
275c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
276c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_attr = get_attributes((u_short *) spk_pos);
277c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
278c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
279c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void bleep(u_short val)
280c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
281c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	static const short vals[] = {
282c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
283c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	};
284c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	short freq;
285c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int time = bleep_time;
28616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	freq = vals[val % 12];
287c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (val > 11)
28816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		freq *= (1 << (val / 12));
289c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unprocessed_sound.freq = freq;
290c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unprocessed_sound.jiffies = msecs_to_jiffies(time);
291c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unprocessed_sound.active = 1;
292c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/* We can only have 1 active sound at a time. */
293c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
294c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
295c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_shut_up(struct vc_data *vc)
296c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
297c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_killed)
298c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
299c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up |= 0x01;
300c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked &= 0xfe;
301c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_date(vc);
302c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (synth != NULL)
303c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		do_flush();
304c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
305c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
306c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speech_kill(struct vc_data *vc)
307c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
308c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char val = synth->is_alive(synth);
309c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (val == 0)
310c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
311c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
312c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/* re-enables synth, if disabled */
313c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (val == 2 || spk_killed) {
314c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* dead */
315c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_shut_up &= ~0x40;
316c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_IAM_ALIVE));
317c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
318c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_YOU_KILLED_SPEAKUP));
319c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_shut_up |= 0x40;
320c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
321c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
322c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
323c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_off(struct vc_data *vc)
324c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
325c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_shut_up & 0x80) {
326c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_shut_up &= 0x7f;
327c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_HEY_THATS_BETTER));
328c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
329c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_shut_up |= 0x80;
330c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_YOU_TURNED_ME_OFF));
331c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
332c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_date(vc);
333c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
334c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
335c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_parked(struct vc_data *vc)
336c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
337c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_parked & 0x80) {
338c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_parked = 0;
339c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_UNPARKED));
340c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
341c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_parked |= 0x80;
342c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_PARKED));
343c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
344c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
345c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
346c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_cut(struct vc_data *vc)
347c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
348c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	static const char err_buf[] = "set selection failed";
349c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int ret;
350c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
351c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!mark_cut_flag) {
352c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		mark_cut_flag = 1;
353c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		xs = (u_short) spk_x;
354c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		ys = (u_short) spk_y;
355c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_sel_cons = vc;
356c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_MARK));
357c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
358c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
359c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	xe = (u_short) spk_x;
360c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	ye = (u_short) spk_y;
361c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	mark_cut_flag = 0;
362c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%s\n", msg_get(MSG_CUT));
363c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
364c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_clear_selection();
365c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	ret = speakup_set_selection(tty);
366c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
367c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	switch (ret) {
368c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case 0:
36916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		break;		/* no error */
37016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	case -EFAULT:
371c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		pr_warn("%sEFAULT\n", err_buf);
372c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
37316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	case -EINVAL:
374c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		pr_warn("%sEINVAL\n", err_buf);
375c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
37616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	case -ENOMEM:
377c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		pr_warn("%sENOMEM\n", err_buf);
378c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
379c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
380c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
381c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
382c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_paste(struct vc_data *vc)
383c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
384c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (mark_cut_flag) {
385c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		mark_cut_flag = 0;
386c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_MARK_CLEARED));
387c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
388c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_PASTE));
389c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_paste_selection(tty);
390c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
391c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
392c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
393c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_attributes(struct vc_data *vc)
394c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
395c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int fg = spk_attr & 0x0f;
396c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int bg = spk_attr >> 4;
397c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (fg > 8) {
398c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s ", msg_get(MSG_BRIGHT));
399c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		fg -= 8;
400c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
401c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%s", msg_get(MSG_COLORS_START + fg));
402c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (bg > 7) {
403c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf(" %s ", msg_get(MSG_ON_BLINKING));
404c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		bg -= 8;
405c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else
406c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf(" %s ", msg_get(MSG_ON));
407c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%s\n", msg_get(MSG_COLORS_START + bg));
408c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
409c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
410c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsenum {
411c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	edge_top = 1,
412c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	edge_bottom,
413c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	edge_left,
414c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	edge_right,
415c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	edge_quiet
416c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
417c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
418c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void announce_edge(struct vc_data *vc, int msg_id)
419c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
420c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (bleeps & 1)
421c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		bleep(spk_y);
422c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if ((bleeps & 2) && (msg_id < edge_quiet))
423c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
424c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
425c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
426c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speak_char(u_char ch)
427c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
428c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char *cp = characters[ch];
429c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct var_t *direct = get_var(DIRECT);
430c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (direct && direct->u.n.value) {
431c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (IS_CHAR(ch, B_CAP)) {
432c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			pitch_shift++;
433c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf("%s", str_caps_start);
434c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
435c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%c", ch);
436c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (IS_CHAR(ch, B_CAP))
437c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf("%s", str_caps_stop);
438c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
439c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
440c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cp == NULL) {
441c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		pr_info("speak_char: cp == NULL!\n");
442c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
443c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
444c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_buffer_add(SPACE);
445c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (IS_CHAR(ch, B_CAP)) {
446c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		pitch_shift++;
447c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s", str_caps_start);
448c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s", cp);
449c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s", str_caps_stop);
450c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
451c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (*cp == '^') {
452c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf("%s", msg_get(MSG_CTRL));
453c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			cp++;
454c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
455c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s", cp);
456c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
457c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_buffer_add(SPACE);
458c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
459c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
46016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic u16 get_char(struct vc_data *vc, u16 * pos, u_char * attribs)
461c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
462c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u16 ch = ' ';
463c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (vc && pos) {
464c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		u16 w = scr_readw(pos);
465c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		u16 c = w & 0xff;
466c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
467c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (w & vc->vc_hi_font_mask)
468c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			c |= 0x100;
469c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
470c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		ch = inverse_translate(vc, c, 0);
471c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		*attribs = (w & 0xff00) >> 8;
472c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
473c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return ch;
474c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
475c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
476c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_char(struct vc_data *vc)
477c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
478c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short ch;
479c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
480c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
481c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_attr != spk_old_attr) {
482c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (attrib_bleep & 1)
483c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			bleep(spk_y);
484c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (attrib_bleep & 2)
485c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			say_attributes(vc);
486c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
487c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speak_char(ch & 0xff);
488c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
489c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
490c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_phonetic_char(struct vc_data *vc)
491c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
492c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short ch;
493c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
494c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
495c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (isascii(ch) && isalpha(ch)) {
496c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		ch &= 0x1f;
497c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", phonetic[--ch]);
498c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
499c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (IS_CHAR(ch, B_NUM))
500c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf("%s ", msg_get(MSG_NUMBER));
501c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speak_char(ch);
502c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
503c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
504c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
505c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_prev_char(struct vc_data *vc)
506c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
507c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
508c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_x == 0) {
509c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_left);
510c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
511c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
512c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x--;
513c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos -= 2;
514c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_char(vc);
515c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
516c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
517c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_next_char(struct vc_data *vc)
518c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
519c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
520c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_x == vc->vc_cols - 1) {
521c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_right);
522c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
523c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
524c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x++;
525c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos += 2;
526c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_char(vc);
527c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
528c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
529c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* get_word - will first check to see if the character under the
53016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * reading cursor is a space and if say_word_ctl is true it will
53116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * return the word space.  If say_word_ctl is not set it will check to
53216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * see if there is a word starting on the next position to the right
53316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * and return that word if it exists.  If it does not exist it will
53416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * move left to the beginning of any previous word on the line or the
53516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * beginning off the line whichever comes first.. */
536c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
537c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_long get_word(struct vc_data *vc)
538c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
539c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
540c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char ch;
541c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short attr_ch;
542c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char temp;
543c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
54416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
545c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
546c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* decided to take out the sayword if on a space (mis-information */
547c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (say_word_ctl && ch == SPACE) {
548c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		*buf = '\0';
549c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_SPACE));
550c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 0;
551c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else if ((tmpx < vc->vc_cols - 2)
552c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		   && (ch == SPACE || ch == 0 || IS_WDLM(ch))
55316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		   && ((char)get_char(vc, (u_short *) &tmp_pos + 1, &temp) >
55416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		       SPACE)) {
555c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		tmp_pos += 2;
556c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		tmpx++;
557c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else
558c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		while (tmpx > 0) {
55916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			ch = (char)get_char(vc, (u_short *) tmp_pos - 1, &temp);
560c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
56116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			    && ((char)get_char(vc, (u_short *) tmp_pos, &temp) >
56216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				SPACE))
563c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				break;
564c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			tmp_pos -= 2;
565c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			tmpx--;
566c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
567c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	attr_ch = get_char(vc, (u_short *) tmp_pos, &spk_attr);
568c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	buf[cnt++] = attr_ch & 0xff;
569c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (tmpx < vc->vc_cols - 1) {
570c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		tmp_pos += 2;
571c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		tmpx++;
57216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
57316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		if ((ch == SPACE) || ch == 0
57416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		    || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
575c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
576c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		buf[cnt++] = ch;
577c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
578c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	buf[cnt] = '\0';
579c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return cnt;
580c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
581c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
582c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_word(struct vc_data *vc)
583c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
584c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long cnt = get_word(vc);
585c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short saved_punc_mask = punc_mask;
586c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cnt == 0)
587c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
588c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	punc_mask = PUNC;
589c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	buf[cnt++] = SPACE;
590c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spkup_write(buf, cnt);
591c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	punc_mask = saved_punc_mask;
592c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
593c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
594c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_prev_word(struct vc_data *vc)
595c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
596c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char temp;
597c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char ch;
598c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short edge_said = 0, last_state = 0, state = 0;
599c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
600c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
601c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_x == 0) {
602c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (spk_y == 0) {
603c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			announce_edge(vc, edge_top);
604c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			return;
605c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
606c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_y--;
607c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_x = vc->vc_cols;
608c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		edge_said = edge_quiet;
609c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
610c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (1) {
611c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (spk_x == 0) {
612c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (spk_y == 0) {
613c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				edge_said = edge_top;
614c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				break;
615c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
616c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (edge_said != edge_quiet)
617c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				edge_said = edge_left;
618c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (state > 0)
619c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				break;
620c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_y--;
621c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_x = vc->vc_cols - 1;
622c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else
623c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_x--;
62416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		spk_pos -= 2;
62516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
626c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (ch == SPACE || ch == 0)
627c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 0;
628c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else if (IS_WDLM(ch))
629c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 1;
630c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else
631c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 2;
632c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (state < last_state) {
633c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_pos += 2;
634c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_x++;
635c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
636c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
637c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		last_state = state;
638c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
639c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_x == 0 && edge_said == edge_quiet)
640c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		edge_said = edge_left;
641c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (edge_said > 0 && edge_said < edge_quiet)
642c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_said);
643c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_word(vc);
644c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
645c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
646c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_next_word(struct vc_data *vc)
647c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
648c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char temp;
649c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char ch;
650c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short edge_said = 0, last_state = 2, state = 0;
651c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
652c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
653c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
654c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_bottom);
655c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
656c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
657c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (1) {
65816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
659c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (ch == SPACE || ch == 0)
660c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 0;
661c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else if (IS_WDLM(ch))
662c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 1;
663c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else
664c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 2;
665c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (state > last_state)
666c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
667c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (spk_x >= vc->vc_cols - 1) {
668c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (spk_y == vc->vc_rows - 1) {
669c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				edge_said = edge_bottom;
670c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				break;
671c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
672c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 0;
673c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_y++;
674c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_x = 0;
675c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			edge_said = edge_right;
676c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else
677c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_x++;
678c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_pos += 2;
679c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		last_state = state;
680c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
681c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (edge_said > 0)
682c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_said);
683c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_word(vc);
684c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
685c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
686c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void spell_word(struct vc_data *vc)
687c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
688c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	static char *delay_str[] = { "", ",", ".", ". .", ". . ." };
689c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char *cp = buf, *str_cap = str_caps_stop;
690c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char *cp1, *last_cap = str_caps_stop;
691c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char ch;
692c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!get_word(vc))
693c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
694c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while ((ch = (u_char) *cp)) {
695c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (cp != buf)
696c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf(" %s ", delay_str[spell_delay]);
697c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (IS_CHAR(ch, B_CAP)) {
698c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			str_cap = str_caps_start;
699c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (*str_caps_stop)
700c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				pitch_shift++;
70116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			else	/* synth has no pitch */
702c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				last_cap = str_caps_stop;
703c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else
704c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			str_cap = str_caps_stop;
705c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (str_cap != last_cap) {
706c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf("%s", str_cap);
707c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			last_cap = str_cap;
708c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
709c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (this_speakup_key == SPELL_PHONETIC
710c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		    && (isascii(ch) && isalpha(ch))) {
711c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			ch &= 31;
712c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			cp1 = phonetic[--ch];
713c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else {
714c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			cp1 = characters[ch];
715c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (*cp1 == '^') {
716c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_printf("%s", msg_get(MSG_CTRL));
717c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				cp1++;
718c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
719c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
720c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s", cp1);
721c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		cp++;
722c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
723c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (str_cap != str_caps_stop)
724c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s", str_caps_stop);
725c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
726c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
727c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int get_line(struct vc_data *vc)
728c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
729c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long tmp = spk_pos - (spk_x * 2);
730c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i = 0;
731c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char tmp2;
732c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
733c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
734c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_attr = get_attributes((u_short *) spk_pos);
735c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < vc->vc_cols; i++) {
736c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		buf[i] = (u_char) get_char(vc, (u_short *) tmp, &tmp2);
737c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		tmp += 2;
738c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
739c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (--i; i >= 0; i--)
740c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (buf[i] != SPACE)
741c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
742c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return ++i;
743c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
744c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
745c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_line(struct vc_data *vc)
746c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
747c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i = get_line(vc);
748c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char *cp;
749c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short saved_punc_mask = punc_mask;
750c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (i == 0) {
751c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_BLANK));
752c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
753c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
754c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	buf[i++] = '\n';
755c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (this_speakup_key == SAY_LINE_INDENT) {
75616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		cp = buf;
75716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		while (*cp == SPACE)
75816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			cp++;
759c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%d, ", (cp - buf) + 1);
760c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
761c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	punc_mask = punc_masks[reading_punc];
762c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spkup_write(buf, i);
763c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	punc_mask = saved_punc_mask;
764c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
765c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
766c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_prev_line(struct vc_data *vc)
767c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
768c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
769c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_y == 0) {
770c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_top);
771c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
772c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
773c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_y--;
774c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos -= vc->vc_size_row;
775c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line(vc);
776c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
777c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
778c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_next_line(struct vc_data *vc)
779c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
780c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
781c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_y == vc->vc_rows - 1) {
782c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_bottom);
783c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
784c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
785c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_y++;
786c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos += vc->vc_size_row;
787c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line(vc);
788c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
789c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
790c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int say_from_to(struct vc_data *vc, u_long from, u_long to,
791c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		       int read_punc)
792c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
793c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i = 0;
794c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char tmp;
795c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short saved_punc_mask = punc_mask;
796c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
797c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_attr = get_attributes((u_short *) from);
798c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (from < to) {
79916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		buf[i++] = (char)get_char(vc, (u_short *) from, &tmp);
800c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		from += 2;
801c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (i >= vc->vc_size_row)
802c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
803c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
804c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (--i; i >= 0; i--)
805c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (buf[i] != SPACE)
806c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
807c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	buf[++i] = SPACE;
808c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	buf[++i] = '\0';
809c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (i < 1)
810c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return i;
811c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (read_punc)
812c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		punc_mask = punc_info[reading_punc].mask;
813c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spkup_write(buf, i);
814c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (read_punc)
815c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		punc_mask = saved_punc_mask;
816c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return i - 1;
817c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
818c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
819c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
820c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			     int read_punc)
821c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
822c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
823c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long end = start + (to * 2);
824c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	start += from * 2;
825c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (say_from_to(vc, start, end, read_punc) <= 0)
826c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (cursor_track != read_all_mode)
827c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf("%s\n", msg_get(MSG_BLANK));
828c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
829c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
830c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* Sentence Reading Commands */
831c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
832c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int currsentence;
833c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int numsentences[2];
834c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic char *sentbufend[2];
835c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic char *sentmarks[2][10];
836c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int currbuf;
837c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int bn;
838c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic char sentbuf[2][256];
839c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
84016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic int say_sentence_num(int num, int prev)
841c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
842c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	bn = currbuf;
843c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	currsentence = num + 1;
844c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (prev && --bn == -1)
845c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		bn = 1;
846c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
847c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (num > numsentences[bn])
848c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 0;
849c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
850c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
851c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return 1;
852c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
853c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
854c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int get_sentence_buf(struct vc_data *vc, int read_punc)
855c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
856c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long start, end;
857c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i, bn;
858c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char tmp;
859c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
860c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	currbuf++;
861c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (currbuf == 2)
862c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		currbuf = 0;
863c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	bn = currbuf;
864c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
86516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
866c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
867c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	numsentences[bn] = 0;
868c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	sentmarks[bn][0] = &sentbuf[bn][0];
869c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	i = 0;
870c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
871c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_attr = get_attributes((u_short *) start);
872c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
873c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (start < end) {
87416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		sentbuf[bn][i] = (char)get_char(vc, (u_short *) start, &tmp);
875c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (i > 0) {
87616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
877c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			    && numsentences[bn] < 9) {
878c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				/* Sentence Marker */
879c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				numsentences[bn]++;
880c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				sentmarks[bn][numsentences[bn]] =
88116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				    &sentbuf[bn][i];
882c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
883c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
884c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		i++;
885c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		start += 2;
886c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (i >= vc->vc_size_row)
887c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
888c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
889c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
890c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (--i; i >= 0; i--)
891c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (sentbuf[bn][i] != SPACE)
892c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
893c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
894c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (i < 1)
895c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
896c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
897c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	sentbuf[bn][++i] = SPACE;
898c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	sentbuf[bn][++i] = '\0';
899c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
900c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	sentbufend[bn] = &sentbuf[bn][i];
901c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return numsentences[bn];
902c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
903c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
904c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
905c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
906c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long start = vc->vc_origin, end;
907c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (from > 0)
908c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		start += from * vc->vc_size_row;
909c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (to > vc->vc_rows)
910c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		to = vc->vc_rows;
911c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	end = vc->vc_origin + (to * vc->vc_size_row);
912c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (from = start; from < end; from = to) {
913c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		to = from + vc->vc_size_row;
914c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_from_to(vc, from, to, 1);
915c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
916c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
917c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
918c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_screen(struct vc_data *vc)
919c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
920c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_screen_from_to(vc, 0, vc->vc_rows);
921c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
922c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
923c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_win_say(struct vc_data *vc)
924c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
925c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long start, end, from, to;
926c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_start < 2) {
927c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
928c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
929c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
930c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	start = vc->vc_origin + (win_top * vc->vc_size_row);
931c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	end = vc->vc_origin + (win_bottom * vc->vc_size_row);
932c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (start <= end) {
933c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		from = start + (win_left * 2);
934c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		to = start + (win_right * 2);
935c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_from_to(vc, from, to, 1);
936c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		start += vc->vc_size_row;
937c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
938c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
939c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
940c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void top_edge(struct vc_data *vc)
941c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
942c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
943c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos = vc->vc_origin + 2 * spk_x;
944c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_y = 0;
945c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line(vc);
946c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
947c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
948c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void bottom_edge(struct vc_data *vc)
949c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
950c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
951c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
952c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_y = vc->vc_rows - 1;
953c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line(vc);
954c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
955c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
956c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void left_edge(struct vc_data *vc)
957c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
958c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
959c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos -= spk_x * 2;
960c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x = 0;
961c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_char(vc);
962c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
963c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
964c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void right_edge(struct vc_data *vc)
965c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
966c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
967c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos += (vc->vc_cols - spk_x - 1) * 2;
968c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x = vc->vc_cols - 1;
969c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_char(vc);
970c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
971c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
972c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_first_char(struct vc_data *vc)
973c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
974c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i, len = get_line(vc);
975c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char ch;
976c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
977c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (len == 0) {
978c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_BLANK));
979c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
980c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
981c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < len; i++)
982c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (buf[i] != SPACE)
983c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
984c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	ch = buf[i];
985c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos -= (spk_x - i) * 2;
986c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x = i;
987c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%d, ", ++i);
988c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speak_char(ch);
989c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
990c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
991c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_last_char(struct vc_data *vc)
992c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
993c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int len = get_line(vc);
994c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char ch;
995c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
996c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (len == 0) {
997c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_BLANK));
998c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
999c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1000c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	ch = buf[--len];
1001c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos -= (spk_x - len) * 2;
1002c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x = len;
1003c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%d, ", ++len);
1004c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speak_char(ch);
1005c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1006c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1007c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_position(struct vc_data *vc)
1008c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1009c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf(msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
101016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		     vc->vc_num + 1);
1011c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("\n");
1012c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1013c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1014c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* Added by brianb */
1015c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_char_num(struct vc_data *vc)
1016c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1017c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char tmp;
1018c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
1019c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	ch &= 0xff;
1020c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf(msg_get(MSG_CHAR_INFO), ch, ch);
1021c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1022c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1023c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* these are stub functions to keep keyboard.c happy. */
1024c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1025c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_from_top(struct vc_data *vc)
1026c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1027c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_screen_from_to(vc, 0, spk_y);
1028c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1029c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1030c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_to_bottom(struct vc_data *vc)
1031c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1032c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_screen_from_to(vc, spk_y, vc->vc_rows);
1033c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1034c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1035c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_from_left(struct vc_data *vc)
1036c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1037c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line_from_to(vc, 0, spk_x, 1);
1038c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1039c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1040c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_to_right(struct vc_data *vc)
1041c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1042c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1043c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1044c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1045c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* end of stub functions. */
1046c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1047c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void spkup_write(const char *in_buf, int count)
1048c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
104916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	static int rep_count;
1050c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	static u_char ch = '\0', old_ch = '\0';
105116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	static u_short char_type, last_type;
1052c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int in_count = count;
1053c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_keydown = 0;
1054c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (count--) {
1055c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (cursor_track == read_all_mode) {
1056c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			/* Insert Sentence Index */
1057c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if ((in_buf == sentmarks[bn][currsentence]) &&
105816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			    (currsentence <= numsentences[bn]))
1059c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_insert_next_index(currsentence++);
1060c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
106116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		ch = (u_char) *in_buf++;
1062c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		char_type = spk_chartab[ch];
106316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		if (ch == old_ch && !(char_type & B_NUM)) {
1064c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (++rep_count > 2)
1065c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				continue;
1066c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else {
106716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			if ((last_type & CH_RPT) && rep_count > 2) {
1068c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_printf(" ");
106916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				synth_printf(msg_get(MSG_REPEAT_DESC),
107016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs					     ++rep_count);
1071c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_printf(" ");
1072c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
1073c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			rep_count = 0;
1074c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1075c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (ch == spk_lastkey) {
1076c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			rep_count = 0;
1077c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (key_echo == 1 && ch >= MINECHOCHAR)
1078c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				speak_char(ch);
1079c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else if (char_type & B_ALPHA) {
1080c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if ((synth_flags & SF_DEC) && (last_type & PUNC))
1081c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_buffer_add(SPACE);
1082c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf("%c", ch);
1083c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else if (char_type & B_NUM) {
1084c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			rep_count = 0;
1085c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf("%c", ch);
108616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		} else if (char_type & punc_mask) {
1087c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			speak_char(ch);
108816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			char_type &= ~PUNC;	/* for dec nospell processing */
108916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		} else if (char_type & SYNTH_OK) {
109016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			/* these are usually puncts like . and , which synth
109116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 * needs for expression.
109216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 * suppress multiple to get rid of long pauses and
109316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 * clear repeat count
109416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 * so if someone has
109516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 * repeats on you don't get nothing repeated count */
1096c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (ch != old_ch)
1097c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_printf("%c", ch);
1098c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			else
1099c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				rep_count = 0;
1100c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else {
1101c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* send space and record position, if next is num overwrite space */
1102c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (old_ch != ch)
1103c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_buffer_add(SPACE);
1104c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			else
1105c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				rep_count = 0;
1106c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1107c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		old_ch = ch;
1108c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		last_type = char_type;
1109c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1110c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_lastkey = 0;
1111c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (in_count > 2 && rep_count > 2) {
111216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		if (last_type & CH_RPT) {
1113c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf(" ");
1114c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf(msg_get(MSG_REPEAT_DESC2), ++rep_count);
1115c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf(" ");
1116c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1117c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		rep_count = 0;
1118c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1119c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1120c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1121c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1122c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1123c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void read_all_doc(struct vc_data *vc);
1124c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void cursor_done(u_long data);
1125c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1126c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1127c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1128c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1129c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
1130c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (synth == NULL || up_flag || spk_killed)
1131c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1132c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_lock(flags);
1133c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == read_all_mode) {
1134c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		switch (value) {
1135c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_SHIFT):
1136c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			del_timer(&cursor_timer);
1137c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_shut_up &= 0xfe;
1138c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			do_flush();
1139c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			read_all_doc(vc);
1140c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
1141c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_CTRL):
1142c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			del_timer(&cursor_timer);
1143c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			cursor_track = prev_cursor_track;
1144c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_shut_up &= 0xfe;
1145c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			do_flush();
1146c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
1147c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1148c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
1149c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_shut_up &= 0xfe;
1150c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		do_flush();
1151c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1152c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (say_ctrl && value < NUM_CTL_LABELS)
1153c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s", msg_get(MSG_CTL_START + value));
1154c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_unlock(flags);
1155c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1156c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1157c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1158c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1159c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
1160c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_lock(flags);
1161c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (up_flag) {
1162c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_lastkey = spk_keydown = 0;
1163c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_unlock(flags);
1164c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1165c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1166c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (synth == NULL || spk_killed) {
1167c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_unlock(flags);
1168c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1169c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1170c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up &= 0xfe;
1171c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_lastkey = value;
1172c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_keydown++;
1173c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked &= 0xfe;
1174c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (key_echo == 2 && value >= MINECHOCHAR)
1175c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speak_char(value);
1176c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_unlock(flags);
1177c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1178c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1179c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsint set_key_info(const u_char *key_info, u_char *k_buffer)
1180c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1181c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i = 0, states, key_data_len;
1182c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	const u_char *cp = key_info;
1183c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char *cp1 = k_buffer;
1184c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char ch, version, num_keys;
1185c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	version = *cp++;
1186c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (version != KEY_MAP_VER)
1187c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
1188c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	num_keys = *cp;
118916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	states = (int)cp[1];
1190c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	key_data_len = (states + 1) * (num_keys + 1);
1191c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(key_buf))
1192c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -2;
1193c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	memset(k_buffer, 0, SHIFT_TBL_SIZE);
1194c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	memset(our_keys, 0, sizeof(our_keys));
1195c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	shift_table = k_buffer;
1196c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	our_keys[0] = shift_table;
1197c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cp1 += SHIFT_TBL_SIZE;
1198c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	memcpy(cp1, cp, key_data_len + 3);
119916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	/* get num_keys, states and data */
120016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	cp1 += 2;		/* now pointing at shift states */
1201c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 1; i <= states; i++) {
1202c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		ch = *cp1++;
1203c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (ch >= SHIFT_TBL_SIZE)
1204c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			return -3;
1205c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		shift_table[ch] = i;
1206c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1207c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	keymap_flags = *cp1++;
1208c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while ((ch = *cp1)) {
1209c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (ch >= MAX_KEY)
1210c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			return -4;
1211c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		our_keys[ch] = cp1;
1212c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		cp1 += states + 1;
1213c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1214c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return 0;
1215c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1216c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1217c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic struct var_t spk_vars[] = {
1218c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/* bell must be first to set high limit */
121916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
122016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
122116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
122216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
122316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
122416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
122516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
122616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
122716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{SAY_CONTROL, TOGGLE_0},
122816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{SAY_WORD_CTL, TOGGLE_0},
122916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{NO_INTERRUPT, TOGGLE_0},
123016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1231c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	V_LAST_VAR
1232c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
1233c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1234c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void toggle_cursoring(struct vc_data *vc)
1235c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1236c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == read_all_mode)
1237c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		cursor_track = prev_cursor_track;
1238c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (++cursor_track >= CT_Max)
1239c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		cursor_track = 0;
1240c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%s\n", msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1241c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1242c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1243c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsvoid reset_default_chars(void)
1244c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1245c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i;
1246c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1247c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/* First, free any non-default */
1248c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 256; i++) {
1249c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if ((characters[i] != NULL)
1250c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		    && (characters[i] != default_chars[i]))
1251c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			kfree(characters[i]);
1252c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1253c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1254c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	memcpy(characters, default_chars, sizeof(default_chars));
1255c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1256c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1257c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsvoid reset_default_chartab(void)
1258c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1259c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1260c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1261c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
126216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic const struct st_bits_data *pb_edit;
1263c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1264c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1265c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1266c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	short mask = pb_edit->mask, ch_type = spk_chartab[ch];
126716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1268c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
1269c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (ch == SPACE) {
1270c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_EDIT_DONE));
1271c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		special_handler = NULL;
1272c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 1;
1273c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
127416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	if (mask < PUNC && !(ch_type & PUNC))
1275c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
1276c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_chartab[ch] ^= mask;
1277c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speak_char(ch);
1278c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf(" %s\n",
127916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		     (spk_chartab[ch] & mask) ? msg_get(MSG_ON) :
128016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		     msg_get(MSG_OFF));
1281c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return 1;
1282c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1283c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1284c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* Allocation concurrency is protected by the console semaphore */
1285628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannonint speakup_allocate(struct vc_data *vc)
1286c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1287c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num;
1288c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1289c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	vc_num = vc->vc_num;
1290c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (speakup_console[vc_num] == NULL) {
1291c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
129216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs						  GFP_ATOMIC);
1293c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (speakup_console[vc_num] == NULL)
1294628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon			return -ENOMEM;
1295c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_date(vc);
1296c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else if (!spk_parked)
1297c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_date(vc);
1298628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
1299628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	return 0;
1300c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1301c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1302c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsvoid speakup_deallocate(struct vc_data *vc)
1303c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1304c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num;
1305c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1306c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	vc_num = vc->vc_num;
130739dd3e5d7b09b5a5010ed1aef512f2d58b65cb99Ilia Mirkin	kfree(speakup_console[vc_num]);
130839dd3e5d7b09b5a5010ed1aef512f2d58b65cb99Ilia Mirkin	speakup_console[vc_num] = NULL;
1309c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1310c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1311c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_char is_cursor;
1312c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1313c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int cursor_con;
1314c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1315c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void reset_highlight_buffers(struct vc_data *);
1316c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1317c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int read_all_key;
1318c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1319c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void start_read_all_timer(struct vc_data *vc, int command);
1320c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1321c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsenum {
1322c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_NOTHING,
1323c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_NEXT_SENT,
1324c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_PREV_LINE,
1325c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_NEXT_LINE,
1326c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_PREV_SENT,
1327c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_DOWN_ARROW,
1328c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_TIMER,
1329c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_FIND_NEXT_SENT,
1330c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_FIND_PREV_SENT,
1331c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
1332c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
133316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void kbd_fakekey2(struct vc_data *vc, int command)
1334c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1335c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	del_timer(&cursor_timer);
1336c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_fake_down_arrow();
1337c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	start_read_all_timer(vc, command);
1338c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1339c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
134016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void read_all_doc(struct vc_data *vc)
1341c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1342c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1343c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1344c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!synth_supports_indexing())
1345c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1346c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track != read_all_mode)
1347c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		prev_cursor_track = cursor_track;
1348c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cursor_track = read_all_mode;
1349c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	reset_index_count(0);
1350c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (get_sentence_buf(vc, 0) == -1)
1351c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		kbd_fakekey2(vc, RA_DOWN_ARROW);
1352c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	else {
1353c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_sentence_num(0, 0);
1354c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_insert_next_index(0);
1355c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		start_read_all_timer(vc, RA_TIMER);
1356c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1357c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1358c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
135916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void stop_read_all(struct vc_data *vc)
1360c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1361c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	del_timer(&cursor_timer);
1362c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cursor_track = prev_cursor_track;
1363c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up &= 0xfe;
1364c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	do_flush();
1365c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1366c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
136716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void start_read_all_timer(struct vc_data *vc, int command)
1368c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1369c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct var_t *cursor_timeout;
1370c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1371c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cursor_con = vc->vc_num;
1372c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	read_all_key = command;
1373c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cursor_timeout = get_var(CURSOR_TIME);
137416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	mod_timer(&cursor_timer,
137516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1376c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1377c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
137816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void handle_cursor_read_all(struct vc_data *vc, int command)
1379c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1380c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int indcount, sentcount, rv, sn;
1381c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1382c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	switch (command) {
1383c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_NEXT_SENT:
1384c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* Get Current Sentence */
1385c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		get_index_count(&indcount, &sentcount);
1386c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/*printk("%d %d  ", indcount, sentcount); */
138716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		reset_index_count(sentcount + 1);
1388c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (indcount == 1) {
138916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			if (!say_sentence_num(sentcount + 1, 0)) {
1390c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1391c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				return;
1392c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
1393c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_insert_next_index(0);
1394c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else {
1395c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			sn = 0;
139616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			if (!say_sentence_num(sentcount + 1, 1)) {
1397c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				sn = 1;
1398c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				reset_index_count(sn);
1399c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			} else
1400c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_insert_next_index(0);
1401c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (!say_sentence_num(sn, 0)) {
1402c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1403c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				return;
1404c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
1405c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_insert_next_index(0);
1406c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1407c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		start_read_all_timer(vc, RA_TIMER);
1408c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1409c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_PREV_SENT:
1410c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1411c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_NEXT_LINE:
1412c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		read_all_doc(vc);
1413c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1414c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_PREV_LINE:
1415c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1416c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_DOWN_ARROW:
1417c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (get_sentence_buf(vc, 0) == -1) {
1418c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			kbd_fakekey2(vc, RA_DOWN_ARROW);
1419c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else {
1420c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			say_sentence_num(0, 0);
1421c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_insert_next_index(0);
1422c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			start_read_all_timer(vc, RA_TIMER);
1423c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1424c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1425c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_FIND_NEXT_SENT:
1426c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		rv = get_sentence_buf(vc, 0);
1427c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (rv == -1)
1428c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			read_all_doc(vc);
1429c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (rv == 0)
1430c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1431c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else {
1432c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			say_sentence_num(1, 0);
1433c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_insert_next_index(0);
1434c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			start_read_all_timer(vc, RA_TIMER);
1435c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1436c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1437c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_FIND_PREV_SENT:
1438c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1439c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_TIMER:
1440c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		get_index_count(&indcount, &sentcount);
1441c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (indcount < 2)
1442c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			kbd_fakekey2(vc, RA_DOWN_ARROW);
1443c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else
1444c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			start_read_all_timer(vc, RA_TIMER);
1445c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1446c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1447c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1448c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1449c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1450c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1451c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
1452c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_lock(flags);
1453c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == read_all_mode) {
1454c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_parked &= 0xfe;
1455c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (synth == NULL || up_flag || spk_shut_up) {
1456c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_unlock(flags);
1457c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			return NOTIFY_STOP;
1458c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1459c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		del_timer(&cursor_timer);
1460c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_shut_up &= 0xfe;
1461c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		do_flush();
146216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		start_read_all_timer(vc, value + 1);
1463c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_unlock(flags);
1464c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return NOTIFY_STOP;
1465c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1466c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_unlock(flags);
1467c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return NOTIFY_OK;
1468c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1469c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1470c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1471c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1472c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
1473c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct var_t *cursor_timeout;
1474c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1475c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_lock(flags);
1476c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked &= 0xfe;
1477c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1478c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_unlock(flags);
1479c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1480c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1481c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up &= 0xfe;
1482c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (no_intr)
1483c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		do_flush();
1484c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* the key press flushes if !no_inter but we want to flush on cursor
1485c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs * moves regardless of no_inter state */
1486c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	is_cursor = value + 1;
1487c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	old_cursor_pos = vc->vc_pos;
1488c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	old_cursor_x = vc->vc_x;
1489c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	old_cursor_y = vc->vc_y;
1490c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1491c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cursor_con = vc->vc_num;
1492c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == CT_Highlight)
1493c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		reset_highlight_buffers(vc);
1494c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cursor_timeout = get_var(CURSOR_TIME);
149516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	mod_timer(&cursor_timer,
149616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1497c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_unlock(flags);
1498c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1499c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
150016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void update_color_buffer(struct vc_data *vc, const char *ic, int len)
1501c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1502c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i, bi, hi;
1503c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num = vc->vc_num;
1504c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
150516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	bi = ((vc->vc_attr & 0x70) >> 4);
1506c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	hi = speakup_console[vc_num]->ht.highsize[bi];
1507c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1508c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	i = 0;
1509c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1510c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1511c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1512c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1513c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1514c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1515c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if ((ic[i] > 32) && (ic[i] < 127)) {
1516c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1517c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			hi++;
1518c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else if ((ic[i] == 32) && (hi != 0)) {
151916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
152016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			    32) {
1521c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				speakup_console[vc_num]->ht.highbuf[bi][hi] =
152216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				    ic[i];
1523c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				hi++;
1524c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
1525c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1526c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		i++;
1527c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1528c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_console[vc_num]->ht.highsize[bi] = hi;
1529c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1530c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
153116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void reset_highlight_buffers(struct vc_data *vc)
1532c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1533c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i;
1534c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num = vc->vc_num;
153516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	for (i = 0; i < 8; i++)
1536c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_console[vc_num]->ht.highsize[i] = 0;
1537c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1538c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
153916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic int count_highlight_color(struct vc_data *vc)
1540c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1541c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i, bg;
1542c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int cc;
1543c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num = vc->vc_num;
1544c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u16 ch;
1545c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u16 *start = (u16 *) vc->vc_origin;
1546c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1547c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 8; i++)
1548c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_console[vc_num]->ht.bgcount[i] = 0;
1549c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1550c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < vc->vc_rows; i++) {
155116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		u16 *end = start + vc->vc_cols * 2;
1552c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		u16 *ptr;
1553c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		for (ptr = start; ptr < end; ptr++) {
1554c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			ch = get_attributes(ptr);
1555c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			bg = (ch & 0x70) >> 4;
1556c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			speakup_console[vc_num]->ht.bgcount[bg]++;
1557c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1558c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		start += vc->vc_size_row;
1559c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1560c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1561c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cc = 0;
1562c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 8; i++)
1563c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1564c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			cc++;
1565c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return cc;
1566c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1567c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
156816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic int get_highlight_color(struct vc_data *vc)
1569c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1570c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i, j;
1571c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned int cptr[8], tmp;
1572c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num = vc->vc_num;
1573c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1574c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 8; i++)
1575c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		cptr[i] = i;
1576c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1577c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 7; i++)
1578c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		for (j = i + 1; j < 8; j++)
1579c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
158016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			    speakup_console[vc_num]->ht.bgcount[cptr[j]]) {
1581c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				tmp = cptr[i];
1582c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				cptr[i] = cptr[j];
1583c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				cptr[j] = tmp;
1584c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
1585c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1586c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 8; i++)
1587c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1588c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1589c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				return cptr[i];
1590c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return -1;
1591c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1592c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
159316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic int speak_highlight(struct vc_data *vc)
1594c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1595c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int hc, d;
1596c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num = vc->vc_num;
1597c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (count_highlight_color(vc) == 1)
1598c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 0;
1599c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	hc = get_highlight_color(vc);
1600c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (hc != -1) {
160116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		d = vc->vc_y - speakup_console[vc_num]->ht.cy;
1602c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if ((d == 1) || (d == -1))
1603c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1604c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				return 0;
1605c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_parked |= 0x01;
1606c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		do_flush();
1607c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
160816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			    speakup_console[vc_num]->ht.highsize[hc]);
1609c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1610c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1611c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1612c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 1;
1613c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1614c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return 0;
1615c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1616c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
161716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void cursor_done(u_long data)
1618c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1619c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct vc_data *vc = vc_cons[cursor_con].d;
1620c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
1621c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	del_timer(&cursor_timer);
1622c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_lock(flags);
1623c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_con != fg_console) {
1624c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		is_cursor = 0;
1625c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto out;
1626c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1627c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_date(vc);
1628c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_enabled) {
1629c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
163016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		    vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1631c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_keydown = is_cursor = 0;
1632c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto out;
1633c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1634c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1635c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == read_all_mode) {
1636c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		handle_cursor_read_all(vc, read_all_key);
1637c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto out;
1638c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1639c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == CT_Highlight) {
1640c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (speak_highlight(vc)) {
1641c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_keydown = is_cursor = 0;
1642c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto out;
1643c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1644c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1645c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == CT_Window)
1646c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_win_say(vc);
1647c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	else if (is_cursor == 1 || is_cursor == 4)
1648c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_line_from_to(vc, 0, vc->vc_cols, 0);
1649c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	else
1650c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_char(vc);
1651c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_keydown = is_cursor = 0;
1652c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsout:
1653c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_unlock(flags);
1654c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1655c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1656c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* called by: vt_notifier_call() */
1657c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_bs(struct vc_data *vc)
1658c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1659c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
1660c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!speakup_console[vc->vc_num])
1661c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1662c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!spk_trylock(flags))
1663c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* Speakup output, discard */
1664c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1665c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!spk_parked)
1666c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_date(vc);
1667c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_shut_up || synth == NULL) {
1668c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_unlock(flags);
1669c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1670c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1671c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (vc->vc_num == fg_console && spk_keydown) {
1672c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_keydown = 0;
1673c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (!is_cursor)
1674c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			say_char(vc);
1675c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1676c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_unlock(flags);
1677c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1678c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1679c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* called by: vt_notifier_call() */
1680c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_con_write(struct vc_data *vc, const char *str, int len)
1681c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1682c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
1683c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1684c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1685c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!spk_trylock(flags))
1686c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* Speakup output, discard */
1687c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1688c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (bell_pos && spk_keydown && (vc->vc_x == bell_pos - 1))
1689c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		bleep(3);
1690c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if ((is_cursor) || (cursor_track == read_all_mode)) {
1691c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (cursor_track == CT_Highlight)
1692c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			update_color_buffer(vc, str, len);
1693c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_unlock(flags);
1694c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1695c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1696c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_enabled) {
1697c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
169816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		    vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1699c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_unlock(flags);
1700c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			return;
1701c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1702c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1703c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1704c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spkup_write(str, len);
1705c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_unlock(flags);
1706c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1707c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
170816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsvoid speakup_con_update(struct vc_data *vc)
1709c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1710c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
1711c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (speakup_console[vc->vc_num] == NULL || spk_parked)
1712c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1713c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!spk_trylock(flags))
1714c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* Speakup output, discard */
1715c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1716c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_date(vc);
1717c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_unlock(flags);
1718c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1719c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1720c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1721c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1722c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
1723c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int on_off = 2;
1724c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char *label;
1725c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (synth == NULL || up_flag || spk_killed)
1726c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1727c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_lock(flags);
1728c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up &= 0xfe;
1729c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (no_intr)
1730c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		do_flush();
1731c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	switch (value) {
1732c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KVAL(K_CAPS):
1733c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		label = msg_get(MSG_KEYNAME_CAPSLOCK);
1734079c9534a96da9a85a2a2f9715851050fbfbf749Alan Cox		on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1735c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1736c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KVAL(K_NUM):
1737c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		label = msg_get(MSG_KEYNAME_NUMLOCK);
1738079c9534a96da9a85a2a2f9715851050fbfbf749Alan Cox		on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1739c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1740c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KVAL(K_HOLD):
1741c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		label = msg_get(MSG_KEYNAME_SCROLLLOCK);
1742079c9534a96da9a85a2a2f9715851050fbfbf749Alan Cox		on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1743c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (speakup_console[vc->vc_num])
1744c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			speakup_console[vc->vc_num]->tty_stopped = on_off;
1745c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1746c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	default:
1747c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_parked &= 0xfe;
1748c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_unlock(flags);
1749c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1750c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1751c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (on_off < 2)
1752c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s %s\n",
1753c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			     label, msg_get(MSG_STATUS_START + on_off));
1754c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_unlock(flags);
1755c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1756c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
175716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic int inc_dec_var(u_char value)
1758c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1759c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct st_var_header *p_header;
1760c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct var_t *var_data;
1761c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char num_buf[32];
1762c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char *cp = num_buf;
1763c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char *pn;
1764c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int var_id = (int)value - VAR_START;
176516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	int how = (var_id & 1) ? E_INC : E_DEC;
176616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	var_id = var_id / 2 + FIRST_SET_VAR;
1767c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	p_header = get_var_header(var_id);
1768c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (p_header == NULL)
1769c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
1770c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (p_header->var_type != VAR_NUM)
1771c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
1772c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	var_data = p_header->data;
1773c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (set_num_var(1, p_header, how) != 0)
1774c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
1775c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!spk_close_press) {
1776c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		for (pn = p_header->name; *pn; pn++) {
1777c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (*pn == '_')
1778c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				*cp = SPACE;
1779c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			else
1780c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				*cp++ = *pn;
1781c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1782c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1783c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
178416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		 var_data->u.n.value);
1785c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%s", num_buf);
1786c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return 0;
1787c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1788c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
178916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void speakup_win_set(struct vc_data *vc)
1790c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1791c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char info[40];
1792c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_start > 1) {
1793c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_WINDOW_ALREADY_SET));
1794c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1795c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1796c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_x < win_left || spk_y < win_top) {
1797c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_END_BEFORE_START));
1798c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1799c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1800c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_start && spk_x == win_left && spk_y == win_top) {
1801c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		win_left = 0;
180216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		win_right = vc->vc_cols - 1;
1803c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		win_bottom = spk_y;
1804c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		snprintf(info, sizeof(info), msg_get(MSG_WINDOW_LINE),
180516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 (int)win_top + 1);
1806c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
1807c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (!win_start) {
1808c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			win_top = spk_y;
1809c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			win_left = spk_x;
1810c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else {
1811c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			win_bottom = spk_y;
1812c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			win_right = spk_x;
1813c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1814c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		snprintf(info, sizeof(info), msg_get(MSG_WINDOW_BOUNDARY),
181516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 (win_start) ? msg_get(MSG_END) : msg_get(MSG_START),
181616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 (int)spk_y + 1, (int)spk_x + 1);
1817c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1818c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%s\n", info);
1819c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	win_start++;
1820c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1821c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
182216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void speakup_win_clear(struct vc_data *vc)
1823c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1824c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	win_top = win_bottom = 0;
1825c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	win_left = win_right = 0;
1826c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	win_start = 0;
1827c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%s\n", msg_get(MSG_WINDOW_CLEARED));
1828c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1829c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
183016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void speakup_win_enable(struct vc_data *vc)
1831c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1832c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_start < 2) {
1833c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
1834c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1835c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1836c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	win_enabled ^= 1;
1837c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_enabled)
1838c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCED));
1839c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	else
1840c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCE_DISABLED));
1841c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1842c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
184316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void speakup_bits(struct vc_data *vc)
1844c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1845c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1846c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (special_handler != NULL || val < 1 || val > 6) {
1847c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_ERROR));
1848c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1849c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1850c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	pb_edit = &punc_info[val];
1851c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf(msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1852c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	special_handler = edit_bits;
1853c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1854c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1855c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1856c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1857c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	static u_char *goto_buf = "\0\0\0\0\0\0";
185816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	static int num;
1859c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int maxlen, go_pos;
1860c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char *cp;
1861c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1862c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto do_goto;
1863c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (type == KT_LATIN && ch == '\n')
1864c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto do_goto;
1865c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (type != 0)
1866c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto oops;
1867c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (ch == 8) {
1868c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (num == 0)
1869c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			return -1;
1870c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		ch = goto_buf[--num];
1871c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto_buf[num] = '\0';
1872c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spkup_write(&ch, 1);
1873c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 1;
1874c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1875c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (ch < '+' || ch > 'y')
1876c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto oops;
1877c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	goto_buf[num++] = ch;
1878c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	goto_buf[num] = '\0';
1879c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spkup_write(&ch, 1);
1880c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	maxlen = (*goto_buf >= '0') ? 3 : 4;
1881c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if ((ch == '+' || ch == '-') && num == 1)
1882c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 1;
1883c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (ch >= '0' && ch <= '9' && num < maxlen)
1884c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 1;
188516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	if (num < maxlen - 1 || num > maxlen)
1886c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto oops;
1887c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (ch < 'x' || ch > 'y') {
1888c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsoops:
1889c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (!spk_killed)
1890c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf(" %s\n", msg_get(MSG_GOTO_CANCELED));
1891c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto_buf[num = 0] = '\0';
1892c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		special_handler = NULL;
1893c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 1;
1894c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1895c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cp = speakup_s2i(goto_buf, &go_pos);
189616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	goto_pos = (u_long) go_pos;
1897c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (*cp == 'x') {
1898c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (*goto_buf < '0')
1899c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto_pos += spk_x;
1900c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else
1901c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto_pos--;
1902c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (goto_pos < 0)
1903c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto_pos = 0;
1904c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (goto_pos >= vc->vc_cols)
190516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			goto_pos = vc->vc_cols - 1;
1906c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto_x = 1;
1907c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
1908c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (*goto_buf < '0')
1909c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto_pos += spk_y;
1910c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else
1911c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto_pos--;
1912c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (goto_pos < 0)
1913c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto_pos = 0;
1914c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (goto_pos >= vc->vc_rows)
191516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			goto_pos = vc->vc_rows - 1;
1916c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto_x = 0;
1917c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
191816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	goto_buf[num = 0] = '\0';
1919c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsdo_goto:
1920c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	special_handler = NULL;
1921c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
1922c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (goto_x) {
1923c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_pos -= spk_x * 2;
1924c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_x = goto_pos;
1925c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_pos += goto_pos * 2;
1926c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_word(vc);
1927c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
1928c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_y = goto_pos;
1929c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1930c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_line(vc);
1931c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1932c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return 1;
1933c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1934c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
193516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void speakup_goto(struct vc_data *vc)
1936c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1937c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (special_handler != NULL) {
1938c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", msg_get(MSG_ERROR));
1939c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1940c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1941c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%s\n", msg_get(MSG_GOTO));
1942c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	special_handler = handle_goto;
1943c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return;
1944c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1945c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1946c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_help(struct vc_data *vc)
1947c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1948c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1949c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1950c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
195116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void do_nothing(struct vc_data *vc)
1952c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
195316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	return;			/* flush done in do_spkup */
1954c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
195516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs
1956c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_char key_speakup, spk_key_locked;
1957c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
195816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void speakup_lock(struct vc_data *vc)
1959c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1960c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!spk_key_locked)
1961c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_key_locked = key_speakup = 16;
1962c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	else
1963c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_key_locked = key_speakup = 0;
1964c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1965c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
196616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbstypedef void (*spkup_hand) (struct vc_data *);
1967c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsspkup_hand spkup_handler[] = {
1968c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/* must be ordered same as defines in speakup.h */
1969c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	do_nothing, speakup_goto, speech_kill, speakup_shut_up,
1970c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_cut, speakup_paste, say_first_char, say_last_char,
1971c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_char, say_prev_char, say_next_char,
1972c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_word, say_prev_word, say_next_word,
1973c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line, say_prev_line, say_next_line,
1974c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	top_edge, bottom_edge, left_edge, right_edge,
1975c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spell_word, spell_word, say_screen,
1976c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_position, say_attributes,
197716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	speakup_off, speakup_parked, say_line,	/* this is for indent */
1978c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_from_top, say_to_bottom,
1979c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_from_left, say_to_right,
1980c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
1981c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_bits, speakup_bits, speakup_bits,
1982c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
1983c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
1984c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
1985c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1986c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void do_spkup(struct vc_data *vc, u_char value)
1987c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1988c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_killed && value != SPEECH_KILL)
1989c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1990c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_keydown = 0;
1991c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_lastkey = 0;
1992c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up &= 0xfe;
1993c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	this_speakup_key = value;
1994c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
1995c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		do_flush();
199616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		(*spkup_handler[value]) (vc);
1997c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
1998c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (inc_dec_var(value) < 0)
1999c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			bleep(9);
2000c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2001c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
2002c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2003c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic const char *pad_chars = "0123456789+-*/\015,.?()";
2004c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2005c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsint
2006c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsspeakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
200716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    int up_flag)
2008c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
2009c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
2010c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int kh;
2011c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char *key_info;
2012c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2013c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char shift_info, offset;
2014c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int ret = 0;
2015c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (synth == NULL)
2016c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 0;
2017c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2018c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_lock(flags);
20195b19208a5e236b26357162d6a28ff9e8d4296725Greg Kroah-Hartman	tty = vc->port.tty;
2020c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (type >= 0xf0)
2021c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		type -= 0xf0;
202216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	if (type == KT_PAD
2023079c9534a96da9a85a2a2f9715851050fbfbf749Alan Cox		&& (vt_get_leds(fg_console, VC_NUMLOCK))) {
2024c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (up_flag) {
2025c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_keydown = 0;
2026c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto out;
2027c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
2028c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		value = spk_lastkey = pad_chars[value];
2029c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_keydown++;
2030c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_parked &= 0xfe;
2031c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto no_map;
2032c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2033c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (keycode >= MAX_KEY)
2034c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto no_map;
2035c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	key_info = our_keys[keycode];
2036c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (key_info == 0)
2037c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto no_map;
2038c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/* Check valid read all mode keys */
2039c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if ((cursor_track == read_all_mode) && (!up_flag)) {
2040c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		switch (value) {
2041c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_DOWN):
2042c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_UP):
2043c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_LEFT):
2044c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_RIGHT):
2045c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_PGUP):
2046c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_PGDN):
2047c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
2048c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		default:
2049c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			stop_read_all(vc);
2050c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
2051c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
2052c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
205316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	shift_info = (shift_state & 0x0f) + key_speakup;
2054c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	offset = shift_table[shift_info];
2055c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (offset) {
2056c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		new_key = key_info[offset];
2057c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (new_key) {
2058c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			ret = 1;
2059c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (new_key == SPK_KEY) {
2060c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				if (!spk_key_locked)
2061c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs					key_speakup = (up_flag) ? 0 : 16;
2062c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				if (up_flag || spk_killed)
2063c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs					goto out;
2064c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				spk_shut_up &= 0xfe;
2065c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				do_flush();
2066c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				goto out;
2067c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
2068c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (up_flag)
2069c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				goto out;
2070c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (last_keycode == keycode &&
207116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			    last_spk_jiffy + MAX_DELAY > jiffies) {
2072c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				spk_close_press = 1;
207316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				offset = shift_table[shift_info + 32];
207416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				/* double press? */
2075c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				if (offset && key_info[offset])
2076c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs					new_key = key_info[offset];
2077c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
2078c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			last_keycode = keycode;
2079c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			last_spk_jiffy = jiffies;
2080c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			type = KT_SPKUP;
2081c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			value = new_key;
2082c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
2083c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2084c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsno_map:
2085c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (type == KT_SPKUP && special_handler == NULL) {
2086c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		do_spkup(vc, new_key);
2087c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_close_press = 0;
2088c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		ret = 1;
2089c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto out;
2090c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2091c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (up_flag || spk_killed || type == KT_SHIFT)
2092c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto out;
2093c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up &= 0xfe;
2094c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	kh = (value == KVAL(K_DOWN))
209516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    || (value == KVAL(K_UP))
209616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    || (value == KVAL(K_LEFT))
209716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    || (value == KVAL(K_RIGHT));
2098c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if ((cursor_track != read_all_mode) || !kh)
2099c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (!no_intr)
2100c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			do_flush();
2101c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (special_handler) {
2102c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (type == KT_SPEC && value == 1) {
2103c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			value = '\n';
2104c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			type = KT_LATIN;
2105c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else if (type == KT_LETTER)
2106c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			type = KT_LATIN;
2107c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else if (value == 0x7f)
210816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			value = 8;	/* make del = backspace */
210916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		ret = (*special_handler) (vc, type, value, keycode);
2110c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_close_press = 0;
2111c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (ret < 0)
2112c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			bleep(9);
2113c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto out;
2114c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2115c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	last_keycode = 0;
2116c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsout:
2117c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_unlock(flags);
2118c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return ret;
2119c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
2120c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2121c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int keyboard_notifier_call(struct notifier_block *nb,
212216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				  unsigned long code, void *_param)
2123c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
2124c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct keyboard_notifier_param *param = _param;
2125c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct vc_data *vc = param->vc;
2126c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int up = !param->down;
2127c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int ret = NOTIFY_OK;
212816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	static int keycode;	/* to hold the current keycode */
2129c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2130c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (vc->vc_mode == KD_GRAPHICS)
2131c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return ret;
2132c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2133c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/*
2134c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 * First, determine whether we are handling a fake keypress on
2135c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 * the current processor.  If we are, then return NOTIFY_OK,
2136c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 * to pass the keystroke up the chain.  This prevents us from
2137c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 * trying to take the Speakup lock while it is held by the
2138c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 * processor on which the simulated keystroke was generated.
2139c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 * Also, the simulated keystrokes should be ignored by Speakup.
2140c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 */
2141c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2142c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (speakup_fake_key_pressed())
2143c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return ret;
2144c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2145c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	switch (code) {
2146c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KBD_KEYCODE:
2147c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* speakup requires keycode and keysym currently */
2148c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		keycode = param->value;
2149c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2150c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KBD_UNBOUND_KEYCODE:
2151c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* not used yet */
2152c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2153c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KBD_UNICODE:
2154c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* not used yet */
2155c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2156c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KBD_KEYSYM:
2157c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (speakup_key(vc, param->shift, keycode, param->value, up))
2158c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			ret = NOTIFY_STOP;
215916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		else if (KTYP(param->value) == KT_CUR)
216016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			ret = pre_handle_cursor(vc, KVAL(param->value), up);
2161c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
216216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	case KBD_POST_KEYSYM:{
216316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			unsigned char type = KTYP(param->value) - 0xf0;
216416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			unsigned char val = KVAL(param->value);
216516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			switch (type) {
216616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			case KT_SHIFT:
216716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				do_handle_shift(vc, val, up);
216816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				break;
216916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			case KT_LATIN:
217016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			case KT_LETTER:
217116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				do_handle_latin(vc, val, up);
217216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				break;
217316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			case KT_CUR:
217416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				do_handle_cursor(vc, val, up);
217516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				break;
217616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			case KT_SPEC:
217716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				do_handle_spec(vc, val, up);
217816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				break;
217916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			}
2180c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
2181c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
2182c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2183c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return ret;
2184c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
2185c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2186c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int vt_notifier_call(struct notifier_block *nb,
218716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			    unsigned long code, void *_param)
2188c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
2189c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct vt_notifier_param *param = _param;
2190c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct vc_data *vc = param->vc;
2191c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	switch (code) {
2192c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case VT_ALLOCATE:
2193c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (vc->vc_mode == KD_TEXT)
2194c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			speakup_allocate(vc);
2195c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2196c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case VT_DEALLOCATE:
2197c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_deallocate(vc);
2198c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2199c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case VT_WRITE:
2200c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (param->c == '\b')
2201c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			speakup_bs(vc);
220216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		else if (param->c < 0x100) {
220316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			char d = param->c;
220416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			speakup_con_write(vc, &d, 1);
220516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		}
2206c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2207c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case VT_UPDATE:
2208c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_con_update(vc);
2209c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2210c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2211c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return NOTIFY_OK;
2212c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
2213c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2214c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* called by: module_exit() */
2215c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void __exit speakup_exit(void)
2216c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
2217c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i;
2218c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2219c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unregister_keyboard_notifier(&keyboard_notifier_block);
2220c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unregister_vt_notifier(&vt_notifier_block);
2221c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_unregister_devsynth();
2222c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	del_timer(&cursor_timer);
2223c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	kthread_stop(speakup_task);
2224c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_task = NULL;
2225c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	mutex_lock(&spk_mutex);
2226c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_release();
2227c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	mutex_unlock(&spk_mutex);
2228c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2229628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	speakup_kobj_exit();
2230628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2231628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	for (i = 0; i < MAX_NR_CONSOLES; i++)
2232628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		kfree(speakup_console[i]);
2233628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2234628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	speakup_remove_virtual_keyboard();
2235628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2236c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < MAXVARS; i++)
2237c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_unregister_var(i);
2238c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2239c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 256; i++) {
2240c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (characters[i] != default_chars[i])
2241c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			kfree(characters[i]);
2242c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2243628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2244628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	free_user_msgs();
2245c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
2246c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2247c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* call by: module_init() */
2248c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int __init speakup_init(void)
2249c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
2250c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i;
2251628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	long err = 0;
2252c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct st_spk_t *first_console;
2253c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct vc_data *vc = vc_cons[fg_console].d;
2254c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct var_t *var;
2255c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2256628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	/* These first few initializations cannot fail. */
225716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	initialize_msgs();	/* Initialize arrays for i18n. */
2258c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	reset_default_chars();
2259c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	reset_default_chartab();
2260c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	strlwr(synth_name);
2261c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_vars[0].u.n.high = vc->vc_cols;
226216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	for (var = spk_vars; var->var_id != MAXVARS; var++)
2263c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_register_var(var);
226416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	for (var = synth_time_vars;
226516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	     (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2266c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_register_var(var);
2267c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 1; punc_info[i].mask != 0; i++)
2268c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		set_mask_bits(0, i, 2);
2269c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2270c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	set_key_info(key_defaults, key_buf);
2271c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2272628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	/* From here on out, initializations can fail. */
2273628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	err = speakup_add_virtual_keyboard();
2274628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	if (err)
2275628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		goto error_virtkeyboard;
2276628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2277628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2278628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	if (!first_console) {
2279628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		err = -ENOMEM;
2280628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		goto error_alloc;
2281628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	}
2282628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2283628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	speakup_console[vc->vc_num] = first_console;
2284628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	speakup_date(vc);
2285628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2286c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < MAX_NR_CONSOLES; i++)
2287628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		if (vc_cons[i].d) {
2288628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon			err = speakup_allocate(vc_cons[i].d);
2289628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon			if (err)
2290628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon				goto error_kobjects;
2291628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		}
2292628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
22934afaee1561e207683dbb886b30a842ffcc22e366Christopher Brannon	if (quiet_boot)
22944afaee1561e207683dbb886b30a842ffcc22e366Christopher Brannon		spk_shut_up |= 0x01;
22954afaee1561e207683dbb886b30a842ffcc22e366Christopher Brannon
2296628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	err = speakup_kobj_init();
2297628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	if (err)
2298628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		goto error_kobjects;
2299c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2300c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_init(synth_name);
2301c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_register_devsynth();
2302628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	/*
2303628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	 * register_devsynth might fail, but this error is not fatal.
2304628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	 * /dev/synth is an extra feature; the rest of Speakup
2305628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	 * will work fine without it.
2306628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	 */
2307c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2308628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	err = register_keyboard_notifier(&keyboard_notifier_block);
2309628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	if (err)
2310628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		goto error_kbdnotifier;
2311628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	err = register_vt_notifier(&vt_notifier_block);
2312628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	if (err)
2313628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		goto error_vtnotifier;
2314c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2315c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2316628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
23177959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs	if (IS_ERR(speakup_task)) {
2318628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		err = PTR_ERR(speakup_task);
2319628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		goto error_task;
23207959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs	}
2321628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2322628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	set_user_nice(speakup_task, 10);
23237959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs	wake_up_process(speakup_task);
2324628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2325628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2326628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	pr_info("synth name on entry is: %s\n", synth_name);
23277959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs	goto out;
23287959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs
2329628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannonerror_task:
2330628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	unregister_vt_notifier(&vt_notifier_block);
2331628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2332628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannonerror_vtnotifier:
2333628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	unregister_keyboard_notifier(&keyboard_notifier_block);
2334628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	del_timer(&cursor_timer);
2335628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2336628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannonerror_kbdnotifier:
2337628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	speakup_unregister_devsynth();
2338628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	mutex_lock(&spk_mutex);
2339628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	synth_release();
2340628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	mutex_unlock(&spk_mutex);
2341628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	speakup_kobj_exit();
2342628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2343628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannonerror_kobjects:
2344628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	for (i = 0; i < MAX_NR_CONSOLES; i++)
2345628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		kfree(speakup_console[i]);
2346628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2347628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannonerror_alloc:
23487959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs	speakup_remove_virtual_keyboard();
2349628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2350628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannonerror_virtkeyboard:
2351628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	for (i = 0; i < MAXVARS; i++)
2352628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		speakup_unregister_var(i);
2353628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2354628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	for (i = 0; i < 256; i++) {
2355628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		if (characters[i] != default_chars[i])
2356628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon			kfree(characters[i]);
2357628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	}
2358628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2359628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	free_user_msgs();
2360628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
23617959d55679e4360205c9ebc89d40a5503c53bae2William Hubbsout:
23627959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs	return err;
2363c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
2364c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2365c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsmodule_init(speakup_init);
2366c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsmodule_exit(speakup_exit);
2367