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
133 char *spk_characters[256];
135 char *spk_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
200 u_short spk_chartab[256];
202 static u_short default_chartab[256] = {
203 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
204 B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
205 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
206 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
207 WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */
208 PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */
209 NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
210 NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */
211 PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */
212 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
213 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
214 A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */
215 PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */
216 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
217 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
218 ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
219 B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
221 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
223 B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
225 B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
227 WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
229 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
230 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
231 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
232 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
233 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
234 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
235 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
236 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
237 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
238 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
239 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */
242 struct task_struct *speakup_task;
243 struct bleep spk_unprocessed_sound;
244 static int spk_keydown;
245 static u_char spk_lastkey, spk_close_press, keymap_flags;
246 static u_char last_keycode, this_speakup_key;
247 static u_long last_spk_jiffy;
249 struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
251 DEFINE_MUTEX(spk_mutex);
253 static int keyboard_notifier_call(struct notifier_block *,
254 unsigned long code, void *param);
256 static struct notifier_block keyboard_notifier_block = {
257 .notifier_call = keyboard_notifier_call,
260 static int vt_notifier_call(struct notifier_block *,
261 unsigned long code, void *param);
263 static struct notifier_block vt_notifier_block = {
264 .notifier_call = vt_notifier_call,
267 static unsigned char get_attributes(u16 *pos)
269 return (u_char) (scr_readw(pos) >> 8);
272 static void speakup_date(struct vc_data *vc)
274 spk_x = spk_cx = vc->vc_x;
275 spk_y = spk_cy = vc->vc_y;
276 spk_pos = spk_cp = vc->vc_pos;
277 spk_old_attr = spk_attr;
278 spk_attr = get_attributes((u_short *) spk_pos);
281 static void bleep(u_short val)
283 static const short vals[] = {
284 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
287 int time = spk_bleep_time;
289 freq = vals[val % 12];
291 freq *= (1 << (val / 12));
292 spk_unprocessed_sound.freq = freq;
293 spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
294 spk_unprocessed_sound.active = 1;
295 /* We can only have 1 active sound at a time. */
298 static void speakup_shut_up(struct vc_data *vc)
309 static void speech_kill(struct vc_data *vc)
311 char val = synth->is_alive(synth);
316 /* re-enables synth, if disabled */
317 if (val == 2 || spk_killed) {
319 spk_shut_up &= ~0x40;
320 synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
322 synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
327 static void speakup_off(struct vc_data *vc)
329 if (spk_shut_up & 0x80) {
331 synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
334 synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
339 static void speakup_parked(struct vc_data *vc)
341 if (spk_parked & 0x80) {
343 synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
346 synth_printf("%s\n", spk_msg_get(MSG_PARKED));
350 static void speakup_cut(struct vc_data *vc)
352 static const char err_buf[] = "set selection failed";
355 if (!mark_cut_flag) {
357 spk_xs = (u_short) spk_x;
358 spk_ys = (u_short) spk_y;
360 synth_printf("%s\n", spk_msg_get(MSG_MARK));
363 spk_xe = (u_short) spk_x;
364 spk_ye = (u_short) spk_y;
366 synth_printf("%s\n", spk_msg_get(MSG_CUT));
368 speakup_clear_selection();
369 ret = speakup_set_selection(tty);
373 break; /* no error */
375 pr_warn("%sEFAULT\n", err_buf);
378 pr_warn("%sEINVAL\n", err_buf);
381 pr_warn("%sENOMEM\n", err_buf);
386 static void speakup_paste(struct vc_data *vc)
390 synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
392 synth_printf("%s\n", spk_msg_get(MSG_PASTE));
393 speakup_paste_selection(tty);
397 static void say_attributes(struct vc_data *vc)
399 int fg = spk_attr & 0x0f;
400 int bg = spk_attr >> 4;
403 synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
406 synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
408 synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
411 synth_printf(" %s ", spk_msg_get(MSG_ON));
412 synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
423 static void announce_edge(struct vc_data *vc, int msg_id)
427 if ((spk_bleeps & 2) && (msg_id < edge_quiet))
429 spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
432 static void speak_char(u_char ch)
434 char *cp = spk_characters[ch];
435 struct var_t *direct = spk_get_var(DIRECT);
437 if (direct && direct->u.n.value) {
438 if (IS_CHAR(ch, B_CAP)) {
440 synth_printf("%s", spk_str_caps_start);
442 synth_printf("%c", ch);
443 if (IS_CHAR(ch, B_CAP))
444 synth_printf("%s", spk_str_caps_stop);
448 pr_info("speak_char: cp == NULL!\n");
451 synth_buffer_add(SPACE);
452 if (IS_CHAR(ch, B_CAP)) {
454 synth_printf("%s", spk_str_caps_start);
455 synth_printf("%s", cp);
456 synth_printf("%s", spk_str_caps_stop);
459 synth_printf("%s", spk_msg_get(MSG_CTRL));
462 synth_printf("%s", cp);
464 synth_buffer_add(SPACE);
467 static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
472 u16 w = scr_readw(pos);
475 if (w & vc->vc_hi_font_mask)
478 ch = inverse_translate(vc, c, 0);
479 *attribs = (w & 0xff00) >> 8;
484 static void say_char(struct vc_data *vc)
488 spk_old_attr = spk_attr;
489 ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
490 if (spk_attr != spk_old_attr) {
491 if (spk_attrib_bleep & 1)
493 if (spk_attrib_bleep & 2)
496 speak_char(ch & 0xff);
499 static void say_phonetic_char(struct vc_data *vc)
503 spk_old_attr = spk_attr;
504 ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
505 if (isascii(ch) && isalpha(ch)) {
507 synth_printf("%s\n", phonetic[--ch]);
509 if (IS_CHAR(ch, B_NUM))
510 synth_printf("%s ", spk_msg_get(MSG_NUMBER));
515 static void say_prev_char(struct vc_data *vc)
519 announce_edge(vc, edge_left);
527 static void say_next_char(struct vc_data *vc)
530 if (spk_x == vc->vc_cols - 1) {
531 announce_edge(vc, edge_right);
539 /* get_word - will first check to see if the character under the
540 * reading cursor is a space and if spk_say_word_ctl is true it will
541 * return the word space. If spk_say_word_ctl is not set it will check to
542 * see if there is a word starting on the next position to the right
543 * and return that word if it exists. If it does not exist it will
544 * move left to the beginning of any previous word on the line or the
545 * beginning off the line whichever comes first..
548 static u_long get_word(struct vc_data *vc)
550 u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
555 spk_old_attr = spk_attr;
556 ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
558 /* decided to take out the sayword if on a space (mis-information */
559 if (spk_say_word_ctl && ch == SPACE) {
561 synth_printf("%s\n", spk_msg_get(MSG_SPACE));
563 } else if ((tmpx < vc->vc_cols - 2)
564 && (ch == SPACE || ch == 0 || IS_WDLM(ch))
565 && ((char)get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE)) {
570 ch = (char)get_char(vc, (u_short *) tmp_pos - 1, &temp);
571 if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
572 && ((char)get_char(vc, (u_short *) tmp_pos, &temp) >
578 attr_ch = get_char(vc, (u_short *) tmp_pos, &spk_attr);
579 buf[cnt++] = attr_ch & 0xff;
580 while (tmpx < vc->vc_cols - 1) {
583 ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
584 if ((ch == SPACE) || ch == 0
585 || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
593 static void say_word(struct vc_data *vc)
595 u_long cnt = get_word(vc);
596 u_short saved_punc_mask = spk_punc_mask;
600 spk_punc_mask = PUNC;
602 spkup_write(buf, cnt);
603 spk_punc_mask = saved_punc_mask;
606 static void say_prev_word(struct vc_data *vc)
610 u_short edge_said = 0, last_state = 0, state = 0;
616 announce_edge(vc, edge_top);
621 edge_said = edge_quiet;
626 edge_said = edge_top;
629 if (edge_said != edge_quiet)
630 edge_said = edge_left;
634 spk_x = vc->vc_cols - 1;
638 ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
639 if (ch == SPACE || ch == 0)
641 else if (IS_WDLM(ch))
645 if (state < last_state) {
652 if (spk_x == 0 && edge_said == edge_quiet)
653 edge_said = edge_left;
654 if (edge_said > 0 && edge_said < edge_quiet)
655 announce_edge(vc, edge_said);
659 static void say_next_word(struct vc_data *vc)
663 u_short edge_said = 0, last_state = 2, state = 0;
666 if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
667 announce_edge(vc, edge_bottom);
671 ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
672 if (ch == SPACE || ch == 0)
674 else if (IS_WDLM(ch))
678 if (state > last_state)
680 if (spk_x >= vc->vc_cols - 1) {
681 if (spk_y == vc->vc_rows - 1) {
682 edge_said = edge_bottom;
688 edge_said = edge_right;
695 announce_edge(vc, edge_said);
699 static void spell_word(struct vc_data *vc)
701 static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
702 char *cp = buf, *str_cap = spk_str_caps_stop;
703 char *cp1, *last_cap = spk_str_caps_stop;
708 while ((ch = (u_char) *cp)) {
710 synth_printf(" %s ", delay_str[spk_spell_delay]);
711 if (IS_CHAR(ch, B_CAP)) {
712 str_cap = spk_str_caps_start;
713 if (*spk_str_caps_stop)
715 else /* synth has no pitch */
716 last_cap = spk_str_caps_stop;
718 str_cap = spk_str_caps_stop;
719 if (str_cap != last_cap) {
720 synth_printf("%s", str_cap);
723 if (this_speakup_key == SPELL_PHONETIC
724 && (isascii(ch) && isalpha(ch))) {
726 cp1 = phonetic[--ch];
728 cp1 = spk_characters[ch];
730 synth_printf("%s", spk_msg_get(MSG_CTRL));
734 synth_printf("%s", cp1);
737 if (str_cap != spk_str_caps_stop)
738 synth_printf("%s", spk_str_caps_stop);
741 static int get_line(struct vc_data *vc)
743 u_long tmp = spk_pos - (spk_x * 2);
747 spk_old_attr = spk_attr;
748 spk_attr = get_attributes((u_short *) spk_pos);
749 for (i = 0; i < vc->vc_cols; i++) {
750 buf[i] = (u_char) get_char(vc, (u_short *) tmp, &tmp2);
753 for (--i; i >= 0; i--)
759 static void say_line(struct vc_data *vc)
761 int i = get_line(vc);
763 u_short saved_punc_mask = spk_punc_mask;
766 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
770 if (this_speakup_key == SAY_LINE_INDENT) {
774 synth_printf("%d, ", (cp - buf) + 1);
776 spk_punc_mask = spk_punc_masks[spk_reading_punc];
778 spk_punc_mask = saved_punc_mask;
781 static void say_prev_line(struct vc_data *vc)
785 announce_edge(vc, edge_top);
789 spk_pos -= vc->vc_size_row;
793 static void say_next_line(struct vc_data *vc)
796 if (spk_y == vc->vc_rows - 1) {
797 announce_edge(vc, edge_bottom);
801 spk_pos += vc->vc_size_row;
805 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
810 u_short saved_punc_mask = spk_punc_mask;
812 spk_old_attr = spk_attr;
813 spk_attr = get_attributes((u_short *) from);
815 buf[i++] = (char)get_char(vc, (u_short *) from, &tmp);
817 if (i >= vc->vc_size_row)
820 for (--i; i >= 0; i--)
828 spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
831 spk_punc_mask = saved_punc_mask;
835 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
838 u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
839 u_long end = start + (to * 2);
842 if (say_from_to(vc, start, end, read_punc) <= 0)
843 if (cursor_track != read_all_mode)
844 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
847 /* Sentence Reading Commands */
849 static int currsentence;
850 static int numsentences[2];
851 static char *sentbufend[2];
852 static char *sentmarks[2][10];
855 static char sentbuf[2][256];
857 static int say_sentence_num(int num, int prev)
860 currsentence = num + 1;
861 if (prev && --bn == -1)
864 if (num > numsentences[bn])
867 spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
871 static int get_sentence_buf(struct vc_data *vc, int read_punc)
881 start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
882 end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
884 numsentences[bn] = 0;
885 sentmarks[bn][0] = &sentbuf[bn][0];
887 spk_old_attr = spk_attr;
888 spk_attr = get_attributes((u_short *) start);
890 while (start < end) {
891 sentbuf[bn][i] = (char)get_char(vc, (u_short *) start, &tmp);
893 if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
894 && numsentences[bn] < 9) {
895 /* Sentence Marker */
897 sentmarks[bn][numsentences[bn]] =
903 if (i >= vc->vc_size_row)
907 for (--i; i >= 0; i--)
908 if (sentbuf[bn][i] != SPACE)
914 sentbuf[bn][++i] = SPACE;
915 sentbuf[bn][++i] = '\0';
917 sentbufend[bn] = &sentbuf[bn][i];
918 return numsentences[bn];
921 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
923 u_long start = vc->vc_origin, end;
926 start += from * vc->vc_size_row;
927 if (to > vc->vc_rows)
929 end = vc->vc_origin + (to * vc->vc_size_row);
930 for (from = start; from < end; from = to) {
931 to = from + vc->vc_size_row;
932 say_from_to(vc, from, to, 1);
936 static void say_screen(struct vc_data *vc)
938 say_screen_from_to(vc, 0, vc->vc_rows);
941 static void speakup_win_say(struct vc_data *vc)
943 u_long start, end, from, to;
946 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
949 start = vc->vc_origin + (win_top * vc->vc_size_row);
950 end = vc->vc_origin + (win_bottom * vc->vc_size_row);
951 while (start <= end) {
952 from = start + (win_left * 2);
953 to = start + (win_right * 2);
954 say_from_to(vc, from, to, 1);
955 start += vc->vc_size_row;
959 static void top_edge(struct vc_data *vc)
962 spk_pos = vc->vc_origin + 2 * spk_x;
967 static void bottom_edge(struct vc_data *vc)
970 spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
971 spk_y = vc->vc_rows - 1;
975 static void left_edge(struct vc_data *vc)
978 spk_pos -= spk_x * 2;
983 static void right_edge(struct vc_data *vc)
986 spk_pos += (vc->vc_cols - spk_x - 1) * 2;
987 spk_x = vc->vc_cols - 1;
991 static void say_first_char(struct vc_data *vc)
993 int i, len = get_line(vc);
998 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1001 for (i = 0; i < len; i++)
1002 if (buf[i] != SPACE)
1005 spk_pos -= (spk_x - i) * 2;
1007 synth_printf("%d, ", ++i);
1011 static void say_last_char(struct vc_data *vc)
1013 int len = get_line(vc);
1018 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1022 spk_pos -= (spk_x - len) * 2;
1024 synth_printf("%d, ", ++len);
1028 static void say_position(struct vc_data *vc)
1030 synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1035 /* Added by brianb */
1036 static void say_char_num(struct vc_data *vc)
1039 u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
1042 synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1045 /* these are stub functions to keep keyboard.c happy. */
1047 static void say_from_top(struct vc_data *vc)
1049 say_screen_from_to(vc, 0, spk_y);
1052 static void say_to_bottom(struct vc_data *vc)
1054 say_screen_from_to(vc, spk_y, vc->vc_rows);
1057 static void say_from_left(struct vc_data *vc)
1059 say_line_from_to(vc, 0, spk_x, 1);
1062 static void say_to_right(struct vc_data *vc)
1064 say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1067 /* end of stub functions. */
1069 static void spkup_write(const char *in_buf, int count)
1071 static int rep_count;
1072 static u_char ch = '\0', old_ch = '\0';
1073 static u_short char_type, last_type;
1074 int in_count = count;
1078 if (cursor_track == read_all_mode) {
1079 /* Insert Sentence Index */
1080 if ((in_buf == sentmarks[bn][currsentence]) &&
1081 (currsentence <= numsentences[bn]))
1082 synth_insert_next_index(currsentence++);
1084 ch = (u_char) *in_buf++;
1085 char_type = spk_chartab[ch];
1086 if (ch == old_ch && !(char_type & B_NUM)) {
1087 if (++rep_count > 2)
1090 if ((last_type & CH_RPT) && rep_count > 2) {
1092 synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1098 if (ch == spk_lastkey) {
1100 if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1102 } else if (char_type & B_ALPHA) {
1103 if ((synth_flags & SF_DEC) && (last_type & PUNC))
1104 synth_buffer_add(SPACE);
1105 synth_printf("%c", ch);
1106 } else if (char_type & B_NUM) {
1108 synth_printf("%c", ch);
1109 } else if (char_type & spk_punc_mask) {
1111 char_type &= ~PUNC; /* for dec nospell processing */
1112 } else if (char_type & SYNTH_OK) {
1113 /* these are usually puncts like . and , which synth
1114 * needs for expression.
1115 * suppress multiple to get rid of long pauses and
1116 * clear repeat count
1118 * repeats on you don't get nothing repeated count
1121 synth_printf("%c", ch);
1125 /* send space and record position, if next is num overwrite space */
1127 synth_buffer_add(SPACE);
1132 last_type = char_type;
1135 if (in_count > 2 && rep_count > 2) {
1136 if (last_type & CH_RPT) {
1138 synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
1146 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1148 static void read_all_doc(struct vc_data *vc);
1149 static void cursor_done(u_long data);
1150 static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1152 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1154 unsigned long flags;
1156 if (synth == NULL || up_flag || spk_killed)
1158 spin_lock_irqsave(&speakup_info.spinlock, flags);
1159 if (cursor_track == read_all_mode) {
1162 del_timer(&cursor_timer);
1163 spk_shut_up &= 0xfe;
1168 del_timer(&cursor_timer);
1169 cursor_track = prev_cursor_track;
1170 spk_shut_up &= 0xfe;
1175 spk_shut_up &= 0xfe;
1178 if (spk_say_ctrl && value < NUM_CTL_LABELS)
1179 synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1180 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1183 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1185 unsigned long flags;
1187 spin_lock_irqsave(&speakup_info.spinlock, flags);
1189 spk_lastkey = spk_keydown = 0;
1190 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1193 if (synth == NULL || spk_killed) {
1194 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1197 spk_shut_up &= 0xfe;
1198 spk_lastkey = value;
1201 if (spk_key_echo == 2 && value >= MINECHOCHAR)
1203 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1206 int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1208 int i = 0, states, key_data_len;
1209 const u_char *cp = key_info;
1210 u_char *cp1 = k_buffer;
1211 u_char ch, version, num_keys;
1214 if (version != KEY_MAP_VER)
1217 states = (int)cp[1];
1218 key_data_len = (states + 1) * (num_keys + 1);
1219 if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf))
1221 memset(k_buffer, 0, SHIFT_TBL_SIZE);
1222 memset(spk_our_keys, 0, sizeof(spk_our_keys));
1223 spk_shift_table = k_buffer;
1224 spk_our_keys[0] = spk_shift_table;
1225 cp1 += SHIFT_TBL_SIZE;
1226 memcpy(cp1, cp, key_data_len + 3);
1227 /* get num_keys, states and data */
1228 cp1 += 2; /* now pointing at shift states */
1229 for (i = 1; i <= states; i++) {
1231 if (ch >= SHIFT_TBL_SIZE)
1233 spk_shift_table[ch] = i;
1235 keymap_flags = *cp1++;
1236 while ((ch = *cp1)) {
1239 spk_our_keys[ch] = cp1;
1245 static struct var_t spk_vars[] = {
1246 /* bell must be first to set high limit */
1247 {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1248 {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1249 {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1250 {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1251 {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1252 {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1253 {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1254 {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1255 {SAY_CONTROL, TOGGLE_0},
1256 {SAY_WORD_CTL, TOGGLE_0},
1257 {NO_INTERRUPT, TOGGLE_0},
1258 {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1262 static void toggle_cursoring(struct vc_data *vc)
1264 if (cursor_track == read_all_mode)
1265 cursor_track = prev_cursor_track;
1266 if (++cursor_track >= CT_Max)
1268 synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1271 void spk_reset_default_chars(void)
1275 /* First, free any non-default */
1276 for (i = 0; i < 256; i++) {
1277 if ((spk_characters[i] != NULL)
1278 && (spk_characters[i] != spk_default_chars[i]))
1279 kfree(spk_characters[i]);
1282 memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1285 void spk_reset_default_chartab(void)
1287 memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1290 static const struct st_bits_data *pb_edit;
1292 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1294 short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1296 if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1299 synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1300 spk_special_handler = NULL;
1303 if (mask < PUNC && !(ch_type & PUNC))
1305 spk_chartab[ch] ^= mask;
1307 synth_printf(" %s\n",
1308 (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1309 spk_msg_get(MSG_OFF));
1313 /* Allocation concurrency is protected by the console semaphore */
1314 static int speakup_allocate(struct vc_data *vc)
1318 vc_num = vc->vc_num;
1319 if (speakup_console[vc_num] == NULL) {
1320 speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1322 if (speakup_console[vc_num] == NULL)
1325 } else if (!spk_parked)
1331 static void speakup_deallocate(struct vc_data *vc)
1335 vc_num = vc->vc_num;
1336 kfree(speakup_console[vc_num]);
1337 speakup_console[vc_num] = NULL;
1340 static u_char is_cursor;
1341 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1342 static int cursor_con;
1344 static void reset_highlight_buffers(struct vc_data *);
1346 static int read_all_key;
1348 static void start_read_all_timer(struct vc_data *vc, int command);
1362 static void kbd_fakekey2(struct vc_data *vc, int command)
1364 del_timer(&cursor_timer);
1365 speakup_fake_down_arrow();
1366 start_read_all_timer(vc, command);
1369 static void read_all_doc(struct vc_data *vc)
1371 if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1373 if (!synth_supports_indexing())
1375 if (cursor_track != read_all_mode)
1376 prev_cursor_track = cursor_track;
1377 cursor_track = read_all_mode;
1378 spk_reset_index_count(0);
1379 if (get_sentence_buf(vc, 0) == -1)
1380 kbd_fakekey2(vc, RA_DOWN_ARROW);
1382 say_sentence_num(0, 0);
1383 synth_insert_next_index(0);
1384 start_read_all_timer(vc, RA_TIMER);
1388 static void stop_read_all(struct vc_data *vc)
1390 del_timer(&cursor_timer);
1391 cursor_track = prev_cursor_track;
1392 spk_shut_up &= 0xfe;
1396 static void start_read_all_timer(struct vc_data *vc, int command)
1398 struct var_t *cursor_timeout;
1400 cursor_con = vc->vc_num;
1401 read_all_key = command;
1402 cursor_timeout = spk_get_var(CURSOR_TIME);
1403 mod_timer(&cursor_timer,
1404 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1407 static void handle_cursor_read_all(struct vc_data *vc, int command)
1409 int indcount, sentcount, rv, sn;
1413 /* Get Current Sentence */
1414 spk_get_index_count(&indcount, &sentcount);
1415 /*printk("%d %d ", indcount, sentcount); */
1416 spk_reset_index_count(sentcount + 1);
1417 if (indcount == 1) {
1418 if (!say_sentence_num(sentcount + 1, 0)) {
1419 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1422 synth_insert_next_index(0);
1425 if (!say_sentence_num(sentcount + 1, 1)) {
1427 spk_reset_index_count(sn);
1429 synth_insert_next_index(0);
1430 if (!say_sentence_num(sn, 0)) {
1431 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1434 synth_insert_next_index(0);
1436 start_read_all_timer(vc, RA_TIMER);
1446 if (get_sentence_buf(vc, 0) == -1) {
1447 kbd_fakekey2(vc, RA_DOWN_ARROW);
1449 say_sentence_num(0, 0);
1450 synth_insert_next_index(0);
1451 start_read_all_timer(vc, RA_TIMER);
1454 case RA_FIND_NEXT_SENT:
1455 rv = get_sentence_buf(vc, 0);
1459 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1461 say_sentence_num(1, 0);
1462 synth_insert_next_index(0);
1463 start_read_all_timer(vc, RA_TIMER);
1466 case RA_FIND_PREV_SENT:
1469 spk_get_index_count(&indcount, &sentcount);
1471 kbd_fakekey2(vc, RA_DOWN_ARROW);
1473 start_read_all_timer(vc, RA_TIMER);
1478 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1480 unsigned long flags;
1482 spin_lock_irqsave(&speakup_info.spinlock, flags);
1483 if (cursor_track == read_all_mode) {
1485 if (synth == NULL || up_flag || spk_shut_up) {
1486 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1489 del_timer(&cursor_timer);
1490 spk_shut_up &= 0xfe;
1492 start_read_all_timer(vc, value + 1);
1493 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1496 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1500 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1502 unsigned long flags;
1503 struct var_t *cursor_timeout;
1505 spin_lock_irqsave(&speakup_info.spinlock, flags);
1507 if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1508 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1511 spk_shut_up &= 0xfe;
1514 /* the key press flushes if !no_inter but we want to flush on cursor
1515 * moves regardless of no_inter state
1517 is_cursor = value + 1;
1518 old_cursor_pos = vc->vc_pos;
1519 old_cursor_x = vc->vc_x;
1520 old_cursor_y = vc->vc_y;
1521 speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1522 cursor_con = vc->vc_num;
1523 if (cursor_track == CT_Highlight)
1524 reset_highlight_buffers(vc);
1525 cursor_timeout = spk_get_var(CURSOR_TIME);
1526 mod_timer(&cursor_timer,
1527 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1528 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1531 static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
1534 int vc_num = vc->vc_num;
1536 bi = (vc->vc_attr & 0x70) >> 4;
1537 hi = speakup_console[vc_num]->ht.highsize[bi];
1540 if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1541 speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1542 speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1543 speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1545 while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1546 if ((ic[i] > 32) && (ic[i] < 127)) {
1547 speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1549 } else if ((ic[i] == 32) && (hi != 0)) {
1550 if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1552 speakup_console[vc_num]->ht.highbuf[bi][hi] =
1559 speakup_console[vc_num]->ht.highsize[bi] = hi;
1562 static void reset_highlight_buffers(struct vc_data *vc)
1565 int vc_num = vc->vc_num;
1567 for (i = 0; i < 8; i++)
1568 speakup_console[vc_num]->ht.highsize[i] = 0;
1571 static int count_highlight_color(struct vc_data *vc)
1575 int vc_num = vc->vc_num;
1577 u16 *start = (u16 *) vc->vc_origin;
1579 for (i = 0; i < 8; i++)
1580 speakup_console[vc_num]->ht.bgcount[i] = 0;
1582 for (i = 0; i < vc->vc_rows; i++) {
1583 u16 *end = start + vc->vc_cols * 2;
1586 for (ptr = start; ptr < end; ptr++) {
1587 ch = get_attributes(ptr);
1588 bg = (ch & 0x70) >> 4;
1589 speakup_console[vc_num]->ht.bgcount[bg]++;
1591 start += vc->vc_size_row;
1595 for (i = 0; i < 8; i++)
1596 if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1601 static int get_highlight_color(struct vc_data *vc)
1604 unsigned int cptr[8];
1605 int vc_num = vc->vc_num;
1607 for (i = 0; i < 8; i++)
1610 for (i = 0; i < 7; i++)
1611 for (j = i + 1; j < 8; j++)
1612 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1613 speakup_console[vc_num]->ht.bgcount[cptr[j]])
1614 swap(cptr[i], cptr[j]);
1616 for (i = 0; i < 8; i++)
1617 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1618 if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1623 static int speak_highlight(struct vc_data *vc)
1626 int vc_num = vc->vc_num;
1628 if (count_highlight_color(vc) == 1)
1630 hc = get_highlight_color(vc);
1632 d = vc->vc_y - speakup_console[vc_num]->ht.cy;
1633 if ((d == 1) || (d == -1))
1634 if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1638 spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1639 speakup_console[vc_num]->ht.highsize[hc]);
1640 spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1641 spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1642 spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1648 static void cursor_done(u_long data)
1650 struct vc_data *vc = vc_cons[cursor_con].d;
1651 unsigned long flags;
1653 del_timer(&cursor_timer);
1654 spin_lock_irqsave(&speakup_info.spinlock, flags);
1655 if (cursor_con != fg_console) {
1661 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1662 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1663 spk_keydown = is_cursor = 0;
1667 if (cursor_track == read_all_mode) {
1668 handle_cursor_read_all(vc, read_all_key);
1671 if (cursor_track == CT_Highlight) {
1672 if (speak_highlight(vc)) {
1673 spk_keydown = is_cursor = 0;
1677 if (cursor_track == CT_Window)
1678 speakup_win_say(vc);
1679 else if (is_cursor == 1 || is_cursor == 4)
1680 say_line_from_to(vc, 0, vc->vc_cols, 0);
1683 spk_keydown = is_cursor = 0;
1685 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1688 /* called by: vt_notifier_call() */
1689 static void speakup_bs(struct vc_data *vc)
1691 unsigned long flags;
1693 if (!speakup_console[vc->vc_num])
1695 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1696 /* Speakup output, discard */
1700 if (spk_shut_up || synth == NULL) {
1701 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1704 if (vc->vc_num == fg_console && spk_keydown) {
1709 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1712 /* called by: vt_notifier_call() */
1713 static void speakup_con_write(struct vc_data *vc, const char *str, int len)
1715 unsigned long flags;
1717 if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1719 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1720 /* Speakup output, discard */
1722 if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
1724 if ((is_cursor) || (cursor_track == read_all_mode)) {
1725 if (cursor_track == CT_Highlight)
1726 update_color_buffer(vc, str, len);
1727 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1731 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1732 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1733 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1738 spkup_write(str, len);
1739 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1742 static void speakup_con_update(struct vc_data *vc)
1744 unsigned long flags;
1746 if (speakup_console[vc->vc_num] == NULL || spk_parked)
1748 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1749 /* Speakup output, discard */
1752 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1755 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1757 unsigned long flags;
1761 if (synth == NULL || up_flag || spk_killed)
1763 spin_lock_irqsave(&speakup_info.spinlock, flags);
1764 spk_shut_up &= 0xfe;
1769 label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1770 on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1773 label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1774 on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1777 label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1778 on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1779 if (speakup_console[vc->vc_num])
1780 speakup_console[vc->vc_num]->tty_stopped = on_off;
1784 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1788 synth_printf("%s %s\n",
1789 label, spk_msg_get(MSG_STATUS_START + on_off));
1790 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1793 static int inc_dec_var(u_char value)
1795 struct st_var_header *p_header;
1796 struct var_t *var_data;
1800 int var_id = (int)value - VAR_START;
1801 int how = (var_id & 1) ? E_INC : E_DEC;
1803 var_id = var_id / 2 + FIRST_SET_VAR;
1804 p_header = spk_get_var_header(var_id);
1805 if (p_header == NULL)
1807 if (p_header->var_type != VAR_NUM)
1809 var_data = p_header->data;
1810 if (spk_set_num_var(1, p_header, how) != 0)
1812 if (!spk_close_press) {
1813 for (pn = p_header->name; *pn; pn++) {
1820 snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1821 var_data->u.n.value);
1822 synth_printf("%s", num_buf);
1826 static void speakup_win_set(struct vc_data *vc)
1830 if (win_start > 1) {
1831 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1834 if (spk_x < win_left || spk_y < win_top) {
1835 synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1838 if (win_start && spk_x == win_left && spk_y == win_top) {
1840 win_right = vc->vc_cols - 1;
1842 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1852 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1854 spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1855 (int)spk_y + 1, (int)spk_x + 1);
1857 synth_printf("%s\n", info);
1861 static void speakup_win_clear(struct vc_data *vc)
1863 win_top = win_bottom = 0;
1864 win_left = win_right = 0;
1866 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1869 static void speakup_win_enable(struct vc_data *vc)
1871 if (win_start < 2) {
1872 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1877 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1879 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1882 static void speakup_bits(struct vc_data *vc)
1884 int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1886 if (spk_special_handler != NULL || val < 1 || val > 6) {
1887 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1890 pb_edit = &spk_punc_info[val];
1891 synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1892 spk_special_handler = edit_bits;
1895 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1897 static u_char goto_buf[8];
1902 if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1904 if (type == KT_LATIN && ch == '\n')
1911 ch = goto_buf[--num];
1912 goto_buf[num] = '\0';
1913 spkup_write(&ch, 1);
1916 if (ch < '+' || ch > 'y')
1918 goto_buf[num++] = ch;
1919 goto_buf[num] = '\0';
1920 spkup_write(&ch, 1);
1921 maxlen = (*goto_buf >= '0') ? 3 : 4;
1922 if ((ch == '+' || ch == '-') && num == 1)
1924 if (ch >= '0' && ch <= '9' && num < maxlen)
1926 if (num < maxlen - 1 || num > maxlen)
1928 if (ch < 'x' || ch > 'y') {
1931 synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1932 goto_buf[num = 0] = '\0';
1933 spk_special_handler = NULL;
1937 goto_pos = simple_strtoul(goto_buf, &cp, 10);
1940 if (*goto_buf < '0')
1942 else if (goto_pos > 0)
1945 if (goto_pos >= vc->vc_cols)
1946 goto_pos = vc->vc_cols - 1;
1949 if (*goto_buf < '0')
1951 else if (goto_pos > 0)
1954 if (goto_pos >= vc->vc_rows)
1955 goto_pos = vc->vc_rows - 1;
1958 goto_buf[num = 0] = '\0';
1960 spk_special_handler = NULL;
1963 spk_pos -= spk_x * 2;
1965 spk_pos += goto_pos * 2;
1969 spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1975 static void speakup_goto(struct vc_data *vc)
1977 if (spk_special_handler != NULL) {
1978 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1981 synth_printf("%s\n", spk_msg_get(MSG_GOTO));
1982 spk_special_handler = handle_goto;
1985 static void speakup_help(struct vc_data *vc)
1987 spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1990 static void do_nothing(struct vc_data *vc)
1992 return; /* flush done in do_spkup */
1995 static u_char key_speakup, spk_key_locked;
1997 static void speakup_lock(struct vc_data *vc)
1999 if (!spk_key_locked)
2000 spk_key_locked = key_speakup = 16;
2002 spk_key_locked = key_speakup = 0;
2005 typedef void (*spkup_hand) (struct vc_data *);
2006 static spkup_hand spkup_handler[] = {
2007 /* must be ordered same as defines in speakup.h */
2008 do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2009 speakup_cut, speakup_paste, say_first_char, say_last_char,
2010 say_char, say_prev_char, say_next_char,
2011 say_word, say_prev_word, say_next_word,
2012 say_line, say_prev_line, say_next_line,
2013 top_edge, bottom_edge, left_edge, right_edge,
2014 spell_word, spell_word, say_screen,
2015 say_position, say_attributes,
2016 speakup_off, speakup_parked, say_line, /* this is for indent */
2017 say_from_top, say_to_bottom,
2018 say_from_left, say_to_right,
2019 say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2020 speakup_bits, speakup_bits, speakup_bits,
2021 speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2022 speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2025 static void do_spkup(struct vc_data *vc, u_char value)
2027 if (spk_killed && value != SPEECH_KILL)
2031 spk_shut_up &= 0xfe;
2032 this_speakup_key = value;
2033 if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2035 (*spkup_handler[value]) (vc);
2037 if (inc_dec_var(value) < 0)
2042 static const char *pad_chars = "0123456789+-*/\015,.?()";
2045 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2048 unsigned long flags;
2051 u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2052 u_char shift_info, offset;
2058 spin_lock_irqsave(&speakup_info.spinlock, flags);
2063 && (vt_get_leds(fg_console, VC_NUMLOCK))) {
2068 value = spk_lastkey = pad_chars[value];
2073 if (keycode >= MAX_KEY)
2075 key_info = spk_our_keys[keycode];
2078 /* Check valid read all mode keys */
2079 if ((cursor_track == read_all_mode) && (!up_flag)) {
2093 shift_info = (shift_state & 0x0f) + key_speakup;
2094 offset = spk_shift_table[shift_info];
2096 new_key = key_info[offset];
2099 if (new_key == SPK_KEY) {
2100 if (!spk_key_locked)
2101 key_speakup = (up_flag) ? 0 : 16;
2102 if (up_flag || spk_killed)
2104 spk_shut_up &= 0xfe;
2110 if (last_keycode == keycode &&
2111 time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2112 spk_close_press = 1;
2113 offset = spk_shift_table[shift_info + 32];
2115 if (offset && key_info[offset])
2116 new_key = key_info[offset];
2118 last_keycode = keycode;
2119 last_spk_jiffy = jiffies;
2125 if (type == KT_SPKUP && spk_special_handler == NULL) {
2126 do_spkup(vc, new_key);
2127 spk_close_press = 0;
2131 if (up_flag || spk_killed || type == KT_SHIFT)
2133 spk_shut_up &= 0xfe;
2134 kh = (value == KVAL(K_DOWN))
2135 || (value == KVAL(K_UP))
2136 || (value == KVAL(K_LEFT))
2137 || (value == KVAL(K_RIGHT));
2138 if ((cursor_track != read_all_mode) || !kh)
2141 if (spk_special_handler) {
2142 if (type == KT_SPEC && value == 1) {
2145 } else if (type == KT_LETTER)
2147 else if (value == 0x7f)
2148 value = 8; /* make del = backspace */
2149 ret = (*spk_special_handler) (vc, type, value, keycode);
2150 spk_close_press = 0;
2157 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2161 static int keyboard_notifier_call(struct notifier_block *nb,
2162 unsigned long code, void *_param)
2164 struct keyboard_notifier_param *param = _param;
2165 struct vc_data *vc = param->vc;
2166 int up = !param->down;
2167 int ret = NOTIFY_OK;
2168 static int keycode; /* to hold the current keycode */
2170 if (vc->vc_mode == KD_GRAPHICS)
2174 * First, determine whether we are handling a fake keypress on
2175 * the current processor. If we are, then return NOTIFY_OK,
2176 * to pass the keystroke up the chain. This prevents us from
2177 * trying to take the Speakup lock while it is held by the
2178 * processor on which the simulated keystroke was generated.
2179 * Also, the simulated keystrokes should be ignored by Speakup.
2182 if (speakup_fake_key_pressed())
2187 /* speakup requires keycode and keysym currently */
2188 keycode = param->value;
2190 case KBD_UNBOUND_KEYCODE:
2197 if (speakup_key(vc, param->shift, keycode, param->value, up))
2199 else if (KTYP(param->value) == KT_CUR)
2200 ret = pre_handle_cursor(vc, KVAL(param->value), up);
2202 case KBD_POST_KEYSYM:{
2203 unsigned char type = KTYP(param->value) - 0xf0;
2204 unsigned char val = KVAL(param->value);
2208 do_handle_shift(vc, val, up);
2212 do_handle_latin(vc, val, up);
2215 do_handle_cursor(vc, val, up);
2218 do_handle_spec(vc, val, up);
2227 static int vt_notifier_call(struct notifier_block *nb,
2228 unsigned long code, void *_param)
2230 struct vt_notifier_param *param = _param;
2231 struct vc_data *vc = param->vc;
2235 if (vc->vc_mode == KD_TEXT)
2236 speakup_allocate(vc);
2239 speakup_deallocate(vc);
2242 if (param->c == '\b')
2244 else if (param->c < 0x100) {
2247 speakup_con_write(vc, &d, 1);
2251 speakup_con_update(vc);
2257 /* called by: module_exit() */
2258 static void __exit speakup_exit(void)
2262 unregister_keyboard_notifier(&keyboard_notifier_block);
2263 unregister_vt_notifier(&vt_notifier_block);
2264 speakup_unregister_devsynth();
2265 speakup_cancel_paste();
2266 del_timer(&cursor_timer);
2267 kthread_stop(speakup_task);
2268 speakup_task = NULL;
2269 mutex_lock(&spk_mutex);
2271 mutex_unlock(&spk_mutex);
2273 speakup_kobj_exit();
2275 for (i = 0; i < MAX_NR_CONSOLES; i++)
2276 kfree(speakup_console[i]);
2278 speakup_remove_virtual_keyboard();
2280 for (i = 0; i < MAXVARS; i++)
2281 speakup_unregister_var(i);
2283 for (i = 0; i < 256; i++) {
2284 if (spk_characters[i] != spk_default_chars[i])
2285 kfree(spk_characters[i]);
2288 spk_free_user_msgs();
2291 /* call by: module_init() */
2292 static int __init speakup_init(void)
2296 struct st_spk_t *first_console;
2297 struct vc_data *vc = vc_cons[fg_console].d;
2300 /* These first few initializations cannot fail. */
2301 spk_initialize_msgs(); /* Initialize arrays for i18n. */
2302 spk_reset_default_chars();
2303 spk_reset_default_chartab();
2304 spk_strlwr(synth_name);
2305 spk_vars[0].u.n.high = vc->vc_cols;
2306 for (var = spk_vars; var->var_id != MAXVARS; var++)
2307 speakup_register_var(var);
2308 for (var = synth_time_vars;
2309 (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2310 speakup_register_var(var);
2311 for (i = 1; spk_punc_info[i].mask != 0; i++)
2312 spk_set_mask_bits(NULL, i, 2);
2314 spk_set_key_info(spk_key_defaults, spk_key_buf);
2316 /* From here on out, initializations can fail. */
2317 err = speakup_add_virtual_keyboard();
2319 goto error_virtkeyboard;
2321 first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2322 if (!first_console) {
2327 speakup_console[vc->vc_num] = first_console;
2330 for (i = 0; i < MAX_NR_CONSOLES; i++)
2332 err = speakup_allocate(vc_cons[i].d);
2334 goto error_kobjects;
2338 spk_shut_up |= 0x01;
2340 err = speakup_kobj_init();
2342 goto error_kobjects;
2344 synth_init(synth_name);
2345 speakup_register_devsynth();
2347 * register_devsynth might fail, but this error is not fatal.
2348 * /dev/synth is an extra feature; the rest of Speakup
2349 * will work fine without it.
2352 err = register_keyboard_notifier(&keyboard_notifier_block);
2354 goto error_kbdnotifier;
2355 err = register_vt_notifier(&vt_notifier_block);
2357 goto error_vtnotifier;
2359 speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2361 if (IS_ERR(speakup_task)) {
2362 err = PTR_ERR(speakup_task);
2366 set_user_nice(speakup_task, 10);
2367 wake_up_process(speakup_task);
2369 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2370 pr_info("synth name on entry is: %s\n", synth_name);
2374 unregister_vt_notifier(&vt_notifier_block);
2377 unregister_keyboard_notifier(&keyboard_notifier_block);
2378 del_timer(&cursor_timer);
2381 speakup_unregister_devsynth();
2382 mutex_lock(&spk_mutex);
2384 mutex_unlock(&spk_mutex);
2385 speakup_kobj_exit();
2388 for (i = 0; i < MAX_NR_CONSOLES; i++)
2389 kfree(speakup_console[i]);
2392 speakup_remove_virtual_keyboard();
2395 for (i = 0; i < MAXVARS; i++)
2396 speakup_unregister_var(i);
2398 for (i = 0; i < 256; i++) {
2399 if (spk_characters[i] != spk_default_chars[i])
2400 kfree(spk_characters[i]);
2403 spk_free_user_msgs();
2409 module_init(speakup_init);
2410 module_exit(speakup_exit);