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.
21 #include <linux/kernel.h>
23 #include <linux/tty.h>
24 #include <linux/mm.h> /* __get_free_page() and friends */
25 #include <linux/vt_kern.h>
26 #include <linux/ctype.h>
27 #include <linux/selection.h>
28 #include <linux/unistd.h>
29 #include <linux/jiffies.h>
30 #include <linux/kthread.h>
31 #include <linux/keyboard.h> /* for KT_SHIFT */
32 #include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
33 #include <linux/input.h>
34 #include <linux/kmod.h>
36 /* speakup_*_selection */
37 #include <linux/module.h>
38 #include <linux/sched.h>
39 #include <linux/slab.h>
40 #include <linux/types.h>
41 #include <linux/consolemap.h>
43 #include <linux/spinlock.h>
44 #include <linux/notifier.h>
46 #include <linux/uaccess.h> /* copy_from|to|user() and others */
51 #define MAX_DELAY msecs_to_jiffies(500)
52 #define MINECHOCHAR SPACE
56 MODULE_DESCRIPTION("Speakup console speech");
57 MODULE_LICENSE("GPL");
58 MODULE_VERSION(SPEAKUP_VERSION);
61 module_param_named(synth, synth_name, charp, 0444);
62 module_param_named(quiet, spk_quiet_boot, bool, 0444);
64 MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
65 MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
67 special_func spk_special_handler;
69 short spk_pitch_shift, synth_flags;
71 int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
72 int spk_no_intr, spk_spell_delay;
73 int spk_key_echo, spk_say_word_ctl;
74 int spk_say_ctrl, spk_bell_pos;
76 int spk_punc_level, spk_reading_punc;
77 char spk_str_caps_start[MAXVARLEN + 1] = "\0";
78 char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
79 const struct st_bits_data spk_punc_info[] = {
81 {"some", "/$%&@", SOME},
82 {"most", "$%&#()=+*/@^<>|\\", MOST},
83 {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
84 {"delimiters", "", B_WDLM},
85 {"repeats", "()", CH_RPT},
86 {"extended numeric", "", B_EXNUM},
87 {"symbols", "", B_SYM},
91 static char mark_cut_flag;
93 static u_char *spk_shift_table;
94 u_char *spk_our_keys[MAX_KEY];
95 u_char spk_key_buf[600];
96 const u_char spk_key_defaults[] = {
97 #include "speakupmap.h"
100 /* Speakup Cursor Track Variables */
101 static int cursor_track = 1, prev_cursor_track = 1;
103 /* cursor track modes, must be ordered same as cursor_msgs */
112 #define read_all_mode CT_Max
114 static struct tty_struct *tty;
116 static void spkup_write(const u16 *in_buf, int count);
118 static char *phonetic[] = {
119 "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
120 "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
122 "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
123 "x ray", "yankee", "zulu"
126 /* array of 256 char pointers (one for each character description)
127 * initialized to default_chars and user selectable via
128 * /proc/speakup/characters
130 char *spk_characters[256];
132 char *spk_default_chars[256] = {
133 /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
134 /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
135 /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
136 /*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
138 /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
140 /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
143 /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
145 /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
146 /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
147 /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
148 /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
149 /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
152 /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
153 /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
154 /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
155 /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
156 /*127*/ "del", "control", "control", "control", "control", "control",
157 "control", "control", "control", "control", "control",
158 /*138*/ "control", "control", "control", "control", "control",
159 "control", "control", "control", "control", "control",
160 "control", "control",
161 /*150*/ "control", "control", "control", "control", "control",
162 "control", "control", "control", "control", "control",
163 /*160*/ "nbsp", "inverted bang",
164 /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
165 /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
166 /*172*/ "not", "soft hyphen", "registered", "macron",
167 /*176*/ "degrees", "plus or minus", "super two", "super three",
168 /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
169 /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
170 /*188*/ "one quarter", "one half", "three quarters",
172 /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
174 /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
176 /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
178 /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
179 /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
181 /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
182 /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
183 /*230*/ "ae", "c cidella", "e grave", "e acute",
184 /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
186 /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
188 /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
190 /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
193 /* array of 256 u_short (one for each character)
194 * initialized to default_chartab and user selectable via
195 * /sys/module/speakup/parameters/chartab
197 u_short spk_chartab[256];
199 static u_short default_chartab[256] = {
200 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
201 B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
202 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
203 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
204 WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */
205 PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */
206 NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
207 NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */
208 PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */
209 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
210 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
211 A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */
212 PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */
213 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
214 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
215 ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
216 B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
218 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
220 B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
222 B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
224 WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
226 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
227 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
228 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
229 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
230 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
231 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
232 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
233 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
234 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
235 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
236 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */
239 struct task_struct *speakup_task;
240 struct bleep spk_unprocessed_sound;
241 static int spk_keydown;
242 static u16 spk_lastkey;
243 static u_char 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(struct vc_data *vc, u16 *pos)
267 pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
268 return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8;
271 static void speakup_date(struct vc_data *vc)
273 spk_x = spk_cx = vc->vc_x;
274 spk_y = spk_cy = vc->vc_y;
275 spk_pos = spk_cp = vc->vc_pos;
276 spk_old_attr = spk_attr;
277 spk_attr = get_attributes(vc, (u_short *)spk_pos);
280 static void bleep(u_short val)
282 static const short vals[] = {
283 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
286 int time = spk_bleep_time;
288 freq = vals[val % 12];
290 freq *= (1 << (val / 12));
291 spk_unprocessed_sound.freq = freq;
292 spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
293 spk_unprocessed_sound.active = 1;
294 /* We can only have 1 active sound at a time. */
297 static void speakup_shut_up(struct vc_data *vc)
308 static void speech_kill(struct vc_data *vc)
310 char val = synth->is_alive(synth);
315 /* re-enables synth, if disabled */
316 if (val == 2 || spk_killed) {
318 spk_shut_up &= ~0x40;
319 synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
321 synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
326 static void speakup_off(struct vc_data *vc)
328 if (spk_shut_up & 0x80) {
330 synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
333 synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
338 static void speakup_parked(struct vc_data *vc)
340 if (spk_parked & 0x80) {
342 synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
345 synth_printf("%s\n", spk_msg_get(MSG_PARKED));
349 static void speakup_cut(struct vc_data *vc)
351 static const char err_buf[] = "set selection failed";
354 if (!mark_cut_flag) {
356 spk_xs = (u_short)spk_x;
357 spk_ys = (u_short)spk_y;
359 synth_printf("%s\n", spk_msg_get(MSG_MARK));
362 spk_xe = (u_short)spk_x;
363 spk_ye = (u_short)spk_y;
365 synth_printf("%s\n", spk_msg_get(MSG_CUT));
367 speakup_clear_selection();
368 ret = speakup_set_selection(tty);
372 break; /* no error */
374 pr_warn("%sEFAULT\n", err_buf);
377 pr_warn("%sEINVAL\n", err_buf);
380 pr_warn("%sENOMEM\n", err_buf);
385 static void speakup_paste(struct vc_data *vc)
389 synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
391 synth_printf("%s\n", spk_msg_get(MSG_PASTE));
392 speakup_paste_selection(tty);
396 static void say_attributes(struct vc_data *vc)
398 int fg = spk_attr & 0x0f;
399 int bg = spk_attr >> 4;
402 synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
405 synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
407 synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
410 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(u16 ch)
435 struct var_t *direct = spk_get_var(DIRECT);
437 if (ch >= 0x100 || (direct && direct->u.n.value)) {
438 if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
440 synth_printf("%s", spk_str_caps_start);
443 if (ch < 0x100 && IS_CHAR(ch, B_CAP))
444 synth_printf("%s", spk_str_caps_stop);
448 cp = spk_characters[ch];
450 pr_info("speak_char: cp == NULL!\n");
453 if (IS_CHAR(ch, B_CAP)) {
455 synth_printf("%s %s %s",
456 spk_str_caps_start, cp, spk_str_caps_stop);
460 synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp);
462 synth_printf(" %s ", cp);
466 static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
474 pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
478 if (w & vc->vc_hi_font_mask) {
479 w &= ~vc->vc_hi_font_mask;
483 ch = inverse_translate(vc, c, 1);
484 *attribs = (w & 0xff00) >> 8;
489 static void say_char(struct vc_data *vc)
493 spk_old_attr = spk_attr;
494 ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
495 if (spk_attr != spk_old_attr) {
496 if (spk_attrib_bleep & 1)
498 if (spk_attrib_bleep & 2)
504 static void say_phonetic_char(struct vc_data *vc)
508 spk_old_attr = spk_attr;
509 ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
510 if (ch <= 0x7f && isalpha(ch)) {
512 synth_printf("%s\n", phonetic[--ch]);
514 if (ch < 0x100 && IS_CHAR(ch, B_NUM))
515 synth_printf("%s ", spk_msg_get(MSG_NUMBER));
520 static void say_prev_char(struct vc_data *vc)
524 announce_edge(vc, edge_left);
532 static void say_next_char(struct vc_data *vc)
535 if (spk_x == vc->vc_cols - 1) {
536 announce_edge(vc, edge_right);
544 /* get_word - will first check to see if the character under the
545 * reading cursor is a space and if spk_say_word_ctl is true it will
546 * return the word space. If spk_say_word_ctl is not set it will check to
547 * see if there is a word starting on the next position to the right
548 * and return that word if it exists. If it does not exist it will
549 * move left to the beginning of any previous word on the line or the
550 * beginning off the line whichever comes first..
553 static u_long get_word(struct vc_data *vc)
555 u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
560 spk_old_attr = spk_attr;
561 ch = get_char(vc, (u_short *)tmp_pos, &temp);
563 /* decided to take out the sayword if on a space (mis-information */
564 if (spk_say_word_ctl && ch == SPACE) {
566 synth_printf("%s\n", spk_msg_get(MSG_SPACE));
568 } else if (tmpx < vc->vc_cols - 2 &&
569 (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
570 get_char(vc, (u_short *)&tmp_pos + 1, &temp) > SPACE) {
575 ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
576 if ((ch == SPACE || ch == 0 ||
577 (ch < 0x100 && IS_WDLM(ch))) &&
578 get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
583 attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
584 buf[cnt++] = attr_ch;
585 while (tmpx < vc->vc_cols - 1) {
588 ch = get_char(vc, (u_short *)tmp_pos, &temp);
589 if (ch == SPACE || ch == 0 ||
590 (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
599 static void say_word(struct vc_data *vc)
601 u_long cnt = get_word(vc);
602 u_short saved_punc_mask = spk_punc_mask;
606 spk_punc_mask = PUNC;
608 spkup_write(buf, cnt);
609 spk_punc_mask = saved_punc_mask;
612 static void say_prev_word(struct vc_data *vc)
616 u_short edge_said = 0, last_state = 0, state = 0;
622 announce_edge(vc, edge_top);
627 edge_said = edge_quiet;
632 edge_said = edge_top;
635 if (edge_said != edge_quiet)
636 edge_said = edge_left;
640 spk_x = vc->vc_cols - 1;
645 ch = get_char(vc, (u_short *)spk_pos, &temp);
646 if (ch == SPACE || ch == 0)
648 else if (ch < 0x100 && IS_WDLM(ch))
652 if (state < last_state) {
659 if (spk_x == 0 && edge_said == edge_quiet)
660 edge_said = edge_left;
661 if (edge_said > 0 && edge_said < edge_quiet)
662 announce_edge(vc, edge_said);
666 static void say_next_word(struct vc_data *vc)
670 u_short edge_said = 0, last_state = 2, state = 0;
673 if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
674 announce_edge(vc, edge_bottom);
678 ch = get_char(vc, (u_short *)spk_pos, &temp);
679 if (ch == SPACE || ch == 0)
681 else if (ch < 0x100 && IS_WDLM(ch))
685 if (state > last_state)
687 if (spk_x >= vc->vc_cols - 1) {
688 if (spk_y == vc->vc_rows - 1) {
689 edge_said = edge_bottom;
695 edge_said = edge_right;
703 announce_edge(vc, edge_said);
707 static void spell_word(struct vc_data *vc)
709 static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
712 char *str_cap = spk_str_caps_stop;
713 char *last_cap = spk_str_caps_stop;
714 struct var_t *direct = spk_get_var(DIRECT);
721 synth_printf(" %s ", delay_str[spk_spell_delay]);
722 /* FIXME: Non-latin1 considered as lower case */
723 if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
724 str_cap = spk_str_caps_start;
725 if (*spk_str_caps_stop)
727 else /* synth has no pitch */
728 last_cap = spk_str_caps_stop;
730 str_cap = spk_str_caps_stop;
732 if (str_cap != last_cap) {
733 synth_printf("%s", str_cap);
736 if (ch >= 0x100 || (direct && direct->u.n.value)) {
738 } else if (this_speakup_key == SPELL_PHONETIC &&
739 ch <= 0x7f && isalpha(ch)) {
741 cp1 = phonetic[--ch];
742 synth_printf("%s", cp1);
744 cp1 = spk_characters[ch];
746 synth_printf("%s", spk_msg_get(MSG_CTRL));
749 synth_printf("%s", cp1);
753 if (str_cap != spk_str_caps_stop)
754 synth_printf("%s", spk_str_caps_stop);
757 static int get_line(struct vc_data *vc)
759 u_long tmp = spk_pos - (spk_x * 2);
763 spk_old_attr = spk_attr;
764 spk_attr = get_attributes(vc, (u_short *)spk_pos);
765 for (i = 0; i < vc->vc_cols; i++) {
766 buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
769 for (--i; i >= 0; i--)
775 static void say_line(struct vc_data *vc)
777 int i = get_line(vc);
779 u_short saved_punc_mask = spk_punc_mask;
782 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
786 if (this_speakup_key == SAY_LINE_INDENT) {
790 synth_printf("%zd, ", (cp - buf) + 1);
792 spk_punc_mask = spk_punc_masks[spk_reading_punc];
794 spk_punc_mask = saved_punc_mask;
797 static void say_prev_line(struct vc_data *vc)
801 announce_edge(vc, edge_top);
805 spk_pos -= vc->vc_size_row;
809 static void say_next_line(struct vc_data *vc)
812 if (spk_y == vc->vc_rows - 1) {
813 announce_edge(vc, edge_bottom);
817 spk_pos += vc->vc_size_row;
821 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
826 u_short saved_punc_mask = spk_punc_mask;
828 spk_old_attr = spk_attr;
829 spk_attr = get_attributes(vc, (u_short *)from);
831 buf[i++] = get_char(vc, (u_short *)from, &tmp);
833 if (i >= vc->vc_size_row)
836 for (--i; i >= 0; i--)
844 spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
847 spk_punc_mask = saved_punc_mask;
851 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
854 u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
855 u_long end = start + (to * 2);
858 if (say_from_to(vc, start, end, read_punc) <= 0)
859 if (cursor_track != read_all_mode)
860 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
863 /* Sentence Reading Commands */
865 static int currsentence;
866 static int numsentences[2];
867 static u16 *sentbufend[2];
868 static u16 *sentmarks[2][10];
871 static u16 sentbuf[2][256];
873 static int say_sentence_num(int num, int prev)
876 currsentence = num + 1;
877 if (prev && --bn == -1)
880 if (num > numsentences[bn])
883 spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
887 static int get_sentence_buf(struct vc_data *vc, int read_punc)
897 start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
898 end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
900 numsentences[bn] = 0;
901 sentmarks[bn][0] = &sentbuf[bn][0];
903 spk_old_attr = spk_attr;
904 spk_attr = get_attributes(vc, (u_short *)start);
906 while (start < end) {
907 sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
909 if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.' &&
910 numsentences[bn] < 9) {
911 /* Sentence Marker */
913 sentmarks[bn][numsentences[bn]] =
919 if (i >= vc->vc_size_row)
923 for (--i; i >= 0; i--)
924 if (sentbuf[bn][i] != SPACE)
930 sentbuf[bn][++i] = SPACE;
931 sentbuf[bn][++i] = '\0';
933 sentbufend[bn] = &sentbuf[bn][i];
934 return numsentences[bn];
937 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
939 u_long start = vc->vc_origin, end;
942 start += from * vc->vc_size_row;
943 if (to > vc->vc_rows)
945 end = vc->vc_origin + (to * vc->vc_size_row);
946 for (from = start; from < end; from = to) {
947 to = from + vc->vc_size_row;
948 say_from_to(vc, from, to, 1);
952 static void say_screen(struct vc_data *vc)
954 say_screen_from_to(vc, 0, vc->vc_rows);
957 static void speakup_win_say(struct vc_data *vc)
959 u_long start, end, from, to;
962 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
965 start = vc->vc_origin + (win_top * vc->vc_size_row);
966 end = vc->vc_origin + (win_bottom * vc->vc_size_row);
967 while (start <= end) {
968 from = start + (win_left * 2);
969 to = start + (win_right * 2);
970 say_from_to(vc, from, to, 1);
971 start += vc->vc_size_row;
975 static void top_edge(struct vc_data *vc)
978 spk_pos = vc->vc_origin + 2 * spk_x;
983 static void bottom_edge(struct vc_data *vc)
986 spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
987 spk_y = vc->vc_rows - 1;
991 static void left_edge(struct vc_data *vc)
994 spk_pos -= spk_x * 2;
999 static void right_edge(struct vc_data *vc)
1002 spk_pos += (vc->vc_cols - spk_x - 1) * 2;
1003 spk_x = vc->vc_cols - 1;
1007 static void say_first_char(struct vc_data *vc)
1009 int i, len = get_line(vc);
1014 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1017 for (i = 0; i < len; i++)
1018 if (buf[i] != SPACE)
1021 spk_pos -= (spk_x - i) * 2;
1023 synth_printf("%d, ", ++i);
1027 static void say_last_char(struct vc_data *vc)
1029 int len = get_line(vc);
1034 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1038 spk_pos -= (spk_x - len) * 2;
1040 synth_printf("%d, ", ++len);
1044 static void say_position(struct vc_data *vc)
1046 synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1051 /* Added by brianb */
1052 static void say_char_num(struct vc_data *vc)
1055 u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);
1057 synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1060 /* these are stub functions to keep keyboard.c happy. */
1062 static void say_from_top(struct vc_data *vc)
1064 say_screen_from_to(vc, 0, spk_y);
1067 static void say_to_bottom(struct vc_data *vc)
1069 say_screen_from_to(vc, spk_y, vc->vc_rows);
1072 static void say_from_left(struct vc_data *vc)
1074 say_line_from_to(vc, 0, spk_x, 1);
1077 static void say_to_right(struct vc_data *vc)
1079 say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1082 /* end of stub functions. */
1084 static void spkup_write(const u16 *in_buf, int count)
1086 static int rep_count;
1087 static u16 ch = '\0', old_ch = '\0';
1088 static u_short char_type, last_type;
1089 int in_count = count;
1093 if (cursor_track == read_all_mode) {
1094 /* Insert Sentence Index */
1095 if ((in_buf == sentmarks[bn][currsentence]) &&
1096 (currsentence <= numsentences[bn]))
1097 synth_insert_next_index(currsentence++);
1101 char_type = spk_chartab[ch];
1104 if (ch == old_ch && !(char_type & B_NUM)) {
1105 if (++rep_count > 2)
1108 if ((last_type & CH_RPT) && rep_count > 2) {
1110 synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1116 if (ch == spk_lastkey) {
1118 if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1120 } else if (char_type & B_ALPHA) {
1121 if ((synth_flags & SF_DEC) && (last_type & PUNC))
1122 synth_buffer_add(SPACE);
1124 } else if (char_type & B_NUM) {
1127 } else if (char_type & spk_punc_mask) {
1129 char_type &= ~PUNC; /* for dec nospell processing */
1130 } else if (char_type & SYNTH_OK) {
1131 /* these are usually puncts like . and , which synth
1132 * needs for expression.
1133 * suppress multiple to get rid of long pauses and
1134 * clear repeat count
1136 * repeats on you don't get nothing repeated count
1143 /* send space and record position, if next is num overwrite space */
1145 synth_buffer_add(SPACE);
1150 last_type = char_type;
1153 if (in_count > 2 && rep_count > 2) {
1154 if (last_type & CH_RPT) {
1156 synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
1164 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1166 static void read_all_doc(struct vc_data *vc);
1167 static void cursor_done(u_long data);
1168 static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1170 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1172 unsigned long flags;
1174 if (!synth || up_flag || spk_killed)
1176 spin_lock_irqsave(&speakup_info.spinlock, flags);
1177 if (cursor_track == read_all_mode) {
1180 del_timer(&cursor_timer);
1181 spk_shut_up &= 0xfe;
1186 del_timer(&cursor_timer);
1187 cursor_track = prev_cursor_track;
1188 spk_shut_up &= 0xfe;
1193 spk_shut_up &= 0xfe;
1196 if (spk_say_ctrl && value < NUM_CTL_LABELS)
1197 synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1198 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1201 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1203 unsigned long flags;
1205 spin_lock_irqsave(&speakup_info.spinlock, flags);
1209 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1212 if (!synth || spk_killed) {
1213 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1216 spk_shut_up &= 0xfe;
1217 spk_lastkey = value;
1220 if (spk_key_echo == 2 && value >= MINECHOCHAR)
1222 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1225 int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1227 int i = 0, states, key_data_len;
1228 const u_char *cp = key_info;
1229 u_char *cp1 = k_buffer;
1230 u_char ch, version, num_keys;
1233 if (version != KEY_MAP_VER) {
1234 pr_debug("version found %d should be %d\n",
1235 version, KEY_MAP_VER);
1239 states = (int)cp[1];
1240 key_data_len = (states + 1) * (num_keys + 1);
1241 if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
1242 pr_debug("too many key_infos (%d over %u)\n",
1243 key_data_len + SHIFT_TBL_SIZE + 4, (unsigned int)(sizeof(spk_key_buf)));
1246 memset(k_buffer, 0, SHIFT_TBL_SIZE);
1247 memset(spk_our_keys, 0, sizeof(spk_our_keys));
1248 spk_shift_table = k_buffer;
1249 spk_our_keys[0] = spk_shift_table;
1250 cp1 += SHIFT_TBL_SIZE;
1251 memcpy(cp1, cp, key_data_len + 3);
1252 /* get num_keys, states and data */
1253 cp1 += 2; /* now pointing at shift states */
1254 for (i = 1; i <= states; i++) {
1256 if (ch >= SHIFT_TBL_SIZE) {
1257 pr_debug("(%d) not valid shift state (max_allowed = %d)\n", ch,
1261 spk_shift_table[ch] = i;
1263 keymap_flags = *cp1++;
1264 while ((ch = *cp1)) {
1265 if (ch >= MAX_KEY) {
1266 pr_debug("(%d), not valid key, (max_allowed = %d)\n", ch, MAX_KEY);
1269 spk_our_keys[ch] = cp1;
1275 static struct var_t spk_vars[] = {
1276 /* bell must be first to set high limit */
1277 {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1278 {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1279 {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1280 {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1281 {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1282 {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1283 {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1284 {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1285 {SAY_CONTROL, TOGGLE_0},
1286 {SAY_WORD_CTL, TOGGLE_0},
1287 {NO_INTERRUPT, TOGGLE_0},
1288 {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1292 static void toggle_cursoring(struct vc_data *vc)
1294 if (cursor_track == read_all_mode)
1295 cursor_track = prev_cursor_track;
1296 if (++cursor_track >= CT_Max)
1298 synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1301 void spk_reset_default_chars(void)
1305 /* First, free any non-default */
1306 for (i = 0; i < 256; i++) {
1307 if (spk_characters[i] &&
1308 (spk_characters[i] != spk_default_chars[i]))
1309 kfree(spk_characters[i]);
1312 memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1315 void spk_reset_default_chartab(void)
1317 memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1320 static const struct st_bits_data *pb_edit;
1322 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1324 short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1326 if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1329 synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1330 spk_special_handler = NULL;
1333 if (mask < PUNC && !(ch_type & PUNC))
1335 spk_chartab[ch] ^= mask;
1337 synth_printf(" %s\n",
1338 (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1339 spk_msg_get(MSG_OFF));
1343 /* Allocation concurrency is protected by the console semaphore */
1344 static int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags)
1348 vc_num = vc->vc_num;
1349 if (!speakup_console[vc_num]) {
1350 speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1352 if (!speakup_console[vc_num])
1355 } else if (!spk_parked) {
1362 static void speakup_deallocate(struct vc_data *vc)
1366 vc_num = vc->vc_num;
1367 kfree(speakup_console[vc_num]);
1368 speakup_console[vc_num] = NULL;
1371 static u_char is_cursor;
1372 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1373 static int cursor_con;
1375 static void reset_highlight_buffers(struct vc_data *);
1377 static int read_all_key;
1379 static int in_keyboard_notifier;
1381 static void start_read_all_timer(struct vc_data *vc, int command);
1395 static void kbd_fakekey2(struct vc_data *vc, int command)
1397 del_timer(&cursor_timer);
1398 speakup_fake_down_arrow();
1399 start_read_all_timer(vc, command);
1402 static void read_all_doc(struct vc_data *vc)
1404 if ((vc->vc_num != fg_console) || !synth || spk_shut_up)
1406 if (!synth_supports_indexing())
1408 if (cursor_track != read_all_mode)
1409 prev_cursor_track = cursor_track;
1410 cursor_track = read_all_mode;
1411 spk_reset_index_count(0);
1412 if (get_sentence_buf(vc, 0) == -1) {
1413 del_timer(&cursor_timer);
1414 if (!in_keyboard_notifier)
1415 speakup_fake_down_arrow();
1416 start_read_all_timer(vc, RA_DOWN_ARROW);
1418 say_sentence_num(0, 0);
1419 synth_insert_next_index(0);
1420 start_read_all_timer(vc, RA_TIMER);
1424 static void stop_read_all(struct vc_data *vc)
1426 del_timer(&cursor_timer);
1427 cursor_track = prev_cursor_track;
1428 spk_shut_up &= 0xfe;
1432 static void start_read_all_timer(struct vc_data *vc, int command)
1434 struct var_t *cursor_timeout;
1436 cursor_con = vc->vc_num;
1437 read_all_key = command;
1438 cursor_timeout = spk_get_var(CURSOR_TIME);
1439 mod_timer(&cursor_timer,
1440 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1443 static void handle_cursor_read_all(struct vc_data *vc, int command)
1445 int indcount, sentcount, rv, sn;
1449 /* Get Current Sentence */
1450 spk_get_index_count(&indcount, &sentcount);
1451 /*printk("%d %d ", indcount, sentcount); */
1452 spk_reset_index_count(sentcount + 1);
1453 if (indcount == 1) {
1454 if (!say_sentence_num(sentcount + 1, 0)) {
1455 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1458 synth_insert_next_index(0);
1461 if (!say_sentence_num(sentcount + 1, 1)) {
1463 spk_reset_index_count(sn);
1465 synth_insert_next_index(0);
1467 if (!say_sentence_num(sn, 0)) {
1468 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1471 synth_insert_next_index(0);
1473 start_read_all_timer(vc, RA_TIMER);
1483 if (get_sentence_buf(vc, 0) == -1) {
1484 kbd_fakekey2(vc, RA_DOWN_ARROW);
1486 say_sentence_num(0, 0);
1487 synth_insert_next_index(0);
1488 start_read_all_timer(vc, RA_TIMER);
1491 case RA_FIND_NEXT_SENT:
1492 rv = get_sentence_buf(vc, 0);
1496 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1498 say_sentence_num(1, 0);
1499 synth_insert_next_index(0);
1500 start_read_all_timer(vc, RA_TIMER);
1503 case RA_FIND_PREV_SENT:
1506 spk_get_index_count(&indcount, &sentcount);
1508 kbd_fakekey2(vc, RA_DOWN_ARROW);
1510 start_read_all_timer(vc, RA_TIMER);
1515 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1517 unsigned long flags;
1519 spin_lock_irqsave(&speakup_info.spinlock, flags);
1520 if (cursor_track == read_all_mode) {
1522 if (!synth || up_flag || spk_shut_up) {
1523 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1526 del_timer(&cursor_timer);
1527 spk_shut_up &= 0xfe;
1529 start_read_all_timer(vc, value + 1);
1530 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1533 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1537 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1539 unsigned long flags;
1540 struct var_t *cursor_timeout;
1542 spin_lock_irqsave(&speakup_info.spinlock, flags);
1544 if (!synth || up_flag || spk_shut_up || cursor_track == CT_Off) {
1545 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1548 spk_shut_up &= 0xfe;
1551 /* the key press flushes if !no_inter but we want to flush on cursor
1552 * moves regardless of no_inter state
1554 is_cursor = value + 1;
1555 old_cursor_pos = vc->vc_pos;
1556 old_cursor_x = vc->vc_x;
1557 old_cursor_y = vc->vc_y;
1558 speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1559 cursor_con = vc->vc_num;
1560 if (cursor_track == CT_Highlight)
1561 reset_highlight_buffers(vc);
1562 cursor_timeout = spk_get_var(CURSOR_TIME);
1563 mod_timer(&cursor_timer,
1564 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1565 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1568 static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
1571 int vc_num = vc->vc_num;
1573 bi = (vc->vc_attr & 0x70) >> 4;
1574 hi = speakup_console[vc_num]->ht.highsize[bi];
1577 if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1578 speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1579 speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1580 speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1582 while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1584 speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1586 } else if ((ic[i] == 32) && (hi != 0)) {
1587 if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1589 speakup_console[vc_num]->ht.highbuf[bi][hi] =
1596 speakup_console[vc_num]->ht.highsize[bi] = hi;
1599 static void reset_highlight_buffers(struct vc_data *vc)
1602 int vc_num = vc->vc_num;
1604 for (i = 0; i < 8; i++)
1605 speakup_console[vc_num]->ht.highsize[i] = 0;
1608 static int count_highlight_color(struct vc_data *vc)
1612 int vc_num = vc->vc_num;
1614 u16 *start = (u16 *)vc->vc_origin;
1616 for (i = 0; i < 8; i++)
1617 speakup_console[vc_num]->ht.bgcount[i] = 0;
1619 for (i = 0; i < vc->vc_rows; i++) {
1620 u16 *end = start + vc->vc_cols * 2;
1623 for (ptr = start; ptr < end; ptr++) {
1624 ch = get_attributes(vc, ptr);
1625 bg = (ch & 0x70) >> 4;
1626 speakup_console[vc_num]->ht.bgcount[bg]++;
1628 start += vc->vc_size_row;
1632 for (i = 0; i < 8; i++)
1633 if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1638 static int get_highlight_color(struct vc_data *vc)
1641 unsigned int cptr[8];
1642 int vc_num = vc->vc_num;
1644 for (i = 0; i < 8; i++)
1647 for (i = 0; i < 7; i++)
1648 for (j = i + 1; j < 8; j++)
1649 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1650 speakup_console[vc_num]->ht.bgcount[cptr[j]])
1651 swap(cptr[i], cptr[j]);
1653 for (i = 0; i < 8; i++)
1654 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1655 if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1660 static int speak_highlight(struct vc_data *vc)
1663 int vc_num = vc->vc_num;
1665 if (count_highlight_color(vc) == 1)
1667 hc = get_highlight_color(vc);
1669 d = vc->vc_y - speakup_console[vc_num]->ht.cy;
1670 if ((d == 1) || (d == -1))
1671 if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1675 spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1676 speakup_console[vc_num]->ht.highsize[hc]);
1677 spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1678 spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1679 spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1685 static void cursor_done(u_long data)
1687 struct vc_data *vc = vc_cons[cursor_con].d;
1688 unsigned long flags;
1690 del_timer(&cursor_timer);
1691 spin_lock_irqsave(&speakup_info.spinlock, flags);
1692 if (cursor_con != fg_console) {
1698 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1699 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1705 if (cursor_track == read_all_mode) {
1706 handle_cursor_read_all(vc, read_all_key);
1709 if (cursor_track == CT_Highlight) {
1710 if (speak_highlight(vc)) {
1716 if (cursor_track == CT_Window)
1717 speakup_win_say(vc);
1718 else if (is_cursor == 1 || is_cursor == 4)
1719 say_line_from_to(vc, 0, vc->vc_cols, 0);
1725 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1728 /* called by: vt_notifier_call() */
1729 static void speakup_bs(struct vc_data *vc)
1731 unsigned long flags;
1733 if (!speakup_console[vc->vc_num])
1735 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1736 /* Speakup output, discard */
1740 if (spk_shut_up || !synth) {
1741 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1744 if (vc->vc_num == fg_console && spk_keydown) {
1749 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1752 /* called by: vt_notifier_call() */
1753 static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
1755 unsigned long flags;
1757 if ((vc->vc_num != fg_console) || spk_shut_up || !synth)
1759 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1760 /* Speakup output, discard */
1762 if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
1764 if ((is_cursor) || (cursor_track == read_all_mode)) {
1765 if (cursor_track == CT_Highlight)
1766 update_color_buffer(vc, str, len);
1767 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1771 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1772 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1773 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1778 spkup_write(str, len);
1779 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1782 static void speakup_con_update(struct vc_data *vc)
1784 unsigned long flags;
1786 if (!speakup_console[vc->vc_num] || spk_parked)
1788 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1789 /* Speakup output, discard */
1792 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1795 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1797 unsigned long flags;
1801 if (!synth || up_flag || spk_killed)
1803 spin_lock_irqsave(&speakup_info.spinlock, flags);
1804 spk_shut_up &= 0xfe;
1809 label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1810 on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1813 label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1814 on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1817 label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1818 on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1819 if (speakup_console[vc->vc_num])
1820 speakup_console[vc->vc_num]->tty_stopped = on_off;
1824 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1828 synth_printf("%s %s\n",
1829 label, spk_msg_get(MSG_STATUS_START + on_off));
1830 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1833 static int inc_dec_var(u_char value)
1835 struct st_var_header *p_header;
1836 struct var_t *var_data;
1840 int var_id = (int)value - VAR_START;
1841 int how = (var_id & 1) ? E_INC : E_DEC;
1843 var_id = var_id / 2 + FIRST_SET_VAR;
1844 p_header = spk_get_var_header(var_id);
1847 if (p_header->var_type != VAR_NUM)
1849 var_data = p_header->data;
1850 if (spk_set_num_var(1, p_header, how) != 0)
1852 if (!spk_close_press) {
1853 for (pn = p_header->name; *pn; pn++) {
1860 snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1861 var_data->u.n.value);
1862 synth_printf("%s", num_buf);
1866 static void speakup_win_set(struct vc_data *vc)
1870 if (win_start > 1) {
1871 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1874 if (spk_x < win_left || spk_y < win_top) {
1875 synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1878 if (win_start && spk_x == win_left && spk_y == win_top) {
1880 win_right = vc->vc_cols - 1;
1882 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1892 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1894 spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1895 (int)spk_y + 1, (int)spk_x + 1);
1897 synth_printf("%s\n", info);
1901 static void speakup_win_clear(struct vc_data *vc)
1908 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1911 static void speakup_win_enable(struct vc_data *vc)
1913 if (win_start < 2) {
1914 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1919 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1921 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1924 static void speakup_bits(struct vc_data *vc)
1926 int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1928 if (spk_special_handler || val < 1 || val > 6) {
1929 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1932 pb_edit = &spk_punc_info[val];
1933 synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1934 spk_special_handler = edit_bits;
1937 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1939 static u_char goto_buf[8];
1945 if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1947 if (type == KT_LATIN && ch == '\n')
1956 wch = goto_buf[--num];
1957 goto_buf[num] = '\0';
1958 spkup_write(&wch, 1);
1961 if (ch < '+' || ch > 'y')
1964 goto_buf[num++] = ch;
1965 goto_buf[num] = '\0';
1966 spkup_write(&wch, 1);
1967 maxlen = (*goto_buf >= '0') ? 3 : 4;
1968 if ((ch == '+' || ch == '-') && num == 1)
1970 if (ch >= '0' && ch <= '9' && num < maxlen)
1972 if (num < maxlen - 1 || num > maxlen)
1974 if (ch < 'x' || ch > 'y') {
1977 synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1978 goto_buf[num = 0] = '\0';
1979 spk_special_handler = NULL;
1983 goto_pos = simple_strtoul(goto_buf, &cp, 10);
1986 if (*goto_buf < '0')
1988 else if (goto_pos > 0)
1991 if (goto_pos >= vc->vc_cols)
1992 goto_pos = vc->vc_cols - 1;
1995 if (*goto_buf < '0')
1997 else if (goto_pos > 0)
2000 if (goto_pos >= vc->vc_rows)
2001 goto_pos = vc->vc_rows - 1;
2004 goto_buf[num = 0] = '\0';
2006 spk_special_handler = NULL;
2009 spk_pos -= spk_x * 2;
2011 spk_pos += goto_pos * 2;
2015 spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
2021 static void speakup_goto(struct vc_data *vc)
2023 if (spk_special_handler) {
2024 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
2027 synth_printf("%s\n", spk_msg_get(MSG_GOTO));
2028 spk_special_handler = handle_goto;
2031 static void speakup_help(struct vc_data *vc)
2033 spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
2036 static void do_nothing(struct vc_data *vc)
2038 return; /* flush done in do_spkup */
2041 static u_char key_speakup, spk_key_locked;
2043 static void speakup_lock(struct vc_data *vc)
2045 if (!spk_key_locked) {
2046 spk_key_locked = 16;
2054 typedef void (*spkup_hand) (struct vc_data *);
2055 static spkup_hand spkup_handler[] = {
2056 /* must be ordered same as defines in speakup.h */
2057 do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2058 speakup_cut, speakup_paste, say_first_char, say_last_char,
2059 say_char, say_prev_char, say_next_char,
2060 say_word, say_prev_word, say_next_word,
2061 say_line, say_prev_line, say_next_line,
2062 top_edge, bottom_edge, left_edge, right_edge,
2063 spell_word, spell_word, say_screen,
2064 say_position, say_attributes,
2065 speakup_off, speakup_parked, say_line, /* this is for indent */
2066 say_from_top, say_to_bottom,
2067 say_from_left, say_to_right,
2068 say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2069 speakup_bits, speakup_bits, speakup_bits,
2070 speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2071 speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2074 static void do_spkup(struct vc_data *vc, u_char value)
2076 if (spk_killed && value != SPEECH_KILL)
2080 spk_shut_up &= 0xfe;
2081 this_speakup_key = value;
2082 if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2084 (*spkup_handler[value]) (vc);
2086 if (inc_dec_var(value) < 0)
2091 static const char *pad_chars = "0123456789+-*/\015,.?()";
2094 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2097 unsigned long flags;
2100 u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2101 u_char shift_info, offset;
2107 spin_lock_irqsave(&speakup_info.spinlock, flags);
2111 if (type == KT_PAD &&
2112 (vt_get_leds(fg_console, VC_NUMLOCK))) {
2117 value = spk_lastkey = pad_chars[value];
2122 if (keycode >= MAX_KEY)
2124 key_info = spk_our_keys[keycode];
2127 /* Check valid read all mode keys */
2128 if ((cursor_track == read_all_mode) && (!up_flag)) {
2142 shift_info = (shift_state & 0x0f) + key_speakup;
2143 offset = spk_shift_table[shift_info];
2145 new_key = key_info[offset];
2148 if (new_key == SPK_KEY) {
2149 if (!spk_key_locked)
2150 key_speakup = (up_flag) ? 0 : 16;
2151 if (up_flag || spk_killed)
2153 spk_shut_up &= 0xfe;
2159 if (last_keycode == keycode &&
2160 time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2161 spk_close_press = 1;
2162 offset = spk_shift_table[shift_info + 32];
2164 if (offset && key_info[offset])
2165 new_key = key_info[offset];
2167 last_keycode = keycode;
2168 last_spk_jiffy = jiffies;
2174 if (type == KT_SPKUP && !spk_special_handler) {
2175 do_spkup(vc, new_key);
2176 spk_close_press = 0;
2180 if (up_flag || spk_killed || type == KT_SHIFT)
2182 spk_shut_up &= 0xfe;
2183 kh = (value == KVAL(K_DOWN)) ||
2184 (value == KVAL(K_UP)) ||
2185 (value == KVAL(K_LEFT)) ||
2186 (value == KVAL(K_RIGHT));
2187 if ((cursor_track != read_all_mode) || !kh)
2190 if (spk_special_handler) {
2191 if (type == KT_SPEC && value == 1) {
2194 } else if (type == KT_LETTER) {
2196 } else if (value == 0x7f) {
2197 value = 8; /* make del = backspace */
2199 ret = (*spk_special_handler) (vc, type, value, keycode);
2200 spk_close_press = 0;
2207 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2211 static int keyboard_notifier_call(struct notifier_block *nb,
2212 unsigned long code, void *_param)
2214 struct keyboard_notifier_param *param = _param;
2215 struct vc_data *vc = param->vc;
2216 int up = !param->down;
2217 int ret = NOTIFY_OK;
2218 static int keycode; /* to hold the current keycode */
2220 in_keyboard_notifier = 1;
2222 if (vc->vc_mode == KD_GRAPHICS)
2226 * First, determine whether we are handling a fake keypress on
2227 * the current processor. If we are, then return NOTIFY_OK,
2228 * to pass the keystroke up the chain. This prevents us from
2229 * trying to take the Speakup lock while it is held by the
2230 * processor on which the simulated keystroke was generated.
2231 * Also, the simulated keystrokes should be ignored by Speakup.
2234 if (speakup_fake_key_pressed())
2239 /* speakup requires keycode and keysym currently */
2240 keycode = param->value;
2242 case KBD_UNBOUND_KEYCODE:
2249 if (speakup_key(vc, param->shift, keycode, param->value, up))
2251 else if (KTYP(param->value) == KT_CUR)
2252 ret = pre_handle_cursor(vc, KVAL(param->value), up);
2254 case KBD_POST_KEYSYM:{
2255 unsigned char type = KTYP(param->value) - 0xf0;
2256 unsigned char val = KVAL(param->value);
2260 do_handle_shift(vc, val, up);
2264 do_handle_latin(vc, val, up);
2267 do_handle_cursor(vc, val, up);
2270 do_handle_spec(vc, val, up);
2277 in_keyboard_notifier = 0;
2281 static int vt_notifier_call(struct notifier_block *nb,
2282 unsigned long code, void *_param)
2284 struct vt_notifier_param *param = _param;
2285 struct vc_data *vc = param->vc;
2289 if (vc->vc_mode == KD_TEXT)
2290 speakup_allocate(vc, GFP_ATOMIC);
2293 speakup_deallocate(vc);
2296 if (param->c == '\b') {
2301 speakup_con_write(vc, &d, 1);
2305 speakup_con_update(vc);
2311 /* called by: module_exit() */
2312 static void __exit speakup_exit(void)
2316 unregister_keyboard_notifier(&keyboard_notifier_block);
2317 unregister_vt_notifier(&vt_notifier_block);
2318 speakup_unregister_devsynth();
2319 speakup_cancel_paste();
2320 del_timer_sync(&cursor_timer);
2321 kthread_stop(speakup_task);
2322 speakup_task = NULL;
2323 mutex_lock(&spk_mutex);
2325 mutex_unlock(&spk_mutex);
2326 spk_ttyio_unregister_ldisc();
2328 speakup_kobj_exit();
2330 for (i = 0; i < MAX_NR_CONSOLES; i++)
2331 kfree(speakup_console[i]);
2333 speakup_remove_virtual_keyboard();
2335 for (i = 0; i < MAXVARS; i++)
2336 speakup_unregister_var(i);
2338 for (i = 0; i < 256; i++) {
2339 if (spk_characters[i] != spk_default_chars[i])
2340 kfree(spk_characters[i]);
2343 spk_free_user_msgs();
2346 /* call by: module_init() */
2347 static int __init speakup_init(void)
2351 struct vc_data *vc = vc_cons[fg_console].d;
2354 /* These first few initializations cannot fail. */
2355 spk_initialize_msgs(); /* Initialize arrays for i18n. */
2356 spk_reset_default_chars();
2357 spk_reset_default_chartab();
2358 spk_strlwr(synth_name);
2359 spk_vars[0].u.n.high = vc->vc_cols;
2360 for (var = spk_vars; var->var_id != MAXVARS; var++)
2361 speakup_register_var(var);
2362 for (var = synth_time_vars;
2363 (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2364 speakup_register_var(var);
2365 for (i = 1; spk_punc_info[i].mask != 0; i++)
2366 spk_set_mask_bits(NULL, i, 2);
2368 spk_set_key_info(spk_key_defaults, spk_key_buf);
2370 /* From here on out, initializations can fail. */
2371 err = speakup_add_virtual_keyboard();
2373 goto error_virtkeyboard;
2375 for (i = 0; i < MAX_NR_CONSOLES; i++)
2377 err = speakup_allocate(vc_cons[i].d, GFP_KERNEL);
2379 goto error_kobjects;
2383 spk_shut_up |= 0x01;
2385 err = speakup_kobj_init();
2387 goto error_kobjects;
2389 spk_ttyio_register_ldisc();
2390 synth_init(synth_name);
2391 speakup_register_devsynth();
2393 * register_devsynth might fail, but this error is not fatal.
2394 * /dev/synth is an extra feature; the rest of Speakup
2395 * will work fine without it.
2398 err = register_keyboard_notifier(&keyboard_notifier_block);
2400 goto error_kbdnotifier;
2401 err = register_vt_notifier(&vt_notifier_block);
2403 goto error_vtnotifier;
2405 speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2407 if (IS_ERR(speakup_task)) {
2408 err = PTR_ERR(speakup_task);
2412 set_user_nice(speakup_task, 10);
2413 wake_up_process(speakup_task);
2415 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2416 pr_info("synth name on entry is: %s\n", synth_name);
2420 unregister_vt_notifier(&vt_notifier_block);
2423 unregister_keyboard_notifier(&keyboard_notifier_block);
2424 del_timer(&cursor_timer);
2427 speakup_unregister_devsynth();
2428 mutex_lock(&spk_mutex);
2430 mutex_unlock(&spk_mutex);
2431 speakup_kobj_exit();
2434 for (i = 0; i < MAX_NR_CONSOLES; i++)
2435 kfree(speakup_console[i]);
2437 speakup_remove_virtual_keyboard();
2440 for (i = 0; i < MAXVARS; i++)
2441 speakup_unregister_var(i);
2443 for (i = 0; i < 256; i++) {
2444 if (spk_characters[i] != spk_default_chars[i])
2445 kfree(spk_characters[i]);
2448 spk_free_user_msgs();
2454 module_init(speakup_init);
2455 module_exit(speakup_exit);