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},
97 static char mark_cut_flag;
99 u_char *our_keys[MAX_KEY], *shift_table;
101 const u_char key_defaults[] = {
102 #include "speakupmap.h"
105 /* Speakup Cursor Track Variables */
106 static int cursor_track = 1, prev_cursor_track = 1;
108 /* cursor track modes, must be ordered same as cursor_msgs */
116 #define read_all_mode CT_Max
118 static struct tty_struct *tty;
120 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",
126 "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
127 "x ray", "yankee", "zulu"
130 /* array of 256 char pointers (one for each character description)
131 * initialized to default_chars and user selectable via
132 * /proc/speakup/characters */
133 char *characters[256];
135 char *default_chars[256] = {
136 /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
137 /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
138 /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
139 /*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
141 /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
143 /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
146 /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
148 /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
149 /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
150 /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
151 /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
152 /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
155 /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
156 /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
157 /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
158 /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
159 /*127*/ "del", "control", "control", "control", "control", "control",
160 "control", "control", "control", "control", "control",
161 /*138*/ "control", "control", "control", "control", "control",
162 "control", "control", "control", "control", "control",
163 "control", "control",
164 /*150*/ "control", "control", "control", "control", "control",
165 "control", "control", "control", "control", "control",
166 /*160*/ "nbsp", "inverted bang",
167 /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
168 /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
169 /*172*/ "not", "soft hyphen", "registered", "macron",
170 /*176*/ "degrees", "plus or minus", "super two", "super three",
171 /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
172 /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
173 /*188*/ "one quarter", "one half", "three quarters",
175 /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
177 /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
179 /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
181 /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
182 /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
184 /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
185 /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
186 /*230*/ "ae", "c cidella", "e grave", "e acute",
187 /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
189 /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
191 /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
193 /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
196 /* array of 256 u_short (one for each character)
197 * initialized to default_chartab and user selectable via
198 * /sys/module/speakup/parameters/chartab */
199 u_short spk_chartab[256];
201 static u_short default_chartab[256] = {
202 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
203 B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
204 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
205 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
206 WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */
207 PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */
208 NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
209 NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */
210 PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */
211 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
212 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
213 A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */
214 PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */
215 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
216 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
217 ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
218 B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
220 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
222 B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
224 B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
226 WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
228 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
229 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
230 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
231 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
232 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
233 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
234 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
235 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
236 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
237 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
238 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */
241 struct task_struct *speakup_task;
242 struct bleep unprocessed_sound;
243 static int spk_keydown;
244 static u_char spk_lastkey, spk_close_press, keymap_flags;
245 static u_char last_keycode, this_speakup_key;
246 static u_long last_spk_jiffy;
248 struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
250 DEFINE_MUTEX(spk_mutex);
252 static int keyboard_notifier_call(struct notifier_block *,
253 unsigned long code, void *param);
255 struct notifier_block keyboard_notifier_block = {
256 .notifier_call = keyboard_notifier_call,
259 static int vt_notifier_call(struct notifier_block *,
260 unsigned long code, void *param);
262 struct notifier_block vt_notifier_block = {
263 .notifier_call = vt_notifier_call,
266 static unsigned char get_attributes(u16 *pos)
268 return (u_char) (scr_readw(pos) >> 8);
271 static void speakup_date(struct vc_data *vc)
273 spk_x = spk_cx = vc->vc_x;
274 spk_y = spk_cy = vc->vc_y;
275 spk_pos = spk_cp = vc->vc_pos;
276 spk_old_attr = spk_attr;
277 spk_attr = get_attributes((u_short *) spk_pos);
280 static void bleep(u_short val)
282 static const short vals[] = {
283 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
286 int time = bleep_time;
287 freq = vals[val % 12];
289 freq *= (1 << (val / 12));
290 unprocessed_sound.freq = freq;
291 unprocessed_sound.jiffies = msecs_to_jiffies(time);
292 unprocessed_sound.active = 1;
293 /* We can only have 1 active sound at a time. */
296 static void speakup_shut_up(struct vc_data *vc)
307 static void speech_kill(struct vc_data *vc)
309 char val = synth->is_alive(synth);
313 /* re-enables synth, if disabled */
314 if (val == 2 || spk_killed) {
316 spk_shut_up &= ~0x40;
317 synth_printf("%s\n", msg_get(MSG_IAM_ALIVE));
319 synth_printf("%s\n", msg_get(MSG_YOU_KILLED_SPEAKUP));
324 static void speakup_off(struct vc_data *vc)
326 if (spk_shut_up & 0x80) {
328 synth_printf("%s\n", msg_get(MSG_HEY_THATS_BETTER));
331 synth_printf("%s\n", msg_get(MSG_YOU_TURNED_ME_OFF));
336 static void speakup_parked(struct vc_data *vc)
338 if (spk_parked & 0x80) {
340 synth_printf("%s\n", msg_get(MSG_UNPARKED));
343 synth_printf("%s\n", msg_get(MSG_PARKED));
347 static void speakup_cut(struct vc_data *vc)
349 static const char err_buf[] = "set selection failed";
352 if (!mark_cut_flag) {
354 xs = (u_short) spk_x;
355 ys = (u_short) spk_y;
357 synth_printf("%s\n", msg_get(MSG_MARK));
360 xe = (u_short) spk_x;
361 ye = (u_short) spk_y;
363 synth_printf("%s\n", msg_get(MSG_CUT));
365 speakup_clear_selection();
366 ret = speakup_set_selection(tty);
370 break; /* no error */
372 pr_warn("%sEFAULT\n", err_buf);
375 pr_warn("%sEINVAL\n", err_buf);
378 pr_warn("%sENOMEM\n", err_buf);
383 static void speakup_paste(struct vc_data *vc)
387 synth_printf("%s\n", msg_get(MSG_MARK_CLEARED));
389 synth_printf("%s\n", msg_get(MSG_PASTE));
390 speakup_paste_selection(tty);
394 static void say_attributes(struct vc_data *vc)
396 int fg = spk_attr & 0x0f;
397 int bg = spk_attr >> 4;
399 synth_printf("%s ", msg_get(MSG_BRIGHT));
402 synth_printf("%s", msg_get(MSG_COLORS_START + fg));
404 synth_printf(" %s ", msg_get(MSG_ON_BLINKING));
407 synth_printf(" %s ", msg_get(MSG_ON));
408 synth_printf("%s\n", msg_get(MSG_COLORS_START + bg));
419 static void announce_edge(struct vc_data *vc, int msg_id)
423 if ((bleeps & 2) && (msg_id < edge_quiet))
424 synth_printf("%s\n", msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
427 static void speak_char(u_char ch)
429 char *cp = characters[ch];
430 struct var_t *direct = get_var(DIRECT);
431 if (direct && direct->u.n.value) {
432 if (IS_CHAR(ch, B_CAP)) {
434 synth_printf("%s", str_caps_start);
436 synth_printf("%c", ch);
437 if (IS_CHAR(ch, B_CAP))
438 synth_printf("%s", str_caps_stop);
442 pr_info("speak_char: cp == NULL!\n");
445 synth_buffer_add(SPACE);
446 if (IS_CHAR(ch, B_CAP)) {
448 synth_printf("%s", str_caps_start);
449 synth_printf("%s", cp);
450 synth_printf("%s", str_caps_stop);
453 synth_printf("%s", msg_get(MSG_CTRL));
456 synth_printf("%s", cp);
458 synth_buffer_add(SPACE);
461 static u16 get_char(struct vc_data *vc, u16 * pos, u_char * attribs)
465 u16 w = scr_readw(pos);
468 if (w & vc->vc_hi_font_mask)
471 ch = inverse_translate(vc, c, 0);
472 *attribs = (w & 0xff00) >> 8;
477 static void say_char(struct vc_data *vc)
480 spk_old_attr = spk_attr;
481 ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
482 if (spk_attr != spk_old_attr) {
483 if (attrib_bleep & 1)
485 if (attrib_bleep & 2)
488 speak_char(ch & 0xff);
491 static void say_phonetic_char(struct vc_data *vc)
494 spk_old_attr = spk_attr;
495 ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
496 if (isascii(ch) && isalpha(ch)) {
498 synth_printf("%s\n", phonetic[--ch]);
500 if (IS_CHAR(ch, B_NUM))
501 synth_printf("%s ", msg_get(MSG_NUMBER));
506 static void say_prev_char(struct vc_data *vc)
510 announce_edge(vc, edge_left);
518 static void say_next_char(struct vc_data *vc)
521 if (spk_x == vc->vc_cols - 1) {
522 announce_edge(vc, edge_right);
530 /* get_word - will first check to see if the character under the
531 * reading cursor is a space and if say_word_ctl is true it will
532 * return the word space. If say_word_ctl is not set it will check to
533 * see if there is a word starting on the next position to the right
534 * and return that word if it exists. If it does not exist it will
535 * move left to the beginning of any previous word on the line or the
536 * beginning off the line whichever comes first.. */
538 static u_long get_word(struct vc_data *vc)
540 u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
544 spk_old_attr = spk_attr;
545 ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
547 /* decided to take out the sayword if on a space (mis-information */
548 if (say_word_ctl && ch == SPACE) {
550 synth_printf("%s\n", msg_get(MSG_SPACE));
552 } else if ((tmpx < vc->vc_cols - 2)
553 && (ch == SPACE || ch == 0 || IS_WDLM(ch))
554 && ((char)get_char(vc, (u_short *) &tmp_pos + 1, &temp) >
560 ch = (char)get_char(vc, (u_short *) tmp_pos - 1, &temp);
561 if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
562 && ((char)get_char(vc, (u_short *) tmp_pos, &temp) >
568 attr_ch = get_char(vc, (u_short *) tmp_pos, &spk_attr);
569 buf[cnt++] = attr_ch & 0xff;
570 while (tmpx < vc->vc_cols - 1) {
573 ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
574 if ((ch == SPACE) || ch == 0
575 || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
583 static void say_word(struct vc_data *vc)
585 u_long cnt = get_word(vc);
586 u_short saved_punc_mask = punc_mask;
591 spkup_write(buf, cnt);
592 punc_mask = saved_punc_mask;
595 static void say_prev_word(struct vc_data *vc)
599 u_short edge_said = 0, last_state = 0, state = 0;
604 announce_edge(vc, edge_top);
609 edge_said = edge_quiet;
614 edge_said = edge_top;
617 if (edge_said != edge_quiet)
618 edge_said = edge_left;
622 spk_x = vc->vc_cols - 1;
626 ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
627 if (ch == SPACE || ch == 0)
629 else if (IS_WDLM(ch))
633 if (state < last_state) {
640 if (spk_x == 0 && edge_said == edge_quiet)
641 edge_said = edge_left;
642 if (edge_said > 0 && edge_said < edge_quiet)
643 announce_edge(vc, edge_said);
647 static void say_next_word(struct vc_data *vc)
651 u_short edge_said = 0, last_state = 2, state = 0;
654 if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
655 announce_edge(vc, edge_bottom);
659 ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
660 if (ch == SPACE || ch == 0)
662 else if (IS_WDLM(ch))
666 if (state > last_state)
668 if (spk_x >= vc->vc_cols - 1) {
669 if (spk_y == vc->vc_rows - 1) {
670 edge_said = edge_bottom;
676 edge_said = edge_right;
683 announce_edge(vc, edge_said);
687 static void spell_word(struct vc_data *vc)
689 static char *delay_str[] = { "", ",", ".", ". .", ". . ." };
690 char *cp = buf, *str_cap = str_caps_stop;
691 char *cp1, *last_cap = str_caps_stop;
695 while ((ch = (u_char) *cp)) {
697 synth_printf(" %s ", delay_str[spell_delay]);
698 if (IS_CHAR(ch, B_CAP)) {
699 str_cap = str_caps_start;
702 else /* synth has no pitch */
703 last_cap = str_caps_stop;
705 str_cap = str_caps_stop;
706 if (str_cap != last_cap) {
707 synth_printf("%s", str_cap);
710 if (this_speakup_key == SPELL_PHONETIC
711 && (isascii(ch) && isalpha(ch))) {
713 cp1 = phonetic[--ch];
715 cp1 = characters[ch];
717 synth_printf("%s", msg_get(MSG_CTRL));
721 synth_printf("%s", cp1);
724 if (str_cap != str_caps_stop)
725 synth_printf("%s", str_caps_stop);
728 static int get_line(struct vc_data *vc)
730 u_long tmp = spk_pos - (spk_x * 2);
734 spk_old_attr = spk_attr;
735 spk_attr = get_attributes((u_short *) spk_pos);
736 for (i = 0; i < vc->vc_cols; i++) {
737 buf[i] = (u_char) get_char(vc, (u_short *) tmp, &tmp2);
740 for (--i; i >= 0; i--)
746 static void say_line(struct vc_data *vc)
748 int i = get_line(vc);
750 u_short saved_punc_mask = punc_mask;
752 synth_printf("%s\n", msg_get(MSG_BLANK));
756 if (this_speakup_key == SAY_LINE_INDENT) {
760 synth_printf("%d, ", (cp - buf) + 1);
762 punc_mask = punc_masks[reading_punc];
764 punc_mask = saved_punc_mask;
767 static void say_prev_line(struct vc_data *vc)
771 announce_edge(vc, edge_top);
775 spk_pos -= vc->vc_size_row;
779 static void say_next_line(struct vc_data *vc)
782 if (spk_y == vc->vc_rows - 1) {
783 announce_edge(vc, edge_bottom);
787 spk_pos += vc->vc_size_row;
791 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
796 u_short saved_punc_mask = punc_mask;
797 spk_old_attr = spk_attr;
798 spk_attr = get_attributes((u_short *) from);
800 buf[i++] = (char)get_char(vc, (u_short *) from, &tmp);
802 if (i >= vc->vc_size_row)
805 for (--i; i >= 0; i--)
813 punc_mask = punc_info[reading_punc].mask;
816 punc_mask = saved_punc_mask;
820 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
823 u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
824 u_long end = start + (to * 2);
826 if (say_from_to(vc, start, end, read_punc) <= 0)
827 if (cursor_track != read_all_mode)
828 synth_printf("%s\n", msg_get(MSG_BLANK));
831 /* Sentence Reading Commands */
833 static int currsentence;
834 static int numsentences[2];
835 static char *sentbufend[2];
836 static char *sentmarks[2][10];
839 static char sentbuf[2][256];
841 static int say_sentence_num(int num, int prev)
844 currsentence = num + 1;
845 if (prev && --bn == -1)
848 if (num > numsentences[bn])
851 spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
855 static int get_sentence_buf(struct vc_data *vc, int read_punc)
865 start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
866 end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
868 numsentences[bn] = 0;
869 sentmarks[bn][0] = &sentbuf[bn][0];
871 spk_old_attr = spk_attr;
872 spk_attr = get_attributes((u_short *) start);
874 while (start < end) {
875 sentbuf[bn][i] = (char)get_char(vc, (u_short *) start, &tmp);
877 if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
878 && numsentences[bn] < 9) {
879 /* Sentence Marker */
881 sentmarks[bn][numsentences[bn]] =
887 if (i >= vc->vc_size_row)
891 for (--i; i >= 0; i--)
892 if (sentbuf[bn][i] != SPACE)
898 sentbuf[bn][++i] = SPACE;
899 sentbuf[bn][++i] = '\0';
901 sentbufend[bn] = &sentbuf[bn][i];
902 return numsentences[bn];
905 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
907 u_long start = vc->vc_origin, end;
909 start += from * vc->vc_size_row;
910 if (to > vc->vc_rows)
912 end = vc->vc_origin + (to * vc->vc_size_row);
913 for (from = start; from < end; from = to) {
914 to = from + vc->vc_size_row;
915 say_from_to(vc, from, to, 1);
919 static void say_screen(struct vc_data *vc)
921 say_screen_from_to(vc, 0, vc->vc_rows);
924 static void speakup_win_say(struct vc_data *vc)
926 u_long start, end, from, to;
928 synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
931 start = vc->vc_origin + (win_top * vc->vc_size_row);
932 end = vc->vc_origin + (win_bottom * vc->vc_size_row);
933 while (start <= end) {
934 from = start + (win_left * 2);
935 to = start + (win_right * 2);
936 say_from_to(vc, from, to, 1);
937 start += vc->vc_size_row;
941 static void top_edge(struct vc_data *vc)
944 spk_pos = vc->vc_origin + 2 * spk_x;
949 static void bottom_edge(struct vc_data *vc)
952 spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
953 spk_y = vc->vc_rows - 1;
957 static void left_edge(struct vc_data *vc)
960 spk_pos -= spk_x * 2;
965 static void right_edge(struct vc_data *vc)
968 spk_pos += (vc->vc_cols - spk_x - 1) * 2;
969 spk_x = vc->vc_cols - 1;
973 static void say_first_char(struct vc_data *vc)
975 int i, len = get_line(vc);
979 synth_printf("%s\n", msg_get(MSG_BLANK));
982 for (i = 0; i < len; i++)
986 spk_pos -= (spk_x - i) * 2;
988 synth_printf("%d, ", ++i);
992 static void say_last_char(struct vc_data *vc)
994 int len = get_line(vc);
998 synth_printf("%s\n", msg_get(MSG_BLANK));
1002 spk_pos -= (spk_x - len) * 2;
1004 synth_printf("%d, ", ++len);
1008 static void say_position(struct vc_data *vc)
1010 synth_printf(msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1015 /* Added by brianb */
1016 static void say_char_num(struct vc_data *vc)
1019 u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
1021 synth_printf(msg_get(MSG_CHAR_INFO), ch, ch);
1024 /* these are stub functions to keep keyboard.c happy. */
1026 static void say_from_top(struct vc_data *vc)
1028 say_screen_from_to(vc, 0, spk_y);
1031 static void say_to_bottom(struct vc_data *vc)
1033 say_screen_from_to(vc, spk_y, vc->vc_rows);
1036 static void say_from_left(struct vc_data *vc)
1038 say_line_from_to(vc, 0, spk_x, 1);
1041 static void say_to_right(struct vc_data *vc)
1043 say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1046 /* end of stub functions. */
1048 static void spkup_write(const char *in_buf, int count)
1050 static int rep_count;
1051 static u_char ch = '\0', old_ch = '\0';
1052 static u_short char_type, last_type;
1053 int in_count = count;
1056 if (cursor_track == read_all_mode) {
1057 /* Insert Sentence Index */
1058 if ((in_buf == sentmarks[bn][currsentence]) &&
1059 (currsentence <= numsentences[bn]))
1060 synth_insert_next_index(currsentence++);
1062 ch = (u_char) *in_buf++;
1063 char_type = spk_chartab[ch];
1064 if (ch == old_ch && !(char_type & B_NUM)) {
1065 if (++rep_count > 2)
1068 if ((last_type & CH_RPT) && rep_count > 2) {
1070 synth_printf(msg_get(MSG_REPEAT_DESC),
1076 if (ch == spk_lastkey) {
1078 if (key_echo == 1 && ch >= MINECHOCHAR)
1080 } else if (char_type & B_ALPHA) {
1081 if ((synth_flags & SF_DEC) && (last_type & PUNC))
1082 synth_buffer_add(SPACE);
1083 synth_printf("%c", ch);
1084 } else if (char_type & B_NUM) {
1086 synth_printf("%c", ch);
1087 } else if (char_type & punc_mask) {
1089 char_type &= ~PUNC; /* for dec nospell processing */
1090 } else if (char_type & SYNTH_OK) {
1091 /* these are usually puncts like . and , which synth
1092 * needs for expression.
1093 * suppress multiple to get rid of long pauses and
1094 * clear repeat count
1096 * repeats on you don't get nothing repeated count */
1098 synth_printf("%c", ch);
1102 /* send space and record position, if next is num overwrite space */
1104 synth_buffer_add(SPACE);
1109 last_type = char_type;
1112 if (in_count > 2 && rep_count > 2) {
1113 if (last_type & CH_RPT) {
1115 synth_printf(msg_get(MSG_REPEAT_DESC2), ++rep_count);
1122 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1124 static void read_all_doc(struct vc_data *vc);
1125 static void cursor_done(u_long data);
1126 static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1128 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1130 unsigned long flags;
1131 if (synth == NULL || up_flag || spk_killed)
1134 if (cursor_track == read_all_mode) {
1137 del_timer(&cursor_timer);
1138 spk_shut_up &= 0xfe;
1143 del_timer(&cursor_timer);
1144 cursor_track = prev_cursor_track;
1145 spk_shut_up &= 0xfe;
1150 spk_shut_up &= 0xfe;
1153 if (say_ctrl && value < NUM_CTL_LABELS)
1154 synth_printf("%s", msg_get(MSG_CTL_START + value));
1158 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1160 unsigned long flags;
1163 spk_lastkey = spk_keydown = 0;
1167 if (synth == NULL || spk_killed) {
1171 spk_shut_up &= 0xfe;
1172 spk_lastkey = value;
1175 if (key_echo == 2 && value >= MINECHOCHAR)
1180 int set_key_info(const u_char *key_info, u_char *k_buffer)
1182 int i = 0, states, key_data_len;
1183 const u_char *cp = key_info;
1184 u_char *cp1 = k_buffer;
1185 u_char ch, version, num_keys;
1187 if (version != KEY_MAP_VER)
1190 states = (int)cp[1];
1191 key_data_len = (states + 1) * (num_keys + 1);
1192 if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(key_buf))
1194 memset(k_buffer, 0, SHIFT_TBL_SIZE);
1195 memset(our_keys, 0, sizeof(our_keys));
1196 shift_table = k_buffer;
1197 our_keys[0] = shift_table;
1198 cp1 += SHIFT_TBL_SIZE;
1199 memcpy(cp1, cp, key_data_len + 3);
1200 /* get num_keys, states and data */
1201 cp1 += 2; /* now pointing at shift states */
1202 for (i = 1; i <= states; i++) {
1204 if (ch >= SHIFT_TBL_SIZE)
1206 shift_table[ch] = i;
1208 keymap_flags = *cp1++;
1209 while ((ch = *cp1)) {
1218 static struct var_t spk_vars[] = {
1219 /* bell must be first to set high limit */
1220 {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1221 {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1222 {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1223 {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1224 {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1225 {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1226 {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1227 {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1228 {SAY_CONTROL, TOGGLE_0},
1229 {SAY_WORD_CTL, TOGGLE_0},
1230 {NO_INTERRUPT, TOGGLE_0},
1231 {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1235 static void toggle_cursoring(struct vc_data *vc)
1237 if (cursor_track == read_all_mode)
1238 cursor_track = prev_cursor_track;
1239 if (++cursor_track >= CT_Max)
1241 synth_printf("%s\n", msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1244 void reset_default_chars(void)
1248 /* First, free any non-default */
1249 for (i = 0; i < 256; i++) {
1250 if ((characters[i] != NULL)
1251 && (characters[i] != default_chars[i]))
1252 kfree(characters[i]);
1255 memcpy(characters, default_chars, sizeof(default_chars));
1258 void reset_default_chartab(void)
1260 memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1263 static const struct st_bits_data *pb_edit;
1265 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1267 short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1268 if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1271 synth_printf("%s\n", msg_get(MSG_EDIT_DONE));
1272 special_handler = NULL;
1275 if (mask < PUNC && !(ch_type & PUNC))
1277 spk_chartab[ch] ^= mask;
1279 synth_printf(" %s\n",
1280 (spk_chartab[ch] & mask) ? msg_get(MSG_ON) :
1285 /* Allocation concurrency is protected by the console semaphore */
1286 int speakup_allocate(struct vc_data *vc)
1290 vc_num = vc->vc_num;
1291 if (speakup_console[vc_num] == NULL) {
1292 speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1294 if (speakup_console[vc_num] == NULL)
1297 } else if (!spk_parked)
1303 void speakup_deallocate(struct vc_data *vc)
1307 vc_num = vc->vc_num;
1308 if (speakup_console[vc_num] != NULL) {
1309 kfree(speakup_console[vc_num]);
1310 speakup_console[vc_num] = NULL;
1314 static u_char is_cursor;
1315 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1316 static int cursor_con;
1318 static void reset_highlight_buffers(struct vc_data *);
1320 static int read_all_key;
1322 static void start_read_all_timer(struct vc_data *vc, int command);
1336 static void kbd_fakekey2(struct vc_data *vc, int command)
1338 del_timer(&cursor_timer);
1339 speakup_fake_down_arrow();
1340 start_read_all_timer(vc, command);
1343 static void read_all_doc(struct vc_data *vc)
1345 if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1347 if (!synth_supports_indexing())
1349 if (cursor_track != read_all_mode)
1350 prev_cursor_track = cursor_track;
1351 cursor_track = read_all_mode;
1352 reset_index_count(0);
1353 if (get_sentence_buf(vc, 0) == -1)
1354 kbd_fakekey2(vc, RA_DOWN_ARROW);
1356 say_sentence_num(0, 0);
1357 synth_insert_next_index(0);
1358 start_read_all_timer(vc, RA_TIMER);
1362 static void stop_read_all(struct vc_data *vc)
1364 del_timer(&cursor_timer);
1365 cursor_track = prev_cursor_track;
1366 spk_shut_up &= 0xfe;
1370 static void start_read_all_timer(struct vc_data *vc, int command)
1372 struct var_t *cursor_timeout;
1374 cursor_con = vc->vc_num;
1375 read_all_key = command;
1376 cursor_timeout = get_var(CURSOR_TIME);
1377 mod_timer(&cursor_timer,
1378 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1381 static void handle_cursor_read_all(struct vc_data *vc, int command)
1383 int indcount, sentcount, rv, sn;
1387 /* Get Current Sentence */
1388 get_index_count(&indcount, &sentcount);
1389 /*printk("%d %d ", indcount, sentcount); */
1390 reset_index_count(sentcount + 1);
1391 if (indcount == 1) {
1392 if (!say_sentence_num(sentcount + 1, 0)) {
1393 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1396 synth_insert_next_index(0);
1399 if (!say_sentence_num(sentcount + 1, 1)) {
1401 reset_index_count(sn);
1403 synth_insert_next_index(0);
1404 if (!say_sentence_num(sn, 0)) {
1405 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1408 synth_insert_next_index(0);
1410 start_read_all_timer(vc, RA_TIMER);
1420 if (get_sentence_buf(vc, 0) == -1) {
1421 kbd_fakekey2(vc, RA_DOWN_ARROW);
1423 say_sentence_num(0, 0);
1424 synth_insert_next_index(0);
1425 start_read_all_timer(vc, RA_TIMER);
1428 case RA_FIND_NEXT_SENT:
1429 rv = get_sentence_buf(vc, 0);
1433 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1435 say_sentence_num(1, 0);
1436 synth_insert_next_index(0);
1437 start_read_all_timer(vc, RA_TIMER);
1440 case RA_FIND_PREV_SENT:
1443 get_index_count(&indcount, &sentcount);
1445 kbd_fakekey2(vc, RA_DOWN_ARROW);
1447 start_read_all_timer(vc, RA_TIMER);
1452 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1454 unsigned long flags;
1456 if (cursor_track == read_all_mode) {
1458 if (synth == NULL || up_flag || spk_shut_up) {
1462 del_timer(&cursor_timer);
1463 spk_shut_up &= 0xfe;
1465 start_read_all_timer(vc, value + 1);
1473 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1475 unsigned long flags;
1476 struct var_t *cursor_timeout;
1480 if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1484 spk_shut_up &= 0xfe;
1487 /* the key press flushes if !no_inter but we want to flush on cursor
1488 * moves regardless of no_inter state */
1489 is_cursor = value + 1;
1490 old_cursor_pos = vc->vc_pos;
1491 old_cursor_x = vc->vc_x;
1492 old_cursor_y = vc->vc_y;
1493 speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1494 cursor_con = vc->vc_num;
1495 if (cursor_track == CT_Highlight)
1496 reset_highlight_buffers(vc);
1497 cursor_timeout = get_var(CURSOR_TIME);
1498 mod_timer(&cursor_timer,
1499 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1503 static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
1506 int vc_num = vc->vc_num;
1508 bi = ((vc->vc_attr & 0x70) >> 4);
1509 hi = speakup_console[vc_num]->ht.highsize[bi];
1512 if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1513 speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1514 speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1515 speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1517 while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1518 if ((ic[i] > 32) && (ic[i] < 127)) {
1519 speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1521 } else if ((ic[i] == 32) && (hi != 0)) {
1522 if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1524 speakup_console[vc_num]->ht.highbuf[bi][hi] =
1531 speakup_console[vc_num]->ht.highsize[bi] = hi;
1534 static void reset_highlight_buffers(struct vc_data *vc)
1537 int vc_num = vc->vc_num;
1538 for (i = 0; i < 8; i++)
1539 speakup_console[vc_num]->ht.highsize[i] = 0;
1542 static int count_highlight_color(struct vc_data *vc)
1546 int vc_num = vc->vc_num;
1548 u16 *start = (u16 *) vc->vc_origin;
1550 for (i = 0; i < 8; i++)
1551 speakup_console[vc_num]->ht.bgcount[i] = 0;
1553 for (i = 0; i < vc->vc_rows; i++) {
1554 u16 *end = start + vc->vc_cols * 2;
1556 for (ptr = start; ptr < end; ptr++) {
1557 ch = get_attributes(ptr);
1558 bg = (ch & 0x70) >> 4;
1559 speakup_console[vc_num]->ht.bgcount[bg]++;
1561 start += vc->vc_size_row;
1565 for (i = 0; i < 8; i++)
1566 if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1571 static int get_highlight_color(struct vc_data *vc)
1574 unsigned int cptr[8], tmp;
1575 int vc_num = vc->vc_num;
1577 for (i = 0; i < 8; i++)
1580 for (i = 0; i < 7; i++)
1581 for (j = i + 1; j < 8; j++)
1582 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1583 speakup_console[vc_num]->ht.bgcount[cptr[j]]) {
1589 for (i = 0; i < 8; i++)
1590 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1591 if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1596 static int speak_highlight(struct vc_data *vc)
1599 int vc_num = vc->vc_num;
1600 if (count_highlight_color(vc) == 1)
1602 hc = get_highlight_color(vc);
1604 d = vc->vc_y - speakup_console[vc_num]->ht.cy;
1605 if ((d == 1) || (d == -1))
1606 if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1610 spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1611 speakup_console[vc_num]->ht.highsize[hc]);
1612 spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1613 spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1614 spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1620 static void cursor_done(u_long data)
1622 struct vc_data *vc = vc_cons[cursor_con].d;
1623 unsigned long flags;
1624 del_timer(&cursor_timer);
1626 if (cursor_con != fg_console) {
1632 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1633 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1634 spk_keydown = is_cursor = 0;
1638 if (cursor_track == read_all_mode) {
1639 handle_cursor_read_all(vc, read_all_key);
1642 if (cursor_track == CT_Highlight) {
1643 if (speak_highlight(vc)) {
1644 spk_keydown = is_cursor = 0;
1648 if (cursor_track == CT_Window)
1649 speakup_win_say(vc);
1650 else if (is_cursor == 1 || is_cursor == 4)
1651 say_line_from_to(vc, 0, vc->vc_cols, 0);
1654 spk_keydown = is_cursor = 0;
1659 /* called by: vt_notifier_call() */
1660 static void speakup_bs(struct vc_data *vc)
1662 unsigned long flags;
1663 if (!speakup_console[vc->vc_num])
1665 if (!spk_trylock(flags))
1666 /* Speakup output, discard */
1670 if (spk_shut_up || synth == NULL) {
1674 if (vc->vc_num == fg_console && spk_keydown) {
1682 /* called by: vt_notifier_call() */
1683 static void speakup_con_write(struct vc_data *vc, const char *str, int len)
1685 unsigned long flags;
1686 if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1688 if (!spk_trylock(flags))
1689 /* Speakup output, discard */
1691 if (bell_pos && spk_keydown && (vc->vc_x == bell_pos - 1))
1693 if ((is_cursor) || (cursor_track == read_all_mode)) {
1694 if (cursor_track == CT_Highlight)
1695 update_color_buffer(vc, str, len);
1700 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1701 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1707 spkup_write(str, len);
1711 void speakup_con_update(struct vc_data *vc)
1713 unsigned long flags;
1714 if (speakup_console[vc->vc_num] == NULL || spk_parked)
1716 if (!spk_trylock(flags))
1717 /* Speakup output, discard */
1723 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1725 unsigned long flags;
1728 if (synth == NULL || up_flag || spk_killed)
1731 spk_shut_up &= 0xfe;
1736 label = msg_get(MSG_KEYNAME_CAPSLOCK);
1737 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_CAPSLOCK));
1740 label = msg_get(MSG_KEYNAME_NUMLOCK);
1741 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_NUMLOCK));
1744 label = msg_get(MSG_KEYNAME_SCROLLLOCK);
1745 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_SCROLLOCK));
1746 if (speakup_console[vc->vc_num])
1747 speakup_console[vc->vc_num]->tty_stopped = on_off;
1755 synth_printf("%s %s\n",
1756 label, msg_get(MSG_STATUS_START + on_off));
1760 static int inc_dec_var(u_char value)
1762 struct st_var_header *p_header;
1763 struct var_t *var_data;
1767 int var_id = (int)value - VAR_START;
1768 int how = (var_id & 1) ? E_INC : E_DEC;
1769 var_id = var_id / 2 + FIRST_SET_VAR;
1770 p_header = get_var_header(var_id);
1771 if (p_header == NULL)
1773 if (p_header->var_type != VAR_NUM)
1775 var_data = p_header->data;
1776 if (set_num_var(1, p_header, how) != 0)
1778 if (!spk_close_press) {
1779 for (pn = p_header->name; *pn; pn++) {
1786 snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1787 var_data->u.n.value);
1788 synth_printf("%s", num_buf);
1792 static void speakup_win_set(struct vc_data *vc)
1795 if (win_start > 1) {
1796 synth_printf("%s\n", msg_get(MSG_WINDOW_ALREADY_SET));
1799 if (spk_x < win_left || spk_y < win_top) {
1800 synth_printf("%s\n", msg_get(MSG_END_BEFORE_START));
1803 if (win_start && spk_x == win_left && spk_y == win_top) {
1805 win_right = vc->vc_cols - 1;
1807 snprintf(info, sizeof(info), msg_get(MSG_WINDOW_LINE),
1817 snprintf(info, sizeof(info), msg_get(MSG_WINDOW_BOUNDARY),
1818 (win_start) ? msg_get(MSG_END) : msg_get(MSG_START),
1819 (int)spk_y + 1, (int)spk_x + 1);
1821 synth_printf("%s\n", info);
1825 static void speakup_win_clear(struct vc_data *vc)
1827 win_top = win_bottom = 0;
1828 win_left = win_right = 0;
1830 synth_printf("%s\n", msg_get(MSG_WINDOW_CLEARED));
1833 static void speakup_win_enable(struct vc_data *vc)
1835 if (win_start < 2) {
1836 synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
1841 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCED));
1843 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCE_DISABLED));
1846 static void speakup_bits(struct vc_data *vc)
1848 int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1849 if (special_handler != NULL || val < 1 || val > 6) {
1850 synth_printf("%s\n", msg_get(MSG_ERROR));
1853 pb_edit = &punc_info[val];
1854 synth_printf(msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1855 special_handler = edit_bits;
1858 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1860 static u_char *goto_buf = "\0\0\0\0\0\0";
1864 if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1866 if (type == KT_LATIN && ch == '\n')
1873 ch = goto_buf[--num];
1874 goto_buf[num] = '\0';
1875 spkup_write(&ch, 1);
1878 if (ch < '+' || ch > 'y')
1880 goto_buf[num++] = ch;
1881 goto_buf[num] = '\0';
1882 spkup_write(&ch, 1);
1883 maxlen = (*goto_buf >= '0') ? 3 : 4;
1884 if ((ch == '+' || ch == '-') && num == 1)
1886 if (ch >= '0' && ch <= '9' && num < maxlen)
1888 if (num < maxlen - 1 || num > maxlen)
1890 if (ch < 'x' || ch > 'y') {
1893 synth_printf(" %s\n", msg_get(MSG_GOTO_CANCELED));
1894 goto_buf[num = 0] = '\0';
1895 special_handler = NULL;
1898 cp = speakup_s2i(goto_buf, &go_pos);
1899 goto_pos = (u_long) go_pos;
1901 if (*goto_buf < '0')
1907 if (goto_pos >= vc->vc_cols)
1908 goto_pos = vc->vc_cols - 1;
1911 if (*goto_buf < '0')
1917 if (goto_pos >= vc->vc_rows)
1918 goto_pos = vc->vc_rows - 1;
1921 goto_buf[num = 0] = '\0';
1923 special_handler = NULL;
1926 spk_pos -= spk_x * 2;
1928 spk_pos += goto_pos * 2;
1932 spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1938 static void speakup_goto(struct vc_data *vc)
1940 if (special_handler != NULL) {
1941 synth_printf("%s\n", msg_get(MSG_ERROR));
1944 synth_printf("%s\n", msg_get(MSG_GOTO));
1945 special_handler = handle_goto;
1949 static void speakup_help(struct vc_data *vc)
1951 handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1954 static void do_nothing(struct vc_data *vc)
1956 return; /* flush done in do_spkup */
1959 static u_char key_speakup, spk_key_locked;
1961 static void speakup_lock(struct vc_data *vc)
1963 if (!spk_key_locked)
1964 spk_key_locked = key_speakup = 16;
1966 spk_key_locked = key_speakup = 0;
1969 typedef void (*spkup_hand) (struct vc_data *);
1970 spkup_hand spkup_handler[] = {
1971 /* must be ordered same as defines in speakup.h */
1972 do_nothing, speakup_goto, speech_kill, speakup_shut_up,
1973 speakup_cut, speakup_paste, say_first_char, say_last_char,
1974 say_char, say_prev_char, say_next_char,
1975 say_word, say_prev_word, say_next_word,
1976 say_line, say_prev_line, say_next_line,
1977 top_edge, bottom_edge, left_edge, right_edge,
1978 spell_word, spell_word, say_screen,
1979 say_position, say_attributes,
1980 speakup_off, speakup_parked, say_line, /* this is for indent */
1981 say_from_top, say_to_bottom,
1982 say_from_left, say_to_right,
1983 say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
1984 speakup_bits, speakup_bits, speakup_bits,
1985 speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
1986 speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
1989 static void do_spkup(struct vc_data *vc, u_char value)
1991 if (spk_killed && value != SPEECH_KILL)
1995 spk_shut_up &= 0xfe;
1996 this_speakup_key = value;
1997 if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
1999 (*spkup_handler[value]) (vc);
2001 if (inc_dec_var(value) < 0)
2006 static const char *pad_chars = "0123456789+-*/\015,.?()";
2009 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2012 unsigned long flags;
2015 u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2016 u_char shift_info, offset;
2026 && (vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK))) {
2031 value = spk_lastkey = pad_chars[value];
2036 if (keycode >= MAX_KEY)
2038 key_info = our_keys[keycode];
2041 /* Check valid read all mode keys */
2042 if ((cursor_track == read_all_mode) && (!up_flag)) {
2056 shift_info = (shift_state & 0x0f) + key_speakup;
2057 offset = shift_table[shift_info];
2059 new_key = key_info[offset];
2062 if (new_key == SPK_KEY) {
2063 if (!spk_key_locked)
2064 key_speakup = (up_flag) ? 0 : 16;
2065 if (up_flag || spk_killed)
2067 spk_shut_up &= 0xfe;
2073 if (last_keycode == keycode &&
2074 last_spk_jiffy + MAX_DELAY > jiffies) {
2075 spk_close_press = 1;
2076 offset = shift_table[shift_info + 32];
2078 if (offset && key_info[offset])
2079 new_key = key_info[offset];
2081 last_keycode = keycode;
2082 last_spk_jiffy = jiffies;
2088 if (type == KT_SPKUP && special_handler == NULL) {
2089 do_spkup(vc, new_key);
2090 spk_close_press = 0;
2094 if (up_flag || spk_killed || type == KT_SHIFT)
2096 spk_shut_up &= 0xfe;
2097 kh = (value == KVAL(K_DOWN))
2098 || (value == KVAL(K_UP))
2099 || (value == KVAL(K_LEFT))
2100 || (value == KVAL(K_RIGHT));
2101 if ((cursor_track != read_all_mode) || !kh)
2104 if (special_handler) {
2105 if (type == KT_SPEC && value == 1) {
2108 } else if (type == KT_LETTER)
2110 else if (value == 0x7f)
2111 value = 8; /* make del = backspace */
2112 ret = (*special_handler) (vc, type, value, keycode);
2113 spk_close_press = 0;
2124 static int keyboard_notifier_call(struct notifier_block *nb,
2125 unsigned long code, void *_param)
2127 struct keyboard_notifier_param *param = _param;
2128 struct vc_data *vc = param->vc;
2129 int up = !param->down;
2130 int ret = NOTIFY_OK;
2131 static int keycode; /* to hold the current keycode */
2133 if (vc->vc_mode == KD_GRAPHICS)
2137 * First, determine whether we are handling a fake keypress on
2138 * the current processor. If we are, then return NOTIFY_OK,
2139 * to pass the keystroke up the chain. This prevents us from
2140 * trying to take the Speakup lock while it is held by the
2141 * processor on which the simulated keystroke was generated.
2142 * Also, the simulated keystrokes should be ignored by Speakup.
2145 if (speakup_fake_key_pressed())
2150 /* speakup requires keycode and keysym currently */
2151 keycode = param->value;
2153 case KBD_UNBOUND_KEYCODE:
2160 if (speakup_key(vc, param->shift, keycode, param->value, up))
2162 else if (KTYP(param->value) == KT_CUR)
2163 ret = pre_handle_cursor(vc, KVAL(param->value), up);
2165 case KBD_POST_KEYSYM:{
2166 unsigned char type = KTYP(param->value) - 0xf0;
2167 unsigned char val = KVAL(param->value);
2170 do_handle_shift(vc, val, up);
2174 do_handle_latin(vc, val, up);
2177 do_handle_cursor(vc, val, up);
2180 do_handle_spec(vc, val, up);
2189 static int vt_notifier_call(struct notifier_block *nb,
2190 unsigned long code, void *_param)
2192 struct vt_notifier_param *param = _param;
2193 struct vc_data *vc = param->vc;
2196 if (vc->vc_mode == KD_TEXT)
2197 speakup_allocate(vc);
2200 speakup_deallocate(vc);
2203 if (param->c == '\b')
2205 else if (param->c < 0x100) {
2207 speakup_con_write(vc, &d, 1);
2211 speakup_con_update(vc);
2217 /* called by: module_exit() */
2218 static void __exit speakup_exit(void)
2222 unregister_keyboard_notifier(&keyboard_notifier_block);
2223 unregister_vt_notifier(&vt_notifier_block);
2224 speakup_unregister_devsynth();
2225 del_timer(&cursor_timer);
2226 kthread_stop(speakup_task);
2227 speakup_task = NULL;
2228 mutex_lock(&spk_mutex);
2230 mutex_unlock(&spk_mutex);
2232 speakup_kobj_exit();
2234 for (i = 0; i < MAX_NR_CONSOLES; i++)
2235 kfree(speakup_console[i]);
2237 speakup_remove_virtual_keyboard();
2239 for (i = 0; i < MAXVARS; i++)
2240 speakup_unregister_var(i);
2242 for (i = 0; i < 256; i++) {
2243 if (characters[i] != default_chars[i])
2244 kfree(characters[i]);
2250 /* call by: module_init() */
2251 static int __init speakup_init(void)
2255 struct st_spk_t *first_console;
2256 struct vc_data *vc = vc_cons[fg_console].d;
2259 /* These first few initializations cannot fail. */
2260 initialize_msgs(); /* Initialize arrays for i18n. */
2261 reset_default_chars();
2262 reset_default_chartab();
2264 spk_vars[0].u.n.high = vc->vc_cols;
2265 for (var = spk_vars; var->var_id != MAXVARS; var++)
2266 speakup_register_var(var);
2267 for (var = synth_time_vars;
2268 (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2269 speakup_register_var(var);
2270 for (i = 1; punc_info[i].mask != 0; i++)
2271 set_mask_bits(0, i, 2);
2273 set_key_info(key_defaults, key_buf);
2275 spk_shut_up |= 0x01;
2277 /* From here on out, initializations can fail. */
2278 err = speakup_add_virtual_keyboard();
2280 goto error_virtkeyboard;
2282 first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2283 if (!first_console) {
2288 speakup_console[vc->vc_num] = first_console;
2291 for (i = 0; i < MAX_NR_CONSOLES; i++)
2293 err = speakup_allocate(vc_cons[i].d);
2295 goto error_kobjects;
2298 err = speakup_kobj_init();
2300 goto error_kobjects;
2302 synth_init(synth_name);
2303 speakup_register_devsynth();
2305 * register_devsynth might fail, but this error is not fatal.
2306 * /dev/synth is an extra feature; the rest of Speakup
2307 * will work fine without it.
2310 err = register_keyboard_notifier(&keyboard_notifier_block);
2312 goto error_kbdnotifier;
2313 err = register_vt_notifier(&vt_notifier_block);
2315 goto error_vtnotifier;
2317 speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2319 if (IS_ERR(speakup_task)) {
2320 err = PTR_ERR(speakup_task);
2324 set_user_nice(speakup_task, 10);
2325 wake_up_process(speakup_task);
2327 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2328 pr_info("synth name on entry is: %s\n", synth_name);
2332 unregister_vt_notifier(&vt_notifier_block);
2335 unregister_keyboard_notifier(&keyboard_notifier_block);
2336 del_timer(&cursor_timer);
2339 speakup_unregister_devsynth();
2340 mutex_lock(&spk_mutex);
2342 mutex_unlock(&spk_mutex);
2343 speakup_kobj_exit();
2346 for (i = 0; i < MAX_NR_CONSOLES; i++)
2347 kfree(speakup_console[i]);
2350 speakup_remove_virtual_keyboard();
2353 for (i = 0; i < MAXVARS; i++)
2354 speakup_unregister_var(i);
2356 for (i = 0; i < 256; i++) {
2357 if (characters[i] != default_chars[i])
2358 kfree(characters[i]);
2367 module_init(speakup_init);
2368 module_exit(speakup_exit);