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>
27 #include <linux/tty.h>
28 #include <linux/mm.h> /* __get_free_page() and friends */
29 #include <linux/vt_kern.h>
30 #include <linux/ctype.h>
31 #include <linux/selection.h>
32 #include <linux/unistd.h>
33 #include <linux/jiffies.h>
34 #include <linux/kthread.h>
35 #include <linux/keyboard.h> /* for KT_SHIFT */
36 #include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
37 #include <linux/input.h>
38 #include <linux/kmod.h>
40 /* speakup_*_selection */
41 #include <linux/module.h>
42 #include <linux/sched.h>
43 #include <linux/slab.h>
44 #include <linux/types.h>
45 #include <linux/consolemap.h>
47 #include <linux/spinlock.h>
48 #include <linux/notifier.h>
50 #include <linux/uaccess.h> /* copy_from|to|user() and others */
55 #define MAX_DELAY msecs_to_jiffies(500)
56 #define MINECHOCHAR SPACE
58 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
59 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
60 MODULE_DESCRIPTION("Speakup console speech");
61 MODULE_LICENSE("GPL");
62 MODULE_VERSION(SPEAKUP_VERSION);
65 module_param_named(synth, synth_name, charp, S_IRUGO);
66 module_param_named(quiet, spk_quiet_boot, bool, S_IRUGO);
68 MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
69 MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
71 special_func spk_special_handler;
73 short spk_pitch_shift, synth_flags;
75 int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
76 int spk_no_intr, spk_spell_delay;
77 int spk_key_echo, spk_say_word_ctl;
78 int spk_say_ctrl, spk_bell_pos;
80 int spk_punc_level, spk_reading_punc;
81 char spk_str_caps_start[MAXVARLEN + 1] = "\0";
82 char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
83 const struct st_bits_data spk_punc_info[] = {
85 {"some", "/$%&@", SOME},
86 {"most", "$%&#()=+*/@^<>|\\", MOST},
87 {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
88 {"delimiters", "", B_WDLM},
89 {"repeats", "()", CH_RPT},
90 {"extended numeric", "", B_EXNUM},
91 {"symbols", "", B_SYM},
95 static char mark_cut_flag;
97 static u_char *spk_shift_table;
98 u_char *spk_our_keys[MAX_KEY];
99 u_char spk_key_buf[600];
100 const u_char spk_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);
121 static char *phonetic[] = {
122 "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
123 "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
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 *spk_characters[256];
134 char *spk_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",
140 /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
142 /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
145 /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
147 /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
148 /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
149 /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
150 /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
151 /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
154 /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
155 /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
156 /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
157 /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
158 /*127*/ "del", "control", "control", "control", "control", "control",
159 "control", "control", "control", "control", "control",
160 /*138*/ "control", "control", "control", "control", "control",
161 "control", "control", "control", "control", "control",
162 "control", "control",
163 /*150*/ "control", "control", "control", "control", "control",
164 "control", "control", "control", "control", "control",
165 /*160*/ "nbsp", "inverted bang",
166 /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
167 /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
168 /*172*/ "not", "soft hyphen", "registered", "macron",
169 /*176*/ "degrees", "plus or minus", "super two", "super three",
170 /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
171 /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
172 /*188*/ "one quarter", "one half", "three quarters",
174 /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
176 /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
178 /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
180 /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
181 /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
183 /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
184 /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
185 /*230*/ "ae", "c cidella", "e grave", "e acute",
186 /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
188 /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
190 /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
192 /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
195 /* array of 256 u_short (one for each character)
196 * initialized to default_chartab and user selectable via
197 * /sys/module/speakup/parameters/chartab */
198 u_short spk_chartab[256];
200 static u_short default_chartab[256] = {
201 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
202 B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
203 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
204 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
205 WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */
206 PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */
207 NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
208 NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */
209 PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */
210 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
211 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
212 A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */
213 PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */
214 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
215 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
216 ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
217 B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
219 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
221 B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
223 B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
225 WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
227 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
228 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
229 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
230 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
231 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
232 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
233 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
234 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
235 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
236 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
237 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */
240 struct task_struct *speakup_task;
241 struct bleep spk_unprocessed_sound;
242 static int spk_keydown;
243 static u_char spk_lastkey, spk_close_press, keymap_flags;
244 static u_char last_keycode, this_speakup_key;
245 static u_long last_spk_jiffy;
247 struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
249 DEFINE_MUTEX(spk_mutex);
251 static int keyboard_notifier_call(struct notifier_block *,
252 unsigned long code, void *param);
254 static struct notifier_block keyboard_notifier_block = {
255 .notifier_call = keyboard_notifier_call,
258 static int vt_notifier_call(struct notifier_block *,
259 unsigned long code, void *param);
261 static struct notifier_block vt_notifier_block = {
262 .notifier_call = vt_notifier_call,
265 static unsigned char get_attributes(u16 *pos)
267 return (u_char) (scr_readw(pos) >> 8);
270 static void speakup_date(struct vc_data *vc)
272 spk_x = spk_cx = vc->vc_x;
273 spk_y = spk_cy = vc->vc_y;
274 spk_pos = spk_cp = vc->vc_pos;
275 spk_old_attr = spk_attr;
276 spk_attr = get_attributes((u_short *) spk_pos);
279 static void bleep(u_short val)
281 static const short vals[] = {
282 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
285 int time = spk_bleep_time;
287 freq = vals[val % 12];
289 freq *= (1 << (val / 12));
290 spk_unprocessed_sound.freq = freq;
291 spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
292 spk_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);
314 /* re-enables synth, if disabled */
315 if (val == 2 || spk_killed) {
317 spk_shut_up &= ~0x40;
318 synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
320 synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
325 static void speakup_off(struct vc_data *vc)
327 if (spk_shut_up & 0x80) {
329 synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
332 synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
337 static void speakup_parked(struct vc_data *vc)
339 if (spk_parked & 0x80) {
341 synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
344 synth_printf("%s\n", spk_msg_get(MSG_PARKED));
348 static void speakup_cut(struct vc_data *vc)
350 static const char err_buf[] = "set selection failed";
353 if (!mark_cut_flag) {
355 spk_xs = (u_short) spk_x;
356 spk_ys = (u_short) spk_y;
358 synth_printf("%s\n", spk_msg_get(MSG_MARK));
361 spk_xe = (u_short) spk_x;
362 spk_ye = (u_short) spk_y;
364 synth_printf("%s\n", spk_msg_get(MSG_CUT));
366 speakup_clear_selection();
367 ret = speakup_set_selection(tty);
371 break; /* no error */
373 pr_warn("%sEFAULT\n", err_buf);
376 pr_warn("%sEINVAL\n", err_buf);
379 pr_warn("%sENOMEM\n", err_buf);
384 static void speakup_paste(struct vc_data *vc)
388 synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
390 synth_printf("%s\n", spk_msg_get(MSG_PASTE));
391 speakup_paste_selection(tty);
395 static void say_attributes(struct vc_data *vc)
397 int fg = spk_attr & 0x0f;
398 int bg = spk_attr >> 4;
401 synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
404 synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
406 synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
409 synth_printf(" %s ", spk_msg_get(MSG_ON));
410 synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
421 static void announce_edge(struct vc_data *vc, int msg_id)
425 if ((spk_bleeps & 2) && (msg_id < edge_quiet))
426 synth_printf("%s\n", spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
429 static void speak_char(u_char ch)
431 char *cp = spk_characters[ch];
432 struct var_t *direct = spk_get_var(DIRECT);
434 if (direct && direct->u.n.value) {
435 if (IS_CHAR(ch, B_CAP)) {
437 synth_printf("%s", spk_str_caps_start);
439 synth_printf("%c", ch);
440 if (IS_CHAR(ch, B_CAP))
441 synth_printf("%s", spk_str_caps_stop);
445 pr_info("speak_char: cp == NULL!\n");
448 synth_buffer_add(SPACE);
449 if (IS_CHAR(ch, B_CAP)) {
451 synth_printf("%s", spk_str_caps_start);
452 synth_printf("%s", cp);
453 synth_printf("%s", spk_str_caps_stop);
456 synth_printf("%s", spk_msg_get(MSG_CTRL));
459 synth_printf("%s", cp);
461 synth_buffer_add(SPACE);
464 static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
469 u16 w = scr_readw(pos);
472 if (w & vc->vc_hi_font_mask)
475 ch = inverse_translate(vc, c, 0);
476 *attribs = (w & 0xff00) >> 8;
481 static void say_char(struct vc_data *vc)
485 spk_old_attr = spk_attr;
486 ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
487 if (spk_attr != spk_old_attr) {
488 if (spk_attrib_bleep & 1)
490 if (spk_attrib_bleep & 2)
493 speak_char(ch & 0xff);
496 static void say_phonetic_char(struct vc_data *vc)
500 spk_old_attr = spk_attr;
501 ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
502 if (isascii(ch) && isalpha(ch)) {
504 synth_printf("%s\n", phonetic[--ch]);
506 if (IS_CHAR(ch, B_NUM))
507 synth_printf("%s ", spk_msg_get(MSG_NUMBER));
512 static void say_prev_char(struct vc_data *vc)
516 announce_edge(vc, edge_left);
524 static void say_next_char(struct vc_data *vc)
527 if (spk_x == vc->vc_cols - 1) {
528 announce_edge(vc, edge_right);
536 /* get_word - will first check to see if the character under the
537 * reading cursor is a space and if spk_say_word_ctl is true it will
538 * return the word space. If spk_say_word_ctl is not set it will check to
539 * see if there is a word starting on the next position to the right
540 * and return that word if it exists. If it does not exist it will
541 * move left to the beginning of any previous word on the line or the
542 * beginning off the line whichever comes first.. */
544 static u_long get_word(struct vc_data *vc)
546 u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
551 spk_old_attr = spk_attr;
552 ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
554 /* decided to take out the sayword if on a space (mis-information */
555 if (spk_say_word_ctl && ch == SPACE) {
557 synth_printf("%s\n", spk_msg_get(MSG_SPACE));
559 } else if ((tmpx < vc->vc_cols - 2)
560 && (ch == SPACE || ch == 0 || IS_WDLM(ch))
561 && ((char)get_char(vc, (u_short *) &tmp_pos + 1, &temp) >
567 ch = (char)get_char(vc, (u_short *) tmp_pos - 1, &temp);
568 if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
569 && ((char)get_char(vc, (u_short *) tmp_pos, &temp) >
575 attr_ch = get_char(vc, (u_short *) tmp_pos, &spk_attr);
576 buf[cnt++] = attr_ch & 0xff;
577 while (tmpx < vc->vc_cols - 1) {
580 ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
581 if ((ch == SPACE) || ch == 0
582 || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
590 static void say_word(struct vc_data *vc)
592 u_long cnt = get_word(vc);
593 u_short saved_punc_mask = spk_punc_mask;
597 spk_punc_mask = PUNC;
599 spkup_write(buf, cnt);
600 spk_punc_mask = saved_punc_mask;
603 static void say_prev_word(struct vc_data *vc)
607 u_short edge_said = 0, last_state = 0, state = 0;
613 announce_edge(vc, edge_top);
618 edge_said = edge_quiet;
623 edge_said = edge_top;
626 if (edge_said != edge_quiet)
627 edge_said = edge_left;
631 spk_x = vc->vc_cols - 1;
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) {
649 if (spk_x == 0 && edge_said == edge_quiet)
650 edge_said = edge_left;
651 if (edge_said > 0 && edge_said < edge_quiet)
652 announce_edge(vc, edge_said);
656 static void say_next_word(struct vc_data *vc)
660 u_short edge_said = 0, last_state = 2, state = 0;
663 if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
664 announce_edge(vc, edge_bottom);
668 ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
669 if (ch == SPACE || ch == 0)
671 else if (IS_WDLM(ch))
675 if (state > last_state)
677 if (spk_x >= vc->vc_cols - 1) {
678 if (spk_y == vc->vc_rows - 1) {
679 edge_said = edge_bottom;
685 edge_said = edge_right;
692 announce_edge(vc, edge_said);
696 static void spell_word(struct vc_data *vc)
698 static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
699 char *cp = buf, *str_cap = spk_str_caps_stop;
700 char *cp1, *last_cap = spk_str_caps_stop;
705 while ((ch = (u_char) *cp)) {
707 synth_printf(" %s ", delay_str[spk_spell_delay]);
708 if (IS_CHAR(ch, B_CAP)) {
709 str_cap = spk_str_caps_start;
710 if (*spk_str_caps_stop)
712 else /* synth has no pitch */
713 last_cap = spk_str_caps_stop;
715 str_cap = spk_str_caps_stop;
716 if (str_cap != last_cap) {
717 synth_printf("%s", str_cap);
720 if (this_speakup_key == SPELL_PHONETIC
721 && (isascii(ch) && isalpha(ch))) {
723 cp1 = phonetic[--ch];
725 cp1 = spk_characters[ch];
727 synth_printf("%s", spk_msg_get(MSG_CTRL));
731 synth_printf("%s", cp1);
734 if (str_cap != spk_str_caps_stop)
735 synth_printf("%s", spk_str_caps_stop);
738 static int get_line(struct vc_data *vc)
740 u_long tmp = spk_pos - (spk_x * 2);
744 spk_old_attr = spk_attr;
745 spk_attr = get_attributes((u_short *) spk_pos);
746 for (i = 0; i < vc->vc_cols; i++) {
747 buf[i] = (u_char) get_char(vc, (u_short *) tmp, &tmp2);
750 for (--i; i >= 0; i--)
756 static void say_line(struct vc_data *vc)
758 int i = get_line(vc);
760 u_short saved_punc_mask = spk_punc_mask;
763 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
767 if (this_speakup_key == SAY_LINE_INDENT) {
771 synth_printf("%d, ", (cp - buf) + 1);
773 spk_punc_mask = spk_punc_masks[spk_reading_punc];
775 spk_punc_mask = saved_punc_mask;
778 static void say_prev_line(struct vc_data *vc)
782 announce_edge(vc, edge_top);
786 spk_pos -= vc->vc_size_row;
790 static void say_next_line(struct vc_data *vc)
793 if (spk_y == vc->vc_rows - 1) {
794 announce_edge(vc, edge_bottom);
798 spk_pos += vc->vc_size_row;
802 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
807 u_short saved_punc_mask = spk_punc_mask;
809 spk_old_attr = spk_attr;
810 spk_attr = get_attributes((u_short *) from);
812 buf[i++] = (char)get_char(vc, (u_short *) from, &tmp);
814 if (i >= vc->vc_size_row)
817 for (--i; i >= 0; i--)
825 spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
828 spk_punc_mask = saved_punc_mask;
832 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
835 u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
836 u_long end = start + (to * 2);
839 if (say_from_to(vc, start, end, read_punc) <= 0)
840 if (cursor_track != read_all_mode)
841 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
844 /* Sentence Reading Commands */
846 static int currsentence;
847 static int numsentences[2];
848 static char *sentbufend[2];
849 static char *sentmarks[2][10];
852 static char sentbuf[2][256];
854 static int say_sentence_num(int num, int prev)
857 currsentence = num + 1;
858 if (prev && --bn == -1)
861 if (num > numsentences[bn])
864 spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
868 static int get_sentence_buf(struct vc_data *vc, int read_punc)
878 start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
879 end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
881 numsentences[bn] = 0;
882 sentmarks[bn][0] = &sentbuf[bn][0];
884 spk_old_attr = spk_attr;
885 spk_attr = get_attributes((u_short *) start);
887 while (start < end) {
888 sentbuf[bn][i] = (char)get_char(vc, (u_short *) start, &tmp);
890 if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
891 && numsentences[bn] < 9) {
892 /* Sentence Marker */
894 sentmarks[bn][numsentences[bn]] =
900 if (i >= vc->vc_size_row)
904 for (--i; i >= 0; i--)
905 if (sentbuf[bn][i] != SPACE)
911 sentbuf[bn][++i] = SPACE;
912 sentbuf[bn][++i] = '\0';
914 sentbufend[bn] = &sentbuf[bn][i];
915 return numsentences[bn];
918 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
920 u_long start = vc->vc_origin, end;
923 start += from * vc->vc_size_row;
924 if (to > vc->vc_rows)
926 end = vc->vc_origin + (to * vc->vc_size_row);
927 for (from = start; from < end; from = to) {
928 to = from + vc->vc_size_row;
929 say_from_to(vc, from, to, 1);
933 static void say_screen(struct vc_data *vc)
935 say_screen_from_to(vc, 0, vc->vc_rows);
938 static void speakup_win_say(struct vc_data *vc)
940 u_long start, end, from, to;
943 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
946 start = vc->vc_origin + (win_top * vc->vc_size_row);
947 end = vc->vc_origin + (win_bottom * vc->vc_size_row);
948 while (start <= end) {
949 from = start + (win_left * 2);
950 to = start + (win_right * 2);
951 say_from_to(vc, from, to, 1);
952 start += vc->vc_size_row;
956 static void top_edge(struct vc_data *vc)
959 spk_pos = vc->vc_origin + 2 * spk_x;
964 static void bottom_edge(struct vc_data *vc)
967 spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
968 spk_y = vc->vc_rows - 1;
972 static void left_edge(struct vc_data *vc)
975 spk_pos -= spk_x * 2;
980 static void right_edge(struct vc_data *vc)
983 spk_pos += (vc->vc_cols - spk_x - 1) * 2;
984 spk_x = vc->vc_cols - 1;
988 static void say_first_char(struct vc_data *vc)
990 int i, len = get_line(vc);
995 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
998 for (i = 0; i < len; i++)
1002 spk_pos -= (spk_x - i) * 2;
1004 synth_printf("%d, ", ++i);
1008 static void say_last_char(struct vc_data *vc)
1010 int len = get_line(vc);
1015 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1019 spk_pos -= (spk_x - len) * 2;
1021 synth_printf("%d, ", ++len);
1025 static void say_position(struct vc_data *vc)
1027 synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1032 /* Added by brianb */
1033 static void say_char_num(struct vc_data *vc)
1036 u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
1039 synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1042 /* these are stub functions to keep keyboard.c happy. */
1044 static void say_from_top(struct vc_data *vc)
1046 say_screen_from_to(vc, 0, spk_y);
1049 static void say_to_bottom(struct vc_data *vc)
1051 say_screen_from_to(vc, spk_y, vc->vc_rows);
1054 static void say_from_left(struct vc_data *vc)
1056 say_line_from_to(vc, 0, spk_x, 1);
1059 static void say_to_right(struct vc_data *vc)
1061 say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1064 /* end of stub functions. */
1066 static void spkup_write(const char *in_buf, int count)
1068 static int rep_count;
1069 static u_char ch = '\0', old_ch = '\0';
1070 static u_short char_type, last_type;
1071 int in_count = count;
1075 if (cursor_track == read_all_mode) {
1076 /* Insert Sentence Index */
1077 if ((in_buf == sentmarks[bn][currsentence]) &&
1078 (currsentence <= numsentences[bn]))
1079 synth_insert_next_index(currsentence++);
1081 ch = (u_char) *in_buf++;
1082 char_type = spk_chartab[ch];
1083 if (ch == old_ch && !(char_type & B_NUM)) {
1084 if (++rep_count > 2)
1087 if ((last_type & CH_RPT) && rep_count > 2) {
1089 synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1095 if (ch == spk_lastkey) {
1097 if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1099 } else if (char_type & B_ALPHA) {
1100 if ((synth_flags & SF_DEC) && (last_type & PUNC))
1101 synth_buffer_add(SPACE);
1102 synth_printf("%c", ch);
1103 } else if (char_type & B_NUM) {
1105 synth_printf("%c", ch);
1106 } else if (char_type & spk_punc_mask) {
1108 char_type &= ~PUNC; /* for dec nospell processing */
1109 } else if (char_type & SYNTH_OK) {
1110 /* these are usually puncts like . and , which synth
1111 * needs for expression.
1112 * suppress multiple to get rid of long pauses and
1113 * clear repeat count
1115 * repeats on you don't get nothing repeated count */
1117 synth_printf("%c", ch);
1121 /* send space and record position, if next is num overwrite space */
1123 synth_buffer_add(SPACE);
1128 last_type = char_type;
1131 if (in_count > 2 && rep_count > 2) {
1132 if (last_type & CH_RPT) {
1134 synth_printf(spk_msg_get(MSG_REPEAT_DESC2), ++rep_count);
1141 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1143 static void read_all_doc(struct vc_data *vc);
1144 static void cursor_done(u_long data);
1145 static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1147 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1149 unsigned long flags;
1151 if (synth == NULL || up_flag || spk_killed)
1153 spin_lock_irqsave(&speakup_info.spinlock, flags);
1154 if (cursor_track == read_all_mode) {
1157 del_timer(&cursor_timer);
1158 spk_shut_up &= 0xfe;
1163 del_timer(&cursor_timer);
1164 cursor_track = prev_cursor_track;
1165 spk_shut_up &= 0xfe;
1170 spk_shut_up &= 0xfe;
1173 if (spk_say_ctrl && value < NUM_CTL_LABELS)
1174 synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1175 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1178 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1180 unsigned long flags;
1182 spin_lock_irqsave(&speakup_info.spinlock, flags);
1184 spk_lastkey = spk_keydown = 0;
1185 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1188 if (synth == NULL || spk_killed) {
1189 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1192 spk_shut_up &= 0xfe;
1193 spk_lastkey = value;
1196 if (spk_key_echo == 2 && value >= MINECHOCHAR)
1198 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1201 int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1203 int i = 0, states, key_data_len;
1204 const u_char *cp = key_info;
1205 u_char *cp1 = k_buffer;
1206 u_char ch, version, num_keys;
1209 if (version != KEY_MAP_VER)
1212 states = (int)cp[1];
1213 key_data_len = (states + 1) * (num_keys + 1);
1214 if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf))
1216 memset(k_buffer, 0, SHIFT_TBL_SIZE);
1217 memset(spk_our_keys, 0, sizeof(spk_our_keys));
1218 spk_shift_table = k_buffer;
1219 spk_our_keys[0] = spk_shift_table;
1220 cp1 += SHIFT_TBL_SIZE;
1221 memcpy(cp1, cp, key_data_len + 3);
1222 /* get num_keys, states and data */
1223 cp1 += 2; /* now pointing at shift states */
1224 for (i = 1; i <= states; i++) {
1226 if (ch >= SHIFT_TBL_SIZE)
1228 spk_shift_table[ch] = i;
1230 keymap_flags = *cp1++;
1231 while ((ch = *cp1)) {
1234 spk_our_keys[ch] = cp1;
1240 static struct var_t spk_vars[] = {
1241 /* bell must be first to set high limit */
1242 {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1243 {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1244 {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1245 {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1246 {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1247 {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1248 {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1249 {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1250 {SAY_CONTROL, TOGGLE_0},
1251 {SAY_WORD_CTL, TOGGLE_0},
1252 {NO_INTERRUPT, TOGGLE_0},
1253 {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1257 static void toggle_cursoring(struct vc_data *vc)
1259 if (cursor_track == read_all_mode)
1260 cursor_track = prev_cursor_track;
1261 if (++cursor_track >= CT_Max)
1263 synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1266 void spk_reset_default_chars(void)
1270 /* First, free any non-default */
1271 for (i = 0; i < 256; i++) {
1272 if ((spk_characters[i] != NULL)
1273 && (spk_characters[i] != spk_default_chars[i]))
1274 kfree(spk_characters[i]);
1277 memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1280 void spk_reset_default_chartab(void)
1282 memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1285 static const struct st_bits_data *pb_edit;
1287 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1289 short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1291 if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1294 synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1295 spk_special_handler = NULL;
1298 if (mask < PUNC && !(ch_type & PUNC))
1300 spk_chartab[ch] ^= mask;
1302 synth_printf(" %s\n",
1303 (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1304 spk_msg_get(MSG_OFF));
1308 /* Allocation concurrency is protected by the console semaphore */
1309 static int speakup_allocate(struct vc_data *vc)
1313 vc_num = vc->vc_num;
1314 if (speakup_console[vc_num] == NULL) {
1315 speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1317 if (speakup_console[vc_num] == NULL)
1320 } else if (!spk_parked)
1326 static void speakup_deallocate(struct vc_data *vc)
1330 vc_num = vc->vc_num;
1331 kfree(speakup_console[vc_num]);
1332 speakup_console[vc_num] = NULL;
1335 static u_char is_cursor;
1336 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1337 static int cursor_con;
1339 static void reset_highlight_buffers(struct vc_data *);
1341 static int read_all_key;
1343 static void start_read_all_timer(struct vc_data *vc, int command);
1357 static void kbd_fakekey2(struct vc_data *vc, int command)
1359 del_timer(&cursor_timer);
1360 speakup_fake_down_arrow();
1361 start_read_all_timer(vc, command);
1364 static void read_all_doc(struct vc_data *vc)
1366 if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1368 if (!synth_supports_indexing())
1370 if (cursor_track != read_all_mode)
1371 prev_cursor_track = cursor_track;
1372 cursor_track = read_all_mode;
1373 spk_reset_index_count(0);
1374 if (get_sentence_buf(vc, 0) == -1)
1375 kbd_fakekey2(vc, RA_DOWN_ARROW);
1377 say_sentence_num(0, 0);
1378 synth_insert_next_index(0);
1379 start_read_all_timer(vc, RA_TIMER);
1383 static void stop_read_all(struct vc_data *vc)
1385 del_timer(&cursor_timer);
1386 cursor_track = prev_cursor_track;
1387 spk_shut_up &= 0xfe;
1391 static void start_read_all_timer(struct vc_data *vc, int command)
1393 struct var_t *cursor_timeout;
1395 cursor_con = vc->vc_num;
1396 read_all_key = command;
1397 cursor_timeout = spk_get_var(CURSOR_TIME);
1398 mod_timer(&cursor_timer,
1399 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1402 static void handle_cursor_read_all(struct vc_data *vc, int command)
1404 int indcount, sentcount, rv, sn;
1408 /* Get Current Sentence */
1409 spk_get_index_count(&indcount, &sentcount);
1410 /*printk("%d %d ", indcount, sentcount); */
1411 spk_reset_index_count(sentcount + 1);
1412 if (indcount == 1) {
1413 if (!say_sentence_num(sentcount + 1, 0)) {
1414 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1417 synth_insert_next_index(0);
1420 if (!say_sentence_num(sentcount + 1, 1)) {
1422 spk_reset_index_count(sn);
1424 synth_insert_next_index(0);
1425 if (!say_sentence_num(sn, 0)) {
1426 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1429 synth_insert_next_index(0);
1431 start_read_all_timer(vc, RA_TIMER);
1441 if (get_sentence_buf(vc, 0) == -1) {
1442 kbd_fakekey2(vc, RA_DOWN_ARROW);
1444 say_sentence_num(0, 0);
1445 synth_insert_next_index(0);
1446 start_read_all_timer(vc, RA_TIMER);
1449 case RA_FIND_NEXT_SENT:
1450 rv = get_sentence_buf(vc, 0);
1454 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1456 say_sentence_num(1, 0);
1457 synth_insert_next_index(0);
1458 start_read_all_timer(vc, RA_TIMER);
1461 case RA_FIND_PREV_SENT:
1464 spk_get_index_count(&indcount, &sentcount);
1466 kbd_fakekey2(vc, RA_DOWN_ARROW);
1468 start_read_all_timer(vc, RA_TIMER);
1473 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1475 unsigned long flags;
1477 spin_lock_irqsave(&speakup_info.spinlock, flags);
1478 if (cursor_track == read_all_mode) {
1480 if (synth == NULL || up_flag || spk_shut_up) {
1481 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1484 del_timer(&cursor_timer);
1485 spk_shut_up &= 0xfe;
1487 start_read_all_timer(vc, value + 1);
1488 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1491 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1495 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1497 unsigned long flags;
1498 struct var_t *cursor_timeout;
1500 spin_lock_irqsave(&speakup_info.spinlock, flags);
1502 if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1503 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1506 spk_shut_up &= 0xfe;
1509 /* the key press flushes if !no_inter but we want to flush on cursor
1510 * moves regardless of no_inter state */
1511 is_cursor = value + 1;
1512 old_cursor_pos = vc->vc_pos;
1513 old_cursor_x = vc->vc_x;
1514 old_cursor_y = vc->vc_y;
1515 speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1516 cursor_con = vc->vc_num;
1517 if (cursor_track == CT_Highlight)
1518 reset_highlight_buffers(vc);
1519 cursor_timeout = spk_get_var(CURSOR_TIME);
1520 mod_timer(&cursor_timer,
1521 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1522 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1525 static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
1528 int vc_num = vc->vc_num;
1530 bi = ((vc->vc_attr & 0x70) >> 4);
1531 hi = speakup_console[vc_num]->ht.highsize[bi];
1534 if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1535 speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1536 speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1537 speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1539 while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1540 if ((ic[i] > 32) && (ic[i] < 127)) {
1541 speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1543 } else if ((ic[i] == 32) && (hi != 0)) {
1544 if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1546 speakup_console[vc_num]->ht.highbuf[bi][hi] =
1553 speakup_console[vc_num]->ht.highsize[bi] = hi;
1556 static void reset_highlight_buffers(struct vc_data *vc)
1559 int vc_num = vc->vc_num;
1561 for (i = 0; i < 8; i++)
1562 speakup_console[vc_num]->ht.highsize[i] = 0;
1565 static int count_highlight_color(struct vc_data *vc)
1569 int vc_num = vc->vc_num;
1571 u16 *start = (u16 *) vc->vc_origin;
1573 for (i = 0; i < 8; i++)
1574 speakup_console[vc_num]->ht.bgcount[i] = 0;
1576 for (i = 0; i < vc->vc_rows; i++) {
1577 u16 *end = start + vc->vc_cols * 2;
1580 for (ptr = start; ptr < end; ptr++) {
1581 ch = get_attributes(ptr);
1582 bg = (ch & 0x70) >> 4;
1583 speakup_console[vc_num]->ht.bgcount[bg]++;
1585 start += vc->vc_size_row;
1589 for (i = 0; i < 8; i++)
1590 if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1595 static int get_highlight_color(struct vc_data *vc)
1598 unsigned int cptr[8], tmp;
1599 int vc_num = vc->vc_num;
1601 for (i = 0; i < 8; i++)
1604 for (i = 0; i < 7; i++)
1605 for (j = i + 1; j < 8; j++)
1606 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1607 speakup_console[vc_num]->ht.bgcount[cptr[j]]) {
1613 for (i = 0; i < 8; i++)
1614 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1615 if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1620 static int speak_highlight(struct vc_data *vc)
1623 int vc_num = vc->vc_num;
1625 if (count_highlight_color(vc) == 1)
1627 hc = get_highlight_color(vc);
1629 d = vc->vc_y - speakup_console[vc_num]->ht.cy;
1630 if ((d == 1) || (d == -1))
1631 if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1635 spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1636 speakup_console[vc_num]->ht.highsize[hc]);
1637 spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1638 spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1639 spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1645 static void cursor_done(u_long data)
1647 struct vc_data *vc = vc_cons[cursor_con].d;
1648 unsigned long flags;
1650 del_timer(&cursor_timer);
1651 spin_lock_irqsave(&speakup_info.spinlock, flags);
1652 if (cursor_con != fg_console) {
1658 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1659 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1660 spk_keydown = is_cursor = 0;
1664 if (cursor_track == read_all_mode) {
1665 handle_cursor_read_all(vc, read_all_key);
1668 if (cursor_track == CT_Highlight) {
1669 if (speak_highlight(vc)) {
1670 spk_keydown = is_cursor = 0;
1674 if (cursor_track == CT_Window)
1675 speakup_win_say(vc);
1676 else if (is_cursor == 1 || is_cursor == 4)
1677 say_line_from_to(vc, 0, vc->vc_cols, 0);
1680 spk_keydown = is_cursor = 0;
1682 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1685 /* called by: vt_notifier_call() */
1686 static void speakup_bs(struct vc_data *vc)
1688 unsigned long flags;
1690 if (!speakup_console[vc->vc_num])
1692 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1693 /* Speakup output, discard */
1697 if (spk_shut_up || synth == NULL) {
1698 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1701 if (vc->vc_num == fg_console && spk_keydown) {
1706 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1709 /* called by: vt_notifier_call() */
1710 static void speakup_con_write(struct vc_data *vc, const char *str, int len)
1712 unsigned long flags;
1714 if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1716 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1717 /* Speakup output, discard */
1719 if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
1721 if ((is_cursor) || (cursor_track == read_all_mode)) {
1722 if (cursor_track == CT_Highlight)
1723 update_color_buffer(vc, str, len);
1724 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1728 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1729 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1730 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1735 spkup_write(str, len);
1736 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1739 static void speakup_con_update(struct vc_data *vc)
1741 unsigned long flags;
1743 if (speakup_console[vc->vc_num] == NULL || spk_parked)
1745 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1746 /* Speakup output, discard */
1749 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1752 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1754 unsigned long flags;
1758 if (synth == NULL || up_flag || spk_killed)
1760 spin_lock_irqsave(&speakup_info.spinlock, flags);
1761 spk_shut_up &= 0xfe;
1766 label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1767 on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1770 label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1771 on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1774 label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1775 on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1776 if (speakup_console[vc->vc_num])
1777 speakup_console[vc->vc_num]->tty_stopped = on_off;
1781 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1785 synth_printf("%s %s\n",
1786 label, spk_msg_get(MSG_STATUS_START + on_off));
1787 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1790 static int inc_dec_var(u_char value)
1792 struct st_var_header *p_header;
1793 struct var_t *var_data;
1797 int var_id = (int)value - VAR_START;
1798 int how = (var_id & 1) ? E_INC : E_DEC;
1800 var_id = var_id / 2 + FIRST_SET_VAR;
1801 p_header = spk_get_var_header(var_id);
1802 if (p_header == NULL)
1804 if (p_header->var_type != VAR_NUM)
1806 var_data = p_header->data;
1807 if (spk_set_num_var(1, p_header, how) != 0)
1809 if (!spk_close_press) {
1810 for (pn = p_header->name; *pn; pn++) {
1817 snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1818 var_data->u.n.value);
1819 synth_printf("%s", num_buf);
1823 static void speakup_win_set(struct vc_data *vc)
1827 if (win_start > 1) {
1828 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1831 if (spk_x < win_left || spk_y < win_top) {
1832 synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1835 if (win_start && spk_x == win_left && spk_y == win_top) {
1837 win_right = vc->vc_cols - 1;
1839 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1849 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1850 (win_start) ? spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1851 (int)spk_y + 1, (int)spk_x + 1);
1853 synth_printf("%s\n", info);
1857 static void speakup_win_clear(struct vc_data *vc)
1859 win_top = win_bottom = 0;
1860 win_left = win_right = 0;
1862 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1865 static void speakup_win_enable(struct vc_data *vc)
1867 if (win_start < 2) {
1868 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1873 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1875 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1878 static void speakup_bits(struct vc_data *vc)
1880 int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1882 if (spk_special_handler != NULL || val < 1 || val > 6) {
1883 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1886 pb_edit = &spk_punc_info[val];
1887 synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1888 spk_special_handler = edit_bits;
1891 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1893 static u_char goto_buf[8];
1898 if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1900 if (type == KT_LATIN && ch == '\n')
1907 ch = goto_buf[--num];
1908 goto_buf[num] = '\0';
1909 spkup_write(&ch, 1);
1912 if (ch < '+' || ch > 'y')
1914 goto_buf[num++] = ch;
1915 goto_buf[num] = '\0';
1916 spkup_write(&ch, 1);
1917 maxlen = (*goto_buf >= '0') ? 3 : 4;
1918 if ((ch == '+' || ch == '-') && num == 1)
1920 if (ch >= '0' && ch <= '9' && num < maxlen)
1922 if (num < maxlen - 1 || num > maxlen)
1924 if (ch < 'x' || ch > 'y') {
1927 synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1928 goto_buf[num = 0] = '\0';
1929 spk_special_handler = NULL;
1933 goto_pos = simple_strtoul(goto_buf, &cp, 10);
1936 if (*goto_buf < '0')
1938 else if (goto_pos > 0)
1941 if (goto_pos >= vc->vc_cols)
1942 goto_pos = vc->vc_cols - 1;
1945 if (*goto_buf < '0')
1947 else if (goto_pos > 0)
1950 if (goto_pos >= vc->vc_rows)
1951 goto_pos = vc->vc_rows - 1;
1954 goto_buf[num = 0] = '\0';
1956 spk_special_handler = NULL;
1959 spk_pos -= spk_x * 2;
1961 spk_pos += goto_pos * 2;
1965 spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1971 static void speakup_goto(struct vc_data *vc)
1973 if (spk_special_handler != NULL) {
1974 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1977 synth_printf("%s\n", spk_msg_get(MSG_GOTO));
1978 spk_special_handler = handle_goto;
1981 static void speakup_help(struct vc_data *vc)
1983 spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1986 static void do_nothing(struct vc_data *vc)
1988 return; /* flush done in do_spkup */
1991 static u_char key_speakup, spk_key_locked;
1993 static void speakup_lock(struct vc_data *vc)
1995 if (!spk_key_locked)
1996 spk_key_locked = key_speakup = 16;
1998 spk_key_locked = key_speakup = 0;
2001 typedef void (*spkup_hand) (struct vc_data *);
2002 static spkup_hand spkup_handler[] = {
2003 /* must be ordered same as defines in speakup.h */
2004 do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2005 speakup_cut, speakup_paste, say_first_char, say_last_char,
2006 say_char, say_prev_char, say_next_char,
2007 say_word, say_prev_word, say_next_word,
2008 say_line, say_prev_line, say_next_line,
2009 top_edge, bottom_edge, left_edge, right_edge,
2010 spell_word, spell_word, say_screen,
2011 say_position, say_attributes,
2012 speakup_off, speakup_parked, say_line, /* this is for indent */
2013 say_from_top, say_to_bottom,
2014 say_from_left, say_to_right,
2015 say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2016 speakup_bits, speakup_bits, speakup_bits,
2017 speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2018 speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2021 static void do_spkup(struct vc_data *vc, u_char value)
2023 if (spk_killed && value != SPEECH_KILL)
2027 spk_shut_up &= 0xfe;
2028 this_speakup_key = value;
2029 if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2031 (*spkup_handler[value]) (vc);
2033 if (inc_dec_var(value) < 0)
2038 static const char *pad_chars = "0123456789+-*/\015,.?()";
2041 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2044 unsigned long flags;
2047 u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2048 u_char shift_info, offset;
2054 spin_lock_irqsave(&speakup_info.spinlock, flags);
2059 && (vt_get_leds(fg_console, VC_NUMLOCK))) {
2064 value = spk_lastkey = pad_chars[value];
2069 if (keycode >= MAX_KEY)
2071 key_info = spk_our_keys[keycode];
2074 /* Check valid read all mode keys */
2075 if ((cursor_track == read_all_mode) && (!up_flag)) {
2089 shift_info = (shift_state & 0x0f) + key_speakup;
2090 offset = spk_shift_table[shift_info];
2092 new_key = key_info[offset];
2095 if (new_key == SPK_KEY) {
2096 if (!spk_key_locked)
2097 key_speakup = (up_flag) ? 0 : 16;
2098 if (up_flag || spk_killed)
2100 spk_shut_up &= 0xfe;
2106 if (last_keycode == keycode &&
2107 time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2108 spk_close_press = 1;
2109 offset = spk_shift_table[shift_info + 32];
2111 if (offset && key_info[offset])
2112 new_key = key_info[offset];
2114 last_keycode = keycode;
2115 last_spk_jiffy = jiffies;
2121 if (type == KT_SPKUP && spk_special_handler == NULL) {
2122 do_spkup(vc, new_key);
2123 spk_close_press = 0;
2127 if (up_flag || spk_killed || type == KT_SHIFT)
2129 spk_shut_up &= 0xfe;
2130 kh = (value == KVAL(K_DOWN))
2131 || (value == KVAL(K_UP))
2132 || (value == KVAL(K_LEFT))
2133 || (value == KVAL(K_RIGHT));
2134 if ((cursor_track != read_all_mode) || !kh)
2137 if (spk_special_handler) {
2138 if (type == KT_SPEC && value == 1) {
2141 } else if (type == KT_LETTER)
2143 else if (value == 0x7f)
2144 value = 8; /* make del = backspace */
2145 ret = (*spk_special_handler) (vc, type, value, keycode);
2146 spk_close_press = 0;
2153 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2157 static int keyboard_notifier_call(struct notifier_block *nb,
2158 unsigned long code, void *_param)
2160 struct keyboard_notifier_param *param = _param;
2161 struct vc_data *vc = param->vc;
2162 int up = !param->down;
2163 int ret = NOTIFY_OK;
2164 static int keycode; /* to hold the current keycode */
2166 if (vc->vc_mode == KD_GRAPHICS)
2170 * First, determine whether we are handling a fake keypress on
2171 * the current processor. If we are, then return NOTIFY_OK,
2172 * to pass the keystroke up the chain. This prevents us from
2173 * trying to take the Speakup lock while it is held by the
2174 * processor on which the simulated keystroke was generated.
2175 * Also, the simulated keystrokes should be ignored by Speakup.
2178 if (speakup_fake_key_pressed())
2183 /* speakup requires keycode and keysym currently */
2184 keycode = param->value;
2186 case KBD_UNBOUND_KEYCODE:
2193 if (speakup_key(vc, param->shift, keycode, param->value, up))
2195 else if (KTYP(param->value) == KT_CUR)
2196 ret = pre_handle_cursor(vc, KVAL(param->value), up);
2198 case KBD_POST_KEYSYM:{
2199 unsigned char type = KTYP(param->value) - 0xf0;
2200 unsigned char val = KVAL(param->value);
2204 do_handle_shift(vc, val, up);
2208 do_handle_latin(vc, val, up);
2211 do_handle_cursor(vc, val, up);
2214 do_handle_spec(vc, val, up);
2223 static int vt_notifier_call(struct notifier_block *nb,
2224 unsigned long code, void *_param)
2226 struct vt_notifier_param *param = _param;
2227 struct vc_data *vc = param->vc;
2231 if (vc->vc_mode == KD_TEXT)
2232 speakup_allocate(vc);
2235 speakup_deallocate(vc);
2238 if (param->c == '\b')
2240 else if (param->c < 0x100) {
2243 speakup_con_write(vc, &d, 1);
2247 speakup_con_update(vc);
2253 /* called by: module_exit() */
2254 static void __exit speakup_exit(void)
2258 unregister_keyboard_notifier(&keyboard_notifier_block);
2259 unregister_vt_notifier(&vt_notifier_block);
2260 speakup_unregister_devsynth();
2261 speakup_cancel_paste();
2262 del_timer(&cursor_timer);
2263 kthread_stop(speakup_task);
2264 speakup_task = NULL;
2265 mutex_lock(&spk_mutex);
2267 mutex_unlock(&spk_mutex);
2269 speakup_kobj_exit();
2271 for (i = 0; i < MAX_NR_CONSOLES; i++)
2272 kfree(speakup_console[i]);
2274 speakup_remove_virtual_keyboard();
2276 for (i = 0; i < MAXVARS; i++)
2277 speakup_unregister_var(i);
2279 for (i = 0; i < 256; i++) {
2280 if (spk_characters[i] != spk_default_chars[i])
2281 kfree(spk_characters[i]);
2284 spk_free_user_msgs();
2287 /* call by: module_init() */
2288 static int __init speakup_init(void)
2292 struct st_spk_t *first_console;
2293 struct vc_data *vc = vc_cons[fg_console].d;
2296 /* These first few initializations cannot fail. */
2297 spk_initialize_msgs(); /* Initialize arrays for i18n. */
2298 spk_reset_default_chars();
2299 spk_reset_default_chartab();
2300 spk_strlwr(synth_name);
2301 spk_vars[0].u.n.high = vc->vc_cols;
2302 for (var = spk_vars; var->var_id != MAXVARS; var++)
2303 speakup_register_var(var);
2304 for (var = synth_time_vars;
2305 (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2306 speakup_register_var(var);
2307 for (i = 1; spk_punc_info[i].mask != 0; i++)
2308 spk_set_mask_bits(NULL, i, 2);
2310 spk_set_key_info(spk_key_defaults, spk_key_buf);
2312 /* From here on out, initializations can fail. */
2313 err = speakup_add_virtual_keyboard();
2315 goto error_virtkeyboard;
2317 first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2318 if (!first_console) {
2323 speakup_console[vc->vc_num] = first_console;
2326 for (i = 0; i < MAX_NR_CONSOLES; i++)
2328 err = speakup_allocate(vc_cons[i].d);
2330 goto error_kobjects;
2334 spk_shut_up |= 0x01;
2336 err = speakup_kobj_init();
2338 goto error_kobjects;
2340 synth_init(synth_name);
2341 speakup_register_devsynth();
2343 * register_devsynth might fail, but this error is not fatal.
2344 * /dev/synth is an extra feature; the rest of Speakup
2345 * will work fine without it.
2348 err = register_keyboard_notifier(&keyboard_notifier_block);
2350 goto error_kbdnotifier;
2351 err = register_vt_notifier(&vt_notifier_block);
2353 goto error_vtnotifier;
2355 speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2357 if (IS_ERR(speakup_task)) {
2358 err = PTR_ERR(speakup_task);
2362 set_user_nice(speakup_task, 10);
2363 wake_up_process(speakup_task);
2365 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2366 pr_info("synth name on entry is: %s\n", synth_name);
2370 unregister_vt_notifier(&vt_notifier_block);
2373 unregister_keyboard_notifier(&keyboard_notifier_block);
2374 del_timer(&cursor_timer);
2377 speakup_unregister_devsynth();
2378 mutex_lock(&spk_mutex);
2380 mutex_unlock(&spk_mutex);
2381 speakup_kobj_exit();
2384 for (i = 0; i < MAX_NR_CONSOLES; i++)
2385 kfree(speakup_console[i]);
2388 speakup_remove_virtual_keyboard();
2391 for (i = 0; i < MAXVARS; i++)
2392 speakup_unregister_var(i);
2394 for (i = 0; i < 256; i++) {
2395 if (spk_characters[i] != spk_default_chars[i])
2396 kfree(spk_characters[i]);
2399 spk_free_user_msgs();
2405 module_init(speakup_init);
2406 module_exit(speakup_exit);