2 review functions for the speakup screen review package.
3 originally written by: Kirk Reiser and Andy Berdan.
5 extensively modified by David Borowski.
7 Copyright (C) 1998 Kirk Reiser.
8 Copyright (C) 2003 David Borowski.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <linux/kernel.h>
26 #include <linux/version.h>
28 #include <linux/tty.h>
29 #include <linux/mm.h> /* __get_free_page() and friends */
30 #include <linux/vt_kern.h>
31 #include <linux/ctype.h>
32 #include <linux/selection.h>
33 #include <linux/unistd.h>
34 #include <linux/jiffies.h>
35 #include <linux/kthread.h>
36 #include <linux/keyboard.h> /* for KT_SHIFT */
37 #include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
38 #include <linux/input.h>
39 #include <linux/kmod.h>
41 #include <linux/bootmem.h> /* for alloc_bootmem */
43 /* speakup_*_selection */
44 #include <linux/module.h>
45 #include <linux/sched.h>
46 #include <linux/slab.h>
47 #include <linux/types.h>
48 #include <linux/consolemap.h>
50 #include <linux/spinlock.h>
51 #include <linux/notifier.h>
53 #include <linux/uaccess.h> /* copy_from|to|user() and others */
58 #define MAX_DELAY msecs_to_jiffies(500)
59 #define MINECHOCHAR SPACE
61 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
62 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
63 MODULE_DESCRIPTION("Speakup console speech");
64 MODULE_LICENSE("GPL");
65 MODULE_VERSION(SPEAKUP_VERSION);
68 module_param_named(synth, synth_name, charp, S_IRUGO);
69 module_param_named(quiet, quiet_boot, bool, S_IRUGO);
71 MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
72 MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
74 special_func special_handler;
76 short pitch_shift, synth_flags;
78 int attrib_bleep, bleeps, bleep_time = 10;
79 int no_intr, spell_delay;
80 int key_echo, say_word_ctl;
81 int say_ctrl, bell_pos;
83 int punc_level, reading_punc;
84 char str_caps_start[MAXVARLEN+1] = "\0", str_caps_stop[MAXVARLEN+1] = "\0";
85 const struct st_bits_data punc_info[] = {
87 { "some", "/$%&@", SOME },
88 { "most", "$%&#()=+*/@^<>|\\", MOST },
89 { "all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC },
90 { "delimiters", "", B_WDLM },
91 { "repeats", "()", CH_RPT },
92 { "extended numeric", "", B_EXNUM },
93 { "symbols", "", B_SYM },
96 static char mark_cut_flag;
98 u_char *our_keys[MAX_KEY], *shift_table;
100 const u_char key_defaults[] = {
101 #include "speakupmap.h"
104 /* Speakup Cursor Track Variables */
105 static int cursor_track = 1, prev_cursor_track = 1;
107 /* cursor track modes, must be ordered same as cursor_msgs */
115 #define read_all_mode CT_Max
117 static struct tty_struct *tty;
119 static void spkup_write(const char *in_buf, int count);
122 static char *phonetic[] = {
123 "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
124 "india", "juliett", "keelo", "leema", "mike", "november", "oscar", "papa",
125 "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
126 "x ray", "yankee", "zulu"
129 /* array of 256 char pointers (one for each character description)
130 * initialized to default_chars and user selectable via
131 * /proc/speakup/characters */
132 char *characters[256];
134 char *default_chars[256] = {
135 /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
136 /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
137 /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
138 /*024*/ "^x", "^y", "^z", "control", "control", "control", "control", "control",
139 /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and", "tick",
140 /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash", "dot",
142 /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
144 /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
145 /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
146 /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
147 /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
148 /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket", "caret",
150 /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
151 /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
152 /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
153 /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
154 /*127*/ "del", "control", "control", "control", "control", "control", "control", "control", "control", "control", "control",
155 /*138*/ "control", "control", "control", "control", "control", "control", "control", "control", "control", "control", "control", "control",
156 /*150*/ "control", "control", "control", "control", "control", "control", "control", "control", "control", "control",
157 /*160*/ "nbsp", "inverted bang",
158 /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
159 /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
160 /*172*/ "not", "soft hyphen", "registered", "macron",
161 /*176*/ "degrees", "plus or minus", "super two", "super three",
162 /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
163 /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
164 /*188*/ "one quarter", "one half", "three quarters", "inverted question",
165 /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT", "A RING",
166 /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX", "E OOMLAUT",
167 /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH", "N TILDE",
168 /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
169 /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE", "U CIRCUMFLEX",
170 /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
171 /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
172 /*230*/ "ae", "c cidella", "e grave", "e acute",
173 /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute", "i circumflex",
174 /*239*/ "i oomlaut", "eth", "n tilde","o grave", "o acute", "o circumflex",
175 /*245*/"o tilde", "o oomlaut", "divided by", "o stroke", "u grave", "u acute",
176 /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
179 /* array of 256 u_short (one for each character)
180 * initialized to default_chartab and user selectable via
181 * /sys/module/speakup/parameters/chartab */
182 u_short spk_chartab[256];
184 static u_short default_chartab[256] = {
185 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
186 B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
187 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
188 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
189 WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */
190 PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */
191 NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
192 NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */
193 PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */
194 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
195 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
196 A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */
197 PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */
198 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
199 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
200 ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
201 B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-135 */
202 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 136-143 */
203 B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 144-151 */
204 B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 152-159 */
205 WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, B_SYM, /* 160-167 */
206 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
207 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
208 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
209 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
210 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
211 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
212 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
213 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
214 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
215 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
216 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */
219 struct task_struct *speakup_task;
220 struct bleep unprocessed_sound;
221 static int spk_keydown;
222 static u_char spk_lastkey, spk_close_press, keymap_flags;
223 static u_char last_keycode, this_speakup_key;
224 static u_long last_spk_jiffy;
226 struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
228 DEFINE_MUTEX(spk_mutex);
230 static int keyboard_notifier_call(struct notifier_block *,
231 unsigned long code, void *param);
233 struct notifier_block keyboard_notifier_block = {
234 .notifier_call = keyboard_notifier_call,
237 static int vt_notifier_call(struct notifier_block *,
238 unsigned long code, void *param);
240 struct notifier_block vt_notifier_block = {
241 .notifier_call = vt_notifier_call,
244 static unsigned char get_attributes(u16 *pos)
246 return (u_char)(scr_readw(pos) >> 8);
249 static void speakup_date(struct vc_data *vc)
251 spk_x = spk_cx = vc->vc_x;
252 spk_y = spk_cy = vc->vc_y;
253 spk_pos = spk_cp = vc->vc_pos;
254 spk_old_attr = spk_attr;
255 spk_attr = get_attributes((u_short *) spk_pos);
258 static void bleep(u_short val)
260 static const short vals[] = {
261 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
264 int time = bleep_time;
267 freq *= (1 << (val/12));
268 unprocessed_sound.freq = freq;
269 unprocessed_sound.jiffies = msecs_to_jiffies(time);
270 unprocessed_sound.active = 1;
271 /* We can only have 1 active sound at a time. */
274 static void speakup_shut_up(struct vc_data *vc)
285 static void speech_kill(struct vc_data *vc)
287 char val = synth->is_alive(synth);
291 /* re-enables synth, if disabled */
292 if (val == 2 || spk_killed) {
294 spk_shut_up &= ~0x40;
295 synth_printf("%s\n", msg_get(MSG_IAM_ALIVE));
297 synth_printf("%s\n", msg_get(MSG_YOU_KILLED_SPEAKUP));
302 static void speakup_off(struct vc_data *vc)
304 if (spk_shut_up & 0x80) {
306 synth_printf("%s\n", msg_get(MSG_HEY_THATS_BETTER));
309 synth_printf("%s\n", msg_get(MSG_YOU_TURNED_ME_OFF));
314 static void speakup_parked(struct vc_data *vc)
316 if (spk_parked & 0x80) {
318 synth_printf("%s\n", msg_get(MSG_UNPARKED));
321 synth_printf("%s\n", msg_get(MSG_PARKED));
325 static void speakup_cut(struct vc_data *vc)
327 static const char err_buf[] = "set selection failed";
330 if (!mark_cut_flag) {
332 xs = (u_short) spk_x;
333 ys = (u_short) spk_y;
335 synth_printf("%s\n", msg_get(MSG_MARK));
338 xe = (u_short) spk_x;
339 ye = (u_short) spk_y;
341 synth_printf("%s\n", msg_get(MSG_CUT));
343 speakup_clear_selection();
344 ret = speakup_set_selection(tty);
348 break; /* no error */
350 pr_warn("%sEFAULT\n", err_buf);
353 pr_warn("%sEINVAL\n", err_buf);
356 pr_warn("%sENOMEM\n", err_buf);
361 static void speakup_paste(struct vc_data *vc)
365 synth_printf("%s\n", msg_get(MSG_MARK_CLEARED));
367 synth_printf("%s\n", msg_get(MSG_PASTE));
368 speakup_paste_selection(tty);
372 static void say_attributes(struct vc_data *vc)
374 int fg = spk_attr & 0x0f;
375 int bg = spk_attr >> 4;
377 synth_printf("%s ", msg_get(MSG_BRIGHT));
380 synth_printf("%s", msg_get(MSG_COLORS_START + fg));
382 synth_printf(" %s ", msg_get(MSG_ON_BLINKING));
385 synth_printf(" %s ", msg_get(MSG_ON));
386 synth_printf("%s\n", msg_get(MSG_COLORS_START + bg));
397 static void announce_edge(struct vc_data *vc, int msg_id)
401 if ((bleeps & 2) && (msg_id < edge_quiet))
402 synth_printf("%s\n", msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
405 static void speak_char(u_char ch)
407 char *cp = characters[ch];
408 struct var_t *direct = get_var(DIRECT);
409 if (direct && direct->u.n.value) {
410 if (IS_CHAR(ch, B_CAP)) {
412 synth_printf("%s", str_caps_start);
414 synth_printf("%c", ch);
415 if (IS_CHAR(ch, B_CAP))
416 synth_printf("%s", str_caps_stop);
420 pr_info("speak_char: cp == NULL!\n");
423 synth_buffer_add(SPACE);
424 if (IS_CHAR(ch, B_CAP)) {
426 synth_printf("%s", str_caps_start);
427 synth_printf("%s", cp);
428 synth_printf("%s", str_caps_stop);
431 synth_printf("%s", msg_get(MSG_CTRL));
434 synth_printf("%s", cp);
436 synth_buffer_add(SPACE);
439 static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
443 u16 w = scr_readw(pos);
446 if (w & vc->vc_hi_font_mask)
449 ch = inverse_translate(vc, c, 0);
450 *attribs = (w & 0xff00) >> 8;
455 static void say_char(struct vc_data *vc)
458 spk_old_attr = spk_attr;
459 ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
460 if (spk_attr != spk_old_attr) {
461 if (attrib_bleep & 1)
463 if (attrib_bleep & 2)
466 speak_char(ch & 0xff);
469 static void say_phonetic_char(struct vc_data *vc)
472 spk_old_attr = spk_attr;
473 ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
474 if (isascii(ch) && isalpha(ch)) {
476 synth_printf("%s\n", phonetic[--ch]);
478 if (IS_CHAR(ch, B_NUM))
479 synth_printf("%s ", msg_get(MSG_NUMBER));
484 static void say_prev_char(struct vc_data *vc)
488 announce_edge(vc, edge_left);
496 static void say_next_char(struct vc_data *vc)
499 if (spk_x == vc->vc_cols - 1) {
500 announce_edge(vc, edge_right);
508 /* get_word - will first check to see if the character under the
509 reading cursor is a space and if say_word_ctl is true it will
510 return the word space. If say_word_ctl is not set it will check to
511 see if there is a word starting on the next position to the right
512 and return that word if it exists. If it does not exist it will
513 move left to the beginning of any previous word on the line or the
514 beginning off the line whichever comes first.. */
516 static u_long get_word(struct vc_data *vc)
518 u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
522 spk_old_attr = spk_attr;
523 ch = (char) get_char(vc, (u_short *) tmp_pos, &temp);
525 /* decided to take out the sayword if on a space (mis-information */
526 if (say_word_ctl && ch == SPACE) {
528 synth_printf("%s\n", msg_get(MSG_SPACE));
530 } else if ((tmpx < vc->vc_cols - 2)
531 && (ch == SPACE || ch == 0 || IS_WDLM(ch))
532 && ((char) get_char(vc, (u_short *) &tmp_pos+1, &temp) > SPACE)) {
537 ch = (char) get_char(vc, (u_short *) tmp_pos - 1, &temp);
538 if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
539 && ((char) get_char(vc, (u_short *) tmp_pos, &temp) >
545 attr_ch = get_char(vc, (u_short *) tmp_pos, &spk_attr);
546 buf[cnt++] = attr_ch & 0xff;
547 while (tmpx < vc->vc_cols - 1) {
550 ch = (char) get_char(vc, (u_short *) tmp_pos, &temp);
551 if ((ch == SPACE) || ch == 0 || (IS_WDLM(buf[cnt-1]) && (ch > SPACE)))
559 static void say_word(struct vc_data *vc)
561 u_long cnt = get_word(vc);
562 u_short saved_punc_mask = punc_mask;
567 spkup_write(buf, cnt);
568 punc_mask = saved_punc_mask;
571 static void say_prev_word(struct vc_data *vc)
575 u_short edge_said = 0, last_state = 0, state = 0;
580 announce_edge(vc, edge_top);
585 edge_said = edge_quiet;
590 edge_said = edge_top;
593 if (edge_said != edge_quiet)
594 edge_said = edge_left;
598 spk_x = vc->vc_cols - 1;
602 ch = (char) get_char(vc, (u_short *) spk_pos, &temp);
603 if (ch == SPACE || ch == 0)
605 else if (IS_WDLM(ch))
609 if (state < last_state) {
616 if (spk_x == 0 && edge_said == edge_quiet)
617 edge_said = edge_left;
618 if (edge_said > 0 && edge_said < edge_quiet)
619 announce_edge(vc, edge_said);
623 static void say_next_word(struct vc_data *vc)
627 u_short edge_said = 0, last_state = 2, state = 0;
630 if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
631 announce_edge(vc, edge_bottom);
635 ch = (char) get_char(vc, (u_short *) spk_pos, &temp);
636 if (ch == SPACE || ch == 0)
638 else if (IS_WDLM(ch))
642 if (state > last_state)
644 if (spk_x >= vc->vc_cols - 1) {
645 if (spk_y == vc->vc_rows - 1) {
646 edge_said = edge_bottom;
652 edge_said = edge_right;
659 announce_edge(vc, edge_said);
663 static void spell_word(struct vc_data *vc)
665 static char *delay_str[] = { "", ",", ".", ". .", ". . ." };
666 char *cp = buf, *str_cap = str_caps_stop;
667 char *cp1, *last_cap = str_caps_stop;
671 while ((ch = (u_char) *cp)) {
673 synth_printf(" %s ", delay_str[spell_delay]);
674 if (IS_CHAR(ch, B_CAP)) {
675 str_cap = str_caps_start;
678 else /* synth has no pitch */
679 last_cap = str_caps_stop;
681 str_cap = str_caps_stop;
682 if (str_cap != last_cap) {
683 synth_printf("%s", str_cap);
686 if (this_speakup_key == SPELL_PHONETIC
687 && (isascii(ch) && isalpha(ch))) {
689 cp1 = phonetic[--ch];
691 cp1 = characters[ch];
693 synth_printf("%s", msg_get(MSG_CTRL));
697 synth_printf("%s", cp1);
700 if (str_cap != str_caps_stop)
701 synth_printf("%s", str_caps_stop);
704 static int get_line(struct vc_data *vc)
706 u_long tmp = spk_pos - (spk_x * 2);
710 spk_old_attr = spk_attr;
711 spk_attr = get_attributes((u_short *) spk_pos);
712 for (i = 0; i < vc->vc_cols; i++) {
713 buf[i] = (u_char) get_char(vc, (u_short *) tmp, &tmp2);
716 for (--i; i >= 0; i--)
722 static void say_line(struct vc_data *vc)
724 int i = get_line(vc);
726 u_short saved_punc_mask = punc_mask;
728 synth_printf("%s\n", msg_get(MSG_BLANK));
732 if (this_speakup_key == SAY_LINE_INDENT) {
733 for (cp = buf; *cp == SPACE; cp++)
735 synth_printf("%d, ", (cp - buf) + 1);
737 punc_mask = punc_masks[reading_punc];
739 punc_mask = saved_punc_mask;
742 static void say_prev_line(struct vc_data *vc)
746 announce_edge(vc, edge_top);
750 spk_pos -= vc->vc_size_row;
754 static void say_next_line(struct vc_data *vc)
757 if (spk_y == vc->vc_rows - 1) {
758 announce_edge(vc, edge_bottom);
762 spk_pos += vc->vc_size_row;
766 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
771 u_short saved_punc_mask = punc_mask;
772 spk_old_attr = spk_attr;
773 spk_attr = get_attributes((u_short *) from);
775 buf[i++] = (char) get_char(vc, (u_short *) from, &tmp);
777 if (i >= vc->vc_size_row)
780 for (--i; i >= 0; i--)
788 punc_mask = punc_info[reading_punc].mask;
791 punc_mask = saved_punc_mask;
795 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
798 u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
799 u_long end = start + (to * 2);
801 if (say_from_to(vc, start, end, read_punc) <= 0)
802 if (cursor_track != read_all_mode)
803 synth_printf("%s\n", msg_get(MSG_BLANK));
806 /* Sentence Reading Commands */
808 void synth_insert_next_index(int);
810 static int currsentence;
811 static int numsentences[2];
812 static char *sentbufend[2];
813 static char *sentmarks[2][10];
816 static char sentbuf[2][256];
818 static int say_sentence_num(int num , int prev)
821 currsentence = num + 1;
822 if (prev && --bn == -1)
825 if (num > numsentences[bn])
828 spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
832 static int get_sentence_buf(struct vc_data *vc, int read_punc)
842 start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
843 end = vc->vc_origin+((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
845 numsentences[bn] = 0;
846 sentmarks[bn][0] = &sentbuf[bn][0];
848 spk_old_attr = spk_attr;
849 spk_attr = get_attributes((u_short *) start);
851 while (start < end) {
852 sentbuf[bn][i] = (char) get_char(vc, (u_short *) start, &tmp);
854 if (sentbuf[bn][i] == SPACE && sentbuf[bn][i-1] == '.'
855 && numsentences[bn] < 9) {
856 /* Sentence Marker */
858 sentmarks[bn][numsentences[bn]] =
864 if (i >= vc->vc_size_row)
868 for (--i; i >= 0; i--)
869 if (sentbuf[bn][i] != SPACE)
875 sentbuf[bn][++i] = SPACE;
876 sentbuf[bn][++i] = '\0';
878 sentbufend[bn] = &sentbuf[bn][i];
879 return numsentences[bn];
882 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
884 u_long start = vc->vc_origin, end;
886 start += from * vc->vc_size_row;
887 if (to > vc->vc_rows)
889 end = vc->vc_origin + (to * vc->vc_size_row);
890 for (from = start; from < end; from = to) {
891 to = from + vc->vc_size_row;
892 say_from_to(vc, from, to, 1);
896 static void say_screen(struct vc_data *vc)
898 say_screen_from_to(vc, 0, vc->vc_rows);
901 static void speakup_win_say(struct vc_data *vc)
903 u_long start, end, from, to;
905 synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
908 start = vc->vc_origin + (win_top * vc->vc_size_row);
909 end = vc->vc_origin + (win_bottom * vc->vc_size_row);
910 while (start <= end) {
911 from = start + (win_left * 2);
912 to = start + (win_right * 2);
913 say_from_to(vc, from, to, 1);
914 start += vc->vc_size_row;
918 static void top_edge(struct vc_data *vc)
921 spk_pos = vc->vc_origin + 2 * spk_x;
926 static void bottom_edge(struct vc_data *vc)
929 spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
930 spk_y = vc->vc_rows - 1;
934 static void left_edge(struct vc_data *vc)
937 spk_pos -= spk_x * 2;
942 static void right_edge(struct vc_data *vc)
945 spk_pos += (vc->vc_cols - spk_x - 1) * 2;
946 spk_x = vc->vc_cols - 1;
950 static void say_first_char(struct vc_data *vc)
952 int i, len = get_line(vc);
956 synth_printf("%s\n", msg_get(MSG_BLANK));
959 for (i = 0; i < len; i++)
963 spk_pos -= (spk_x - i) * 2;
965 synth_printf("%d, ", ++i);
969 static void say_last_char(struct vc_data *vc)
971 int len = get_line(vc);
975 synth_printf("%s\n", msg_get(MSG_BLANK));
979 spk_pos -= (spk_x - len) * 2;
981 synth_printf("%d, ", ++len);
985 static void say_position(struct vc_data *vc)
987 synth_printf(msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
992 /* Added by brianb */
993 static void say_char_num(struct vc_data *vc)
996 u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
998 synth_printf(msg_get(MSG_CHAR_INFO), ch, ch);
1001 /* these are stub functions to keep keyboard.c happy. */
1003 static void say_from_top(struct vc_data *vc)
1005 say_screen_from_to(vc, 0, spk_y);
1008 static void say_to_bottom(struct vc_data *vc)
1010 say_screen_from_to(vc, spk_y, vc->vc_rows);
1013 static void say_from_left(struct vc_data *vc)
1015 say_line_from_to(vc, 0, spk_x, 1);
1018 static void say_to_right(struct vc_data *vc)
1020 say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1023 /* end of stub functions. */
1025 static void spkup_write(const char *in_buf, int count)
1027 static int rep_count = 0;
1028 static u_char ch = '\0', old_ch = '\0';
1029 static u_short char_type = 0, last_type = 0;
1030 int in_count = count;
1033 if (cursor_track == read_all_mode) {
1034 /* Insert Sentence Index */
1035 if ((in_buf == sentmarks[bn][currsentence]) &&
1036 (currsentence <= numsentences[bn]))
1037 synth_insert_next_index(currsentence++);
1039 ch = (u_char)*in_buf++;
1040 char_type = spk_chartab[ch];
1041 if (ch == old_ch && !(char_type&B_NUM)) {
1042 if (++rep_count > 2)
1045 if ((last_type&CH_RPT) && rep_count > 2) {
1047 synth_printf(msg_get(MSG_REPEAT_DESC), ++rep_count);
1052 if (ch == spk_lastkey) {
1054 if (key_echo == 1 && ch >= MINECHOCHAR)
1056 } else if (char_type & B_ALPHA) {
1057 if ((synth_flags & SF_DEC) && (last_type & PUNC))
1058 synth_buffer_add(SPACE);
1059 synth_printf("%c", ch);
1060 } else if (char_type & B_NUM) {
1062 synth_printf("%c", ch);
1063 } else if (char_type&punc_mask) {
1065 char_type &= ~PUNC; /* for dec nospell processing */
1066 } else if (char_type&SYNTH_OK) {
1067 /* these are usually puncts like . and , which synth needs for expression.
1068 * suppress multiple to get rid of long pausesand clear repeat count so if
1069 *someone has repeats on you don't get nothing repeated count */
1071 synth_printf("%c", ch);
1075 /* send space and record position, if next is num overwrite space */
1077 synth_buffer_add(SPACE);
1082 last_type = char_type;
1085 if (in_count > 2 && rep_count > 2) {
1086 if (last_type&CH_RPT) {
1088 synth_printf(msg_get(MSG_REPEAT_DESC2), ++rep_count);
1095 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1097 static void read_all_doc(struct vc_data *vc);
1098 static void cursor_done(u_long data);
1099 static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1101 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1103 unsigned long flags;
1104 if (synth == NULL || up_flag || spk_killed)
1107 if (cursor_track == read_all_mode) {
1110 del_timer(&cursor_timer);
1111 spk_shut_up &= 0xfe;
1116 del_timer(&cursor_timer);
1117 cursor_track = prev_cursor_track;
1118 spk_shut_up &= 0xfe;
1123 spk_shut_up &= 0xfe;
1126 if (say_ctrl && value < NUM_CTL_LABELS)
1127 synth_printf("%s", msg_get(MSG_CTL_START + value));
1131 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1133 unsigned long flags;
1136 spk_lastkey = spk_keydown = 0;
1140 if (synth == NULL || spk_killed) {
1144 spk_shut_up &= 0xfe;
1145 spk_lastkey = value;
1148 if (key_echo == 2 && value >= MINECHOCHAR)
1153 int set_key_info(const u_char *key_info, u_char *k_buffer)
1155 int i = 0, states, key_data_len;
1156 const u_char *cp = key_info;
1157 u_char *cp1 = k_buffer;
1158 u_char ch, version, num_keys;
1160 if (version != KEY_MAP_VER)
1163 states = (int) cp[1];
1164 key_data_len = (states + 1) * (num_keys + 1);
1165 if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(key_buf))
1167 memset(k_buffer, 0, SHIFT_TBL_SIZE);
1168 memset(our_keys, 0, sizeof(our_keys));
1169 shift_table = k_buffer;
1170 our_keys[0] = shift_table;
1171 cp1 += SHIFT_TBL_SIZE;
1172 memcpy(cp1, cp, key_data_len + 3);
1173 /* get num_keys, states and data*/
1174 cp1 += 2; /* now pointing at shift states */
1175 for (i = 1; i <= states; i++) {
1177 if (ch >= SHIFT_TBL_SIZE)
1179 shift_table[ch] = i;
1181 keymap_flags = *cp1++;
1182 while ((ch = *cp1)) {
1191 static struct var_t spk_vars[] = {
1192 /* bell must be first to set high limit */
1193 { BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL }},
1194 { SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL }},
1195 { ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL }},
1196 { BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL }},
1197 { BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL }},
1198 { PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL }},
1199 { READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL }},
1200 { CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL }},
1201 { SAY_CONTROL, TOGGLE_0 },
1202 { SAY_WORD_CTL, TOGGLE_0 },
1203 { NO_INTERRUPT, TOGGLE_0 },
1204 { KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL }},
1209 static void toggle_cursoring(struct vc_data *vc)
1211 if (cursor_track == read_all_mode)
1212 cursor_track = prev_cursor_track;
1213 if (++cursor_track >= CT_Max)
1215 synth_printf("%s\n", msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1218 void reset_default_chars(void)
1222 /* First, free any non-default */
1223 for (i = 0; i < 256; i++) {
1224 if ((characters[i] != NULL)
1225 && (characters[i] != default_chars[i]))
1226 kfree(characters[i]);
1229 memcpy(characters, default_chars, sizeof(default_chars));
1232 void reset_default_chartab(void)
1234 memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1237 static const struct st_bits_data *pb_edit = NULL;
1239 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1241 short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1242 if (type != KT_LATIN || (ch_type&B_NUM) || ch < SPACE)
1245 synth_printf("%s\n", msg_get(MSG_EDIT_DONE));
1246 special_handler = NULL;
1249 if (mask < PUNC && !(ch_type&PUNC))
1251 spk_chartab[ch] ^= mask;
1253 synth_printf(" %s\n",
1254 (spk_chartab[ch]&mask) ? msg_get(MSG_ON) : msg_get(MSG_OFF));
1258 /* Allocation concurrency is protected by the console semaphore */
1259 void speakup_allocate(struct vc_data *vc)
1263 vc_num = vc->vc_num;
1264 if (speakup_console[vc_num] == NULL) {
1265 speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1267 if (speakup_console[vc_num] == NULL)
1270 } else if (!spk_parked)
1274 void speakup_deallocate(struct vc_data *vc)
1278 vc_num = vc->vc_num;
1279 if (speakup_console[vc_num] != NULL) {
1280 kfree(speakup_console[vc_num]);
1281 speakup_console[vc_num] = NULL;
1285 static u_char is_cursor;
1286 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1287 static int cursor_con;
1289 static void reset_highlight_buffers(struct vc_data *);
1291 static int read_all_key;
1293 void reset_index_count(int);
1294 void get_index_count(int *, int *);
1295 /*int synth_supports_indexing(void); */
1296 static void start_read_all_timer(struct vc_data *vc, int command);
1311 kbd_fakekey2(struct vc_data *vc, int command)
1313 del_timer(&cursor_timer);
1314 speakup_fake_down_arrow();
1315 start_read_all_timer(vc, command);
1319 read_all_doc(struct vc_data *vc)
1321 if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1323 if (!synth_supports_indexing())
1325 if (cursor_track != read_all_mode)
1326 prev_cursor_track = cursor_track;
1327 cursor_track = read_all_mode;
1328 reset_index_count(0);
1329 if (get_sentence_buf(vc, 0) == -1)
1330 kbd_fakekey2(vc, RA_DOWN_ARROW);
1332 say_sentence_num(0, 0);
1333 synth_insert_next_index(0);
1334 start_read_all_timer(vc, RA_TIMER);
1339 stop_read_all(struct vc_data *vc)
1341 del_timer(&cursor_timer);
1342 cursor_track = prev_cursor_track;
1343 spk_shut_up &= 0xfe;
1348 start_read_all_timer(struct vc_data *vc, int command)
1350 struct var_t *cursor_timeout;
1352 cursor_con = vc->vc_num;
1353 read_all_key = command;
1354 cursor_timeout = get_var(CURSOR_TIME);
1355 mod_timer(&cursor_timer, jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1359 handle_cursor_read_all(struct vc_data *vc, int command)
1361 int indcount, sentcount, rv, sn;
1365 /* Get Current Sentence */
1366 get_index_count(&indcount, &sentcount);
1367 /*printk("%d %d ", indcount, sentcount); */
1368 reset_index_count(sentcount+1);
1369 if (indcount == 1) {
1370 if (!say_sentence_num(sentcount+1, 0)) {
1371 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1374 synth_insert_next_index(0);
1377 if (!say_sentence_num(sentcount+1, 1)) {
1379 reset_index_count(sn);
1381 synth_insert_next_index(0);
1382 if (!say_sentence_num(sn, 0)) {
1383 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1386 synth_insert_next_index(0);
1388 start_read_all_timer(vc, RA_TIMER);
1398 if (get_sentence_buf(vc, 0) == -1) {
1399 kbd_fakekey2(vc, RA_DOWN_ARROW);
1401 say_sentence_num(0, 0);
1402 synth_insert_next_index(0);
1403 start_read_all_timer(vc, RA_TIMER);
1406 case RA_FIND_NEXT_SENT:
1407 rv = get_sentence_buf(vc, 0);
1411 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1413 say_sentence_num(1, 0);
1414 synth_insert_next_index(0);
1415 start_read_all_timer(vc, RA_TIMER);
1418 case RA_FIND_PREV_SENT:
1421 get_index_count(&indcount, &sentcount);
1423 kbd_fakekey2(vc, RA_DOWN_ARROW);
1425 start_read_all_timer(vc, RA_TIMER);
1430 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1432 unsigned long flags;
1434 if (cursor_track == read_all_mode) {
1436 if (synth == NULL || up_flag || spk_shut_up) {
1440 del_timer(&cursor_timer);
1441 spk_shut_up &= 0xfe;
1443 start_read_all_timer(vc, value+1);
1451 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1453 unsigned long flags;
1454 struct var_t *cursor_timeout;
1458 if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1462 spk_shut_up &= 0xfe;
1465 /* the key press flushes if !no_inter but we want to flush on cursor
1466 * moves regardless of no_inter state */
1467 is_cursor = value + 1;
1468 old_cursor_pos = vc->vc_pos;
1469 old_cursor_x = vc->vc_x;
1470 old_cursor_y = vc->vc_y;
1471 speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1472 cursor_con = vc->vc_num;
1473 if (cursor_track == CT_Highlight)
1474 reset_highlight_buffers(vc);
1475 cursor_timeout = get_var(CURSOR_TIME);
1476 mod_timer(&cursor_timer, jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1481 update_color_buffer(struct vc_data *vc , const char *ic , int len)
1484 int vc_num = vc->vc_num;
1486 bi = ((vc->vc_attr & 0x70) >> 4) ;
1487 hi = speakup_console[vc_num]->ht.highsize[bi];
1490 if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1491 speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1492 speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1493 speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1495 while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1496 if ((ic[i] > 32) && (ic[i] < 127)) {
1497 speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1499 } else if ((ic[i] == 32) && (hi != 0)) {
1500 if (speakup_console[vc_num]->ht.highbuf[bi][hi-1] !=
1502 speakup_console[vc_num]->ht.highbuf[bi][hi] =
1509 speakup_console[vc_num]->ht.highsize[bi] = hi;
1513 reset_highlight_buffers(struct vc_data *vc)
1516 int vc_num = vc->vc_num;
1517 for (i = 0 ; i < 8 ; i++)
1518 speakup_console[vc_num]->ht.highsize[i] = 0;
1522 count_highlight_color(struct vc_data *vc)
1526 int vc_num = vc->vc_num;
1528 u16 *start = (u16 *) vc->vc_origin;
1530 for (i = 0; i < 8; i++)
1531 speakup_console[vc_num]->ht.bgcount[i] = 0;
1533 for (i = 0; i < vc->vc_rows; i++) {
1534 u16 *end = start + vc->vc_cols*2;
1536 for (ptr = start; ptr < end; ptr++) {
1537 ch = get_attributes(ptr);
1538 bg = (ch & 0x70) >> 4;
1539 speakup_console[vc_num]->ht.bgcount[bg]++;
1541 start += vc->vc_size_row;
1545 for (i = 0; i < 8; i++)
1546 if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1552 get_highlight_color(struct vc_data *vc)
1555 unsigned int cptr[8], tmp;
1556 int vc_num = vc->vc_num;
1558 for (i = 0; i < 8; i++)
1561 for (i = 0; i < 7; i++)
1562 for (j = i + 1; j < 8; j++)
1563 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1564 speakup_console[vc_num]->ht.bgcount[cptr[j]]) {
1570 for (i = 0; i < 8; i++)
1571 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1572 if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1578 speak_highlight(struct vc_data *vc)
1581 int vc_num = vc->vc_num;
1582 if (count_highlight_color(vc) == 1)
1584 hc = get_highlight_color(vc);
1586 d = vc->vc_y-speakup_console[vc_num]->ht.cy;
1587 if ((d == 1) || (d == -1))
1588 if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1592 spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1593 speakup_console[vc_num]->ht.highsize[hc]);
1594 spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1595 spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1596 spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1603 cursor_done(u_long data)
1605 struct vc_data *vc = vc_cons[cursor_con].d;
1606 unsigned long flags;
1607 del_timer(&cursor_timer);
1609 if (cursor_con != fg_console) {
1615 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1616 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1617 spk_keydown = is_cursor = 0;
1621 if (cursor_track == read_all_mode) {
1622 handle_cursor_read_all(vc, read_all_key);
1625 if (cursor_track == CT_Highlight) {
1626 if (speak_highlight(vc)) {
1627 spk_keydown = is_cursor = 0;
1631 if (cursor_track == CT_Window)
1632 speakup_win_say(vc);
1633 else if (is_cursor == 1 || is_cursor == 4)
1634 say_line_from_to(vc, 0, vc->vc_cols, 0);
1637 spk_keydown = is_cursor = 0;
1642 /* called by: vt_notifier_call() */
1643 static void speakup_bs(struct vc_data *vc)
1645 unsigned long flags;
1646 if (!speakup_console[vc->vc_num])
1648 if (!spk_trylock(flags))
1649 /* Speakup output, discard */
1653 if (spk_shut_up || synth == NULL) {
1657 if (vc->vc_num == fg_console && spk_keydown) {
1665 /* called by: vt_notifier_call() */
1666 static void speakup_con_write(struct vc_data *vc, const char *str, int len)
1668 unsigned long flags;
1669 if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1671 if (!spk_trylock(flags))
1672 /* Speakup output, discard */
1674 if (bell_pos && spk_keydown && (vc->vc_x == bell_pos - 1))
1676 if ((is_cursor) || (cursor_track == read_all_mode)) {
1677 if (cursor_track == CT_Highlight)
1678 update_color_buffer(vc, str, len);
1683 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1684 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1690 spkup_write(str, len);
1695 speakup_con_update(struct vc_data *vc)
1697 unsigned long flags;
1698 if (speakup_console[vc->vc_num] == NULL || spk_parked)
1700 if (!spk_trylock(flags))
1701 /* Speakup output, discard */
1707 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1709 unsigned long flags;
1712 if (synth == NULL || up_flag || spk_killed)
1715 spk_shut_up &= 0xfe;
1720 label = msg_get(MSG_KEYNAME_CAPSLOCK);
1721 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_CAPSLOCK));
1724 label = msg_get(MSG_KEYNAME_NUMLOCK);
1725 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_NUMLOCK));
1728 label = msg_get(MSG_KEYNAME_SCROLLLOCK);
1729 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_SCROLLOCK));
1730 if (speakup_console[vc->vc_num])
1731 speakup_console[vc->vc_num]->tty_stopped = on_off;
1739 synth_printf("%s %s\n",
1740 label, msg_get(MSG_STATUS_START + on_off));
1745 inc_dec_var(u_char value)
1747 struct st_var_header *p_header;
1748 struct var_t *var_data;
1752 int var_id = (int)value - VAR_START;
1753 int how = (var_id&1) ? E_INC : E_DEC;
1754 var_id = var_id/2+FIRST_SET_VAR;
1755 p_header = get_var_header(var_id);
1756 if (p_header == NULL)
1758 if (p_header->var_type != VAR_NUM)
1760 var_data = p_header->data;
1761 if (set_num_var(1, p_header, how) != 0)
1763 if (!spk_close_press) {
1764 for (pn = p_header->name; *pn; pn++) {
1771 snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1772 var_data->u.n.value);
1773 synth_printf("%s", num_buf);
1778 speakup_win_set(struct vc_data *vc)
1781 if (win_start > 1) {
1782 synth_printf("%s\n", msg_get(MSG_WINDOW_ALREADY_SET));
1785 if (spk_x < win_left || spk_y < win_top) {
1786 synth_printf("%s\n", msg_get(MSG_END_BEFORE_START));
1789 if (win_start && spk_x == win_left && spk_y == win_top) {
1791 win_right = vc->vc_cols-1;
1793 snprintf(info, sizeof(info), msg_get(MSG_WINDOW_LINE),
1803 snprintf(info, sizeof(info), msg_get(MSG_WINDOW_BOUNDARY),
1804 (win_start) ? msg_get(MSG_END) : msg_get(MSG_START),
1805 (int)spk_y+1, (int)spk_x+1);
1807 synth_printf("%s\n", info);
1812 speakup_win_clear(struct vc_data *vc)
1814 win_top = win_bottom = 0;
1815 win_left = win_right = 0;
1817 synth_printf("%s\n", msg_get(MSG_WINDOW_CLEARED));
1821 speakup_win_enable(struct vc_data *vc)
1823 if (win_start < 2) {
1824 synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
1829 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCED));
1831 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCE_DISABLED));
1835 speakup_bits(struct vc_data *vc)
1837 int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1838 if (special_handler != NULL || val < 1 || val > 6) {
1839 synth_printf("%s\n", msg_get(MSG_ERROR));
1842 pb_edit = &punc_info[val];
1843 synth_printf(msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1844 special_handler = edit_bits;
1847 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1849 static u_char *goto_buf = "\0\0\0\0\0\0";
1853 if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1855 if (type == KT_LATIN && ch == '\n')
1862 ch = goto_buf[--num];
1863 goto_buf[num] = '\0';
1864 spkup_write(&ch, 1);
1867 if (ch < '+' || ch > 'y')
1869 goto_buf[num++] = ch;
1870 goto_buf[num] = '\0';
1871 spkup_write(&ch, 1);
1872 maxlen = (*goto_buf >= '0') ? 3 : 4;
1873 if ((ch == '+' || ch == '-') && num == 1)
1875 if (ch >= '0' && ch <= '9' && num < maxlen)
1877 if (num < maxlen-1 || num > maxlen)
1879 if (ch < 'x' || ch > 'y') {
1882 synth_printf(" %s\n", msg_get(MSG_GOTO_CANCELED));
1883 goto_buf[num = 0] = '\0';
1884 special_handler = NULL;
1887 cp = speakup_s2i(goto_buf, &go_pos);
1888 goto_pos = (u_long)go_pos;
1890 if (*goto_buf < '0')
1896 if (goto_pos >= vc->vc_cols)
1897 goto_pos = vc->vc_cols-1;
1900 if (*goto_buf < '0')
1906 if (goto_pos >= vc->vc_rows)
1907 goto_pos = vc->vc_rows-1;
1910 goto_buf[num = 0] = '\0';
1912 special_handler = NULL;
1915 spk_pos -= spk_x * 2;
1917 spk_pos += goto_pos * 2;
1921 spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1928 speakup_goto(struct vc_data *vc)
1930 if (special_handler != NULL) {
1931 synth_printf("%s\n", msg_get(MSG_ERROR));
1934 synth_printf("%s\n", msg_get(MSG_GOTO));
1935 special_handler = handle_goto;
1939 static void speakup_help(struct vc_data *vc)
1941 handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1945 do_nothing(struct vc_data *vc)
1947 return; /* flush done in do_spkup */
1949 static u_char key_speakup, spk_key_locked;
1952 speakup_lock(struct vc_data *vc)
1954 if (!spk_key_locked)
1955 spk_key_locked = key_speakup = 16;
1957 spk_key_locked = key_speakup = 0;
1960 typedef void(*spkup_hand)(struct vc_data *);
1961 spkup_hand spkup_handler[] = {
1962 /* must be ordered same as defines in speakup.h */
1963 do_nothing, speakup_goto, speech_kill, speakup_shut_up,
1964 speakup_cut, speakup_paste, say_first_char, say_last_char,
1965 say_char, say_prev_char, say_next_char,
1966 say_word, say_prev_word, say_next_word,
1967 say_line, say_prev_line, say_next_line,
1968 top_edge, bottom_edge, left_edge, right_edge,
1969 spell_word, spell_word, say_screen,
1970 say_position, say_attributes,
1971 speakup_off, speakup_parked, say_line, /* this is for indent */
1972 say_from_top, say_to_bottom,
1973 say_from_left, say_to_right,
1974 say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
1975 speakup_bits, speakup_bits, speakup_bits,
1976 speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
1977 speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
1980 static void do_spkup(struct vc_data *vc, u_char value)
1982 if (spk_killed && value != SPEECH_KILL)
1986 spk_shut_up &= 0xfe;
1987 this_speakup_key = value;
1988 if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
1990 (*spkup_handler[value])(vc);
1992 if (inc_dec_var(value) < 0)
1997 static const char *pad_chars = "0123456789+-*/\015,.?()";
2000 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2003 unsigned long flags;
2006 u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2007 u_char shift_info, offset;
2016 if (type == KT_PAD &&
2017 (vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK))) {
2022 value = spk_lastkey = pad_chars[value];
2027 if (keycode >= MAX_KEY)
2029 key_info = our_keys[keycode];
2032 /* Check valid read all mode keys */
2033 if ((cursor_track == read_all_mode) && (!up_flag)) {
2047 shift_info = (shift_state&0x0f) + key_speakup;
2048 offset = shift_table[shift_info];
2050 new_key = key_info[offset];
2053 if (new_key == SPK_KEY) {
2054 if (!spk_key_locked)
2055 key_speakup = (up_flag) ? 0 : 16;
2056 if (up_flag || spk_killed)
2058 spk_shut_up &= 0xfe;
2064 if (last_keycode == keycode &&
2065 last_spk_jiffy+MAX_DELAY > jiffies) {
2066 spk_close_press = 1;
2067 offset = shift_table[shift_info+32];
2069 if (offset && key_info[offset])
2070 new_key = key_info[offset];
2072 last_keycode = keycode;
2073 last_spk_jiffy = jiffies;
2079 if (type == KT_SPKUP && special_handler == NULL) {
2080 do_spkup(vc, new_key);
2081 spk_close_press = 0;
2085 if (up_flag || spk_killed || type == KT_SHIFT)
2087 spk_shut_up &= 0xfe;
2088 kh = (value == KVAL(K_DOWN))
2089 || (value == KVAL(K_UP))
2090 || (value == KVAL(K_LEFT))
2091 || (value == KVAL(K_RIGHT));
2092 if ((cursor_track != read_all_mode) || !kh)
2095 if (special_handler) {
2096 if (type == KT_SPEC && value == 1) {
2099 } else if (type == KT_LETTER)
2101 else if (value == 0x7f)
2102 value = 8; /* make del = backspace */
2103 ret = (*special_handler)(vc, type, value, keycode);
2104 spk_close_press = 0;
2115 static int keyboard_notifier_call(struct notifier_block *nb,
2116 unsigned long code, void *_param)
2118 struct keyboard_notifier_param *param = _param;
2119 struct vc_data *vc = param->vc;
2120 int up = !param->down;
2121 int ret = NOTIFY_OK;
2122 static int keycode; /* to hold the current keycode */
2124 if (vc->vc_mode == KD_GRAPHICS)
2128 * First, determine whether we are handling a fake keypress on
2129 * the current processor. If we are, then return NOTIFY_OK,
2130 * to pass the keystroke up the chain. This prevents us from
2131 * trying to take the Speakup lock while it is held by the
2132 * processor on which the simulated keystroke was generated.
2133 * Also, the simulated keystrokes should be ignored by Speakup.
2136 if (speakup_fake_key_pressed())
2141 /* speakup requires keycode and keysym currently */
2142 keycode = param->value;
2144 case KBD_UNBOUND_KEYCODE:
2151 if (speakup_key(vc, param->shift, keycode, param->value, up))
2154 if (KTYP(param->value) == KT_CUR)
2155 ret = pre_handle_cursor(vc,
2156 KVAL(param->value), up);
2158 case KBD_POST_KEYSYM: {
2159 unsigned char type = KTYP(param->value) - 0xf0;
2160 unsigned char val = KVAL(param->value);
2163 do_handle_shift(vc, val, up);
2167 do_handle_latin(vc, val, up);
2170 do_handle_cursor(vc, val, up);
2173 do_handle_spec(vc, val, up);
2182 static int vt_notifier_call(struct notifier_block *nb,
2183 unsigned long code, void *_param)
2185 struct vt_notifier_param *param = _param;
2186 struct vc_data *vc = param->vc;
2189 if (vc->vc_mode == KD_TEXT)
2190 speakup_allocate(vc);
2193 speakup_deallocate(vc);
2196 if (param->c == '\b')
2199 if (param->c < 0x100) {
2201 speakup_con_write(vc, &d, 1);
2205 speakup_con_update(vc);
2211 /* called by: module_exit() */
2212 static void __exit speakup_exit(void)
2217 unregister_keyboard_notifier(&keyboard_notifier_block);
2218 unregister_vt_notifier(&vt_notifier_block);
2219 speakup_unregister_devsynth();
2220 del_timer(&cursor_timer);
2222 kthread_stop(speakup_task);
2223 speakup_task = NULL;
2224 mutex_lock(&spk_mutex);
2226 mutex_unlock(&spk_mutex);
2228 for (i = 0; i < MAXVARS; i++)
2229 speakup_unregister_var(i);
2231 for (i = 0; i < 256; i++) {
2232 if (characters[i] != default_chars[i])
2233 kfree(characters[i]);
2235 for (i = 0; speakup_console[i]; i++)
2236 kfree(speakup_console[i]);
2237 speakup_kobj_exit();
2238 speakup_remove_virtual_keyboard();
2241 /* call by: module_init() */
2242 static int __init speakup_init(void)
2246 struct st_spk_t *first_console;
2247 struct vc_data *vc = vc_cons[fg_console].d;
2250 err = speakup_add_virtual_keyboard();
2254 initialize_msgs(); /* Initialize arrays for i18n. */
2255 first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2258 if (speakup_kobj_init() < 0)
2261 reset_default_chars();
2262 reset_default_chartab();
2264 speakup_console[vc->vc_num] = first_console;
2266 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2269 spk_vars[0].u.n.high = vc->vc_cols;
2270 for (var = spk_vars; var->var_id !=MAXVARS; var++)
2271 speakup_register_var(var);
2272 for (var = synth_time_vars; (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2273 speakup_register_var(var);
2274 for (i = 1; punc_info[i].mask != 0; i++)
2275 set_mask_bits(0, i, 2);
2277 set_key_info(key_defaults, key_buf);
2279 spk_shut_up |= 0x01;
2281 for (i = 0; i < MAX_NR_CONSOLES; i++)
2283 speakup_allocate(vc_cons[i].d);
2285 pr_warn("synth name on entry is: %s\n", synth_name);
2286 synth_init(synth_name);
2287 speakup_register_devsynth();
2289 register_keyboard_notifier(&keyboard_notifier_block);
2290 register_vt_notifier(&vt_notifier_block);
2292 speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2293 set_user_nice(speakup_task, 10);
2294 if ( ! IS_ERR(speakup_task))
2295 wake_up_process(speakup_task);
2302 module_init(speakup_init);
2303 module_exit(speakup_exit);