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 #include <linux/bootmem.h> /* for alloc_bootmem */
42 /* speakup_*_selection */
43 #include <linux/module.h>
44 #include <linux/sched.h>
45 #include <linux/slab.h>
46 #include <linux/types.h>
47 #include <linux/consolemap.h>
49 #include <linux/spinlock.h>
50 #include <linux/notifier.h>
52 #include <linux/uaccess.h> /* copy_from|to|user() and others */
57 #define MAX_DELAY msecs_to_jiffies(500)
58 #define MINECHOCHAR SPACE
60 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
61 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
62 MODULE_DESCRIPTION("Speakup console speech");
63 MODULE_LICENSE("GPL");
64 MODULE_VERSION(SPEAKUP_VERSION
);
67 module_param_named(synth
, synth_name
, charp
, S_IRUGO
);
68 module_param_named(quiet
, quiet_boot
, bool, S_IRUGO
);
70 MODULE_PARM_DESC(synth
, "Synth to start if speakup is built in.");
71 MODULE_PARM_DESC(quiet
, "Do not announce when the synthesizer is found.");
73 special_func special_handler
;
75 short pitch_shift
, synth_flags
;
77 int attrib_bleep
, bleeps
, bleep_time
= 10;
78 int no_intr
, spell_delay
;
79 int key_echo
, say_word_ctl
;
80 int say_ctrl
, bell_pos
;
82 int punc_level
, reading_punc
;
83 char str_caps_start
[MAXVARLEN
+ 1] = "\0", str_caps_stop
[MAXVARLEN
+ 1] = "\0";
84 const struct st_bits_data punc_info
[] = {
86 {"some", "/$%&@", SOME
},
87 {"most", "$%&#()=+*/@^<>|\\", MOST
},
88 {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC
},
89 {"delimiters", "", B_WDLM
},
90 {"repeats", "()", CH_RPT
},
91 {"extended numeric", "", B_EXNUM
},
92 {"symbols", "", B_SYM
},
96 static char mark_cut_flag
;
98 u_char
*our_keys
[MAX_KEY
], *shift_table
;
100 const u_char key_defaults
[] = {
101 #include "speakupmap.h"
104 /* Speakup Cursor Track Variables */
105 static int cursor_track
= 1, prev_cursor_track
= 1;
107 /* cursor track modes, must be ordered same as cursor_msgs */
115 #define read_all_mode CT_Max
117 static struct tty_struct
*tty
;
119 static void spkup_write(const char *in_buf
, int count
);
121 static char *phonetic
[] = {
122 "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
123 "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
125 "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
126 "x ray", "yankee", "zulu"
129 /* array of 256 char pointers (one for each character description)
130 * initialized to default_chars and user selectable via
131 * /proc/speakup/characters */
132 char *characters
[256];
134 char *default_chars
[256] = {
135 /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
136 /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
137 /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
138 /*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
140 /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
142 /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
145 /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
147 /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
148 /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
149 /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
150 /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
151 /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
154 /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
155 /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
156 /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
157 /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
158 /*127*/ "del", "control", "control", "control", "control", "control",
159 "control", "control", "control", "control", "control",
160 /*138*/ "control", "control", "control", "control", "control",
161 "control", "control", "control", "control", "control",
162 "control", "control",
163 /*150*/ "control", "control", "control", "control", "control",
164 "control", "control", "control", "control", "control",
165 /*160*/ "nbsp", "inverted bang",
166 /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
167 /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
168 /*172*/ "not", "soft hyphen", "registered", "macron",
169 /*176*/ "degrees", "plus or minus", "super two", "super three",
170 /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
171 /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
172 /*188*/ "one quarter", "one half", "three quarters",
174 /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
176 /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
178 /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
180 /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
181 /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
183 /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
184 /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
185 /*230*/ "ae", "c cidella", "e grave", "e acute",
186 /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
188 /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
190 /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
192 /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
195 /* array of 256 u_short (one for each character)
196 * initialized to default_chartab and user selectable via
197 * /sys/module/speakup/parameters/chartab */
198 u_short spk_chartab
[256];
200 static u_short default_chartab
[256] = {
201 B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, /* 0-7 */
202 B_CTL
, B_CTL
, A_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, /* 8-15 */
203 B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, /*16-23 */
204 B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, /* 24-31 */
205 WDLM
, A_PUNC
, PUNC
, PUNC
, PUNC
, PUNC
, PUNC
, A_PUNC
, /* !"#$%&' */
206 PUNC
, PUNC
, PUNC
, PUNC
, A_PUNC
, A_PUNC
, A_PUNC
, PUNC
, /* ()*+, -./ */
207 NUM
, NUM
, NUM
, NUM
, NUM
, NUM
, NUM
, NUM
, /* 01234567 */
208 NUM
, NUM
, A_PUNC
, PUNC
, PUNC
, PUNC
, PUNC
, A_PUNC
, /* 89:;<=>? */
209 PUNC
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* @ABCDEFG */
210 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* HIJKLMNO */
211 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* PQRSTUVW */
212 A_CAP
, A_CAP
, A_CAP
, PUNC
, PUNC
, PUNC
, PUNC
, PUNC
, /* XYZ[\]^_ */
213 PUNC
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* `abcdefg */
214 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* hijklmno */
215 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* pqrstuvw */
216 ALPHA
, ALPHA
, ALPHA
, PUNC
, PUNC
, PUNC
, PUNC
, 0, /* xyz{|}~ */
217 B_CAPSYM
, B_CAPSYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 128-134 */
219 B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 136-142 */
221 B_CAPSYM
, B_CAPSYM
, B_SYM
, B_CAPSYM
, B_SYM
, B_SYM
, B_SYM
, /* 144-150 */
223 B_SYM
, B_SYM
, B_CAPSYM
, B_CAPSYM
, B_SYM
, B_SYM
, B_SYM
, /*152-158 */
225 WDLM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_CAPSYM
, /* 160-166 */
227 B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 168-175 */
228 B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 176-183 */
229 B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 184-191 */
230 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* 192-199 */
231 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* 200-207 */
232 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, B_SYM
, /* 208-215 */
233 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, ALPHA
, /* 216-223 */
234 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* 224-231 */
235 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* 232-239 */
236 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, B_SYM
, /* 240-247 */
237 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
/* 248-255 */
240 struct task_struct
*speakup_task
;
241 struct bleep unprocessed_sound
;
242 static int spk_keydown
;
243 static u_char spk_lastkey
, spk_close_press
, keymap_flags
;
244 static u_char last_keycode
, this_speakup_key
;
245 static u_long last_spk_jiffy
;
247 struct st_spk_t
*speakup_console
[MAX_NR_CONSOLES
];
249 DEFINE_MUTEX(spk_mutex
);
251 static int keyboard_notifier_call(struct notifier_block
*,
252 unsigned long code
, void *param
);
254 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 struct notifier_block vt_notifier_block
= {
262 .notifier_call
= vt_notifier_call
,
265 static unsigned char get_attributes(u16
*pos
)
267 return (u_char
) (scr_readw(pos
) >> 8);
270 static void speakup_date(struct vc_data
*vc
)
272 spk_x
= spk_cx
= vc
->vc_x
;
273 spk_y
= spk_cy
= vc
->vc_y
;
274 spk_pos
= spk_cp
= vc
->vc_pos
;
275 spk_old_attr
= spk_attr
;
276 spk_attr
= get_attributes((u_short
*) spk_pos
);
279 static void bleep(u_short val
)
281 static const short vals
[] = {
282 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
285 int time
= bleep_time
;
286 freq
= vals
[val
% 12];
288 freq
*= (1 << (val
/ 12));
289 unprocessed_sound
.freq
= freq
;
290 unprocessed_sound
.jiffies
= msecs_to_jiffies(time
);
291 unprocessed_sound
.active
= 1;
292 /* We can only have 1 active sound at a time. */
295 static void speakup_shut_up(struct vc_data
*vc
)
306 static void speech_kill(struct vc_data
*vc
)
308 char val
= synth
->is_alive(synth
);
312 /* re-enables synth, if disabled */
313 if (val
== 2 || spk_killed
) {
315 spk_shut_up
&= ~0x40;
316 synth_printf("%s\n", msg_get(MSG_IAM_ALIVE
));
318 synth_printf("%s\n", msg_get(MSG_YOU_KILLED_SPEAKUP
));
323 static void speakup_off(struct vc_data
*vc
)
325 if (spk_shut_up
& 0x80) {
327 synth_printf("%s\n", msg_get(MSG_HEY_THATS_BETTER
));
330 synth_printf("%s\n", msg_get(MSG_YOU_TURNED_ME_OFF
));
335 static void speakup_parked(struct vc_data
*vc
)
337 if (spk_parked
& 0x80) {
339 synth_printf("%s\n", msg_get(MSG_UNPARKED
));
342 synth_printf("%s\n", msg_get(MSG_PARKED
));
346 static void speakup_cut(struct vc_data
*vc
)
348 static const char err_buf
[] = "set selection failed";
351 if (!mark_cut_flag
) {
353 xs
= (u_short
) spk_x
;
354 ys
= (u_short
) spk_y
;
356 synth_printf("%s\n", msg_get(MSG_MARK
));
359 xe
= (u_short
) spk_x
;
360 ye
= (u_short
) spk_y
;
362 synth_printf("%s\n", msg_get(MSG_CUT
));
364 speakup_clear_selection();
365 ret
= speakup_set_selection(tty
);
369 break; /* no error */
371 pr_warn("%sEFAULT\n", err_buf
);
374 pr_warn("%sEINVAL\n", err_buf
);
377 pr_warn("%sENOMEM\n", err_buf
);
382 static void speakup_paste(struct vc_data
*vc
)
386 synth_printf("%s\n", msg_get(MSG_MARK_CLEARED
));
388 synth_printf("%s\n", msg_get(MSG_PASTE
));
389 speakup_paste_selection(tty
);
393 static void say_attributes(struct vc_data
*vc
)
395 int fg
= spk_attr
& 0x0f;
396 int bg
= spk_attr
>> 4;
398 synth_printf("%s ", msg_get(MSG_BRIGHT
));
401 synth_printf("%s", msg_get(MSG_COLORS_START
+ fg
));
403 synth_printf(" %s ", msg_get(MSG_ON_BLINKING
));
406 synth_printf(" %s ", msg_get(MSG_ON
));
407 synth_printf("%s\n", msg_get(MSG_COLORS_START
+ bg
));
418 static void announce_edge(struct vc_data
*vc
, int msg_id
)
422 if ((bleeps
& 2) && (msg_id
< edge_quiet
))
423 synth_printf("%s\n", msg_get(MSG_EDGE_MSGS_START
+ msg_id
- 1));
426 static void speak_char(u_char ch
)
428 char *cp
= characters
[ch
];
429 struct var_t
*direct
= get_var(DIRECT
);
430 if (direct
&& direct
->u
.n
.value
) {
431 if (IS_CHAR(ch
, B_CAP
)) {
433 synth_printf("%s", str_caps_start
);
435 synth_printf("%c", ch
);
436 if (IS_CHAR(ch
, B_CAP
))
437 synth_printf("%s", str_caps_stop
);
441 pr_info("speak_char: cp == NULL!\n");
444 synth_buffer_add(SPACE
);
445 if (IS_CHAR(ch
, B_CAP
)) {
447 synth_printf("%s", str_caps_start
);
448 synth_printf("%s", cp
);
449 synth_printf("%s", str_caps_stop
);
452 synth_printf("%s", msg_get(MSG_CTRL
));
455 synth_printf("%s", cp
);
457 synth_buffer_add(SPACE
);
460 static u16
get_char(struct vc_data
*vc
, u16
* pos
, u_char
* attribs
)
464 u16 w
= scr_readw(pos
);
467 if (w
& vc
->vc_hi_font_mask
)
470 ch
= inverse_translate(vc
, c
, 0);
471 *attribs
= (w
& 0xff00) >> 8;
476 static void say_char(struct vc_data
*vc
)
479 spk_old_attr
= spk_attr
;
480 ch
= get_char(vc
, (u_short
*) spk_pos
, &spk_attr
);
481 if (spk_attr
!= spk_old_attr
) {
482 if (attrib_bleep
& 1)
484 if (attrib_bleep
& 2)
487 speak_char(ch
& 0xff);
490 static void say_phonetic_char(struct vc_data
*vc
)
493 spk_old_attr
= spk_attr
;
494 ch
= get_char(vc
, (u_short
*) spk_pos
, &spk_attr
);
495 if (isascii(ch
) && isalpha(ch
)) {
497 synth_printf("%s\n", phonetic
[--ch
]);
499 if (IS_CHAR(ch
, B_NUM
))
500 synth_printf("%s ", msg_get(MSG_NUMBER
));
505 static void say_prev_char(struct vc_data
*vc
)
509 announce_edge(vc
, edge_left
);
517 static void say_next_char(struct vc_data
*vc
)
520 if (spk_x
== vc
->vc_cols
- 1) {
521 announce_edge(vc
, edge_right
);
529 /* get_word - will first check to see if the character under the
530 * reading cursor is a space and if say_word_ctl is true it will
531 * return the word space. If say_word_ctl is not set it will check to
532 * see if there is a word starting on the next position to the right
533 * and return that word if it exists. If it does not exist it will
534 * move left to the beginning of any previous word on the line or the
535 * beginning off the line whichever comes first.. */
537 static u_long
get_word(struct vc_data
*vc
)
539 u_long cnt
= 0, tmpx
= spk_x
, tmp_pos
= spk_pos
;
543 spk_old_attr
= spk_attr
;
544 ch
= (char)get_char(vc
, (u_short
*) tmp_pos
, &temp
);
546 /* decided to take out the sayword if on a space (mis-information */
547 if (say_word_ctl
&& ch
== SPACE
) {
549 synth_printf("%s\n", msg_get(MSG_SPACE
));
551 } else if ((tmpx
< vc
->vc_cols
- 2)
552 && (ch
== SPACE
|| ch
== 0 || IS_WDLM(ch
))
553 && ((char)get_char(vc
, (u_short
*) &tmp_pos
+ 1, &temp
) >
559 ch
= (char)get_char(vc
, (u_short
*) tmp_pos
- 1, &temp
);
560 if ((ch
== SPACE
|| ch
== 0 || IS_WDLM(ch
))
561 && ((char)get_char(vc
, (u_short
*) tmp_pos
, &temp
) >
567 attr_ch
= get_char(vc
, (u_short
*) tmp_pos
, &spk_attr
);
568 buf
[cnt
++] = attr_ch
& 0xff;
569 while (tmpx
< vc
->vc_cols
- 1) {
572 ch
= (char)get_char(vc
, (u_short
*) tmp_pos
, &temp
);
573 if ((ch
== SPACE
) || ch
== 0
574 || (IS_WDLM(buf
[cnt
- 1]) && (ch
> SPACE
)))
582 static void say_word(struct vc_data
*vc
)
584 u_long cnt
= get_word(vc
);
585 u_short saved_punc_mask
= punc_mask
;
590 spkup_write(buf
, cnt
);
591 punc_mask
= saved_punc_mask
;
594 static void say_prev_word(struct vc_data
*vc
)
598 u_short edge_said
= 0, last_state
= 0, state
= 0;
603 announce_edge(vc
, edge_top
);
608 edge_said
= edge_quiet
;
613 edge_said
= edge_top
;
616 if (edge_said
!= edge_quiet
)
617 edge_said
= edge_left
;
621 spk_x
= vc
->vc_cols
- 1;
625 ch
= (char)get_char(vc
, (u_short
*) spk_pos
, &temp
);
626 if (ch
== SPACE
|| ch
== 0)
628 else if (IS_WDLM(ch
))
632 if (state
< last_state
) {
639 if (spk_x
== 0 && edge_said
== edge_quiet
)
640 edge_said
= edge_left
;
641 if (edge_said
> 0 && edge_said
< edge_quiet
)
642 announce_edge(vc
, edge_said
);
646 static void say_next_word(struct vc_data
*vc
)
650 u_short edge_said
= 0, last_state
= 2, state
= 0;
653 if (spk_x
== vc
->vc_cols
- 1 && spk_y
== vc
->vc_rows
- 1) {
654 announce_edge(vc
, edge_bottom
);
658 ch
= (char)get_char(vc
, (u_short
*) spk_pos
, &temp
);
659 if (ch
== SPACE
|| ch
== 0)
661 else if (IS_WDLM(ch
))
665 if (state
> last_state
)
667 if (spk_x
>= vc
->vc_cols
- 1) {
668 if (spk_y
== vc
->vc_rows
- 1) {
669 edge_said
= edge_bottom
;
675 edge_said
= edge_right
;
682 announce_edge(vc
, edge_said
);
686 static void spell_word(struct vc_data
*vc
)
688 static char *delay_str
[] = { "", ",", ".", ". .", ". . ." };
689 char *cp
= buf
, *str_cap
= str_caps_stop
;
690 char *cp1
, *last_cap
= str_caps_stop
;
694 while ((ch
= (u_char
) *cp
)) {
696 synth_printf(" %s ", delay_str
[spell_delay
]);
697 if (IS_CHAR(ch
, B_CAP
)) {
698 str_cap
= str_caps_start
;
701 else /* synth has no pitch */
702 last_cap
= str_caps_stop
;
704 str_cap
= str_caps_stop
;
705 if (str_cap
!= last_cap
) {
706 synth_printf("%s", str_cap
);
709 if (this_speakup_key
== SPELL_PHONETIC
710 && (isascii(ch
) && isalpha(ch
))) {
712 cp1
= phonetic
[--ch
];
714 cp1
= characters
[ch
];
716 synth_printf("%s", msg_get(MSG_CTRL
));
720 synth_printf("%s", cp1
);
723 if (str_cap
!= str_caps_stop
)
724 synth_printf("%s", str_caps_stop
);
727 static int get_line(struct vc_data
*vc
)
729 u_long tmp
= spk_pos
- (spk_x
* 2);
733 spk_old_attr
= spk_attr
;
734 spk_attr
= get_attributes((u_short
*) spk_pos
);
735 for (i
= 0; i
< vc
->vc_cols
; i
++) {
736 buf
[i
] = (u_char
) get_char(vc
, (u_short
*) tmp
, &tmp2
);
739 for (--i
; i
>= 0; i
--)
745 static void say_line(struct vc_data
*vc
)
747 int i
= get_line(vc
);
749 u_short saved_punc_mask
= punc_mask
;
751 synth_printf("%s\n", msg_get(MSG_BLANK
));
755 if (this_speakup_key
== SAY_LINE_INDENT
) {
759 synth_printf("%d, ", (cp
- buf
) + 1);
761 punc_mask
= punc_masks
[reading_punc
];
763 punc_mask
= saved_punc_mask
;
766 static void say_prev_line(struct vc_data
*vc
)
770 announce_edge(vc
, edge_top
);
774 spk_pos
-= vc
->vc_size_row
;
778 static void say_next_line(struct vc_data
*vc
)
781 if (spk_y
== vc
->vc_rows
- 1) {
782 announce_edge(vc
, edge_bottom
);
786 spk_pos
+= vc
->vc_size_row
;
790 static int say_from_to(struct vc_data
*vc
, u_long from
, u_long to
,
795 u_short saved_punc_mask
= punc_mask
;
796 spk_old_attr
= spk_attr
;
797 spk_attr
= get_attributes((u_short
*) from
);
799 buf
[i
++] = (char)get_char(vc
, (u_short
*) from
, &tmp
);
801 if (i
>= vc
->vc_size_row
)
804 for (--i
; i
>= 0; i
--)
812 punc_mask
= punc_info
[reading_punc
].mask
;
815 punc_mask
= saved_punc_mask
;
819 static void say_line_from_to(struct vc_data
*vc
, u_long from
, u_long to
,
822 u_long start
= vc
->vc_origin
+ (spk_y
* vc
->vc_size_row
);
823 u_long end
= start
+ (to
* 2);
825 if (say_from_to(vc
, start
, end
, read_punc
) <= 0)
826 if (cursor_track
!= read_all_mode
)
827 synth_printf("%s\n", msg_get(MSG_BLANK
));
830 /* Sentence Reading Commands */
832 static int currsentence
;
833 static int numsentences
[2];
834 static char *sentbufend
[2];
835 static char *sentmarks
[2][10];
838 static char sentbuf
[2][256];
840 static int say_sentence_num(int num
, int prev
)
843 currsentence
= num
+ 1;
844 if (prev
&& --bn
== -1)
847 if (num
> numsentences
[bn
])
850 spkup_write(sentmarks
[bn
][num
], sentbufend
[bn
] - sentmarks
[bn
][num
]);
854 static int get_sentence_buf(struct vc_data
*vc
, int read_punc
)
864 start
= vc
->vc_origin
+ ((spk_y
) * vc
->vc_size_row
);
865 end
= vc
->vc_origin
+ ((spk_y
) * vc
->vc_size_row
) + vc
->vc_cols
* 2;
867 numsentences
[bn
] = 0;
868 sentmarks
[bn
][0] = &sentbuf
[bn
][0];
870 spk_old_attr
= spk_attr
;
871 spk_attr
= get_attributes((u_short
*) start
);
873 while (start
< end
) {
874 sentbuf
[bn
][i
] = (char)get_char(vc
, (u_short
*) start
, &tmp
);
876 if (sentbuf
[bn
][i
] == SPACE
&& sentbuf
[bn
][i
- 1] == '.'
877 && numsentences
[bn
] < 9) {
878 /* Sentence Marker */
880 sentmarks
[bn
][numsentences
[bn
]] =
886 if (i
>= vc
->vc_size_row
)
890 for (--i
; i
>= 0; i
--)
891 if (sentbuf
[bn
][i
] != SPACE
)
897 sentbuf
[bn
][++i
] = SPACE
;
898 sentbuf
[bn
][++i
] = '\0';
900 sentbufend
[bn
] = &sentbuf
[bn
][i
];
901 return numsentences
[bn
];
904 static void say_screen_from_to(struct vc_data
*vc
, u_long from
, u_long to
)
906 u_long start
= vc
->vc_origin
, end
;
908 start
+= from
* vc
->vc_size_row
;
909 if (to
> vc
->vc_rows
)
911 end
= vc
->vc_origin
+ (to
* vc
->vc_size_row
);
912 for (from
= start
; from
< end
; from
= to
) {
913 to
= from
+ vc
->vc_size_row
;
914 say_from_to(vc
, from
, to
, 1);
918 static void say_screen(struct vc_data
*vc
)
920 say_screen_from_to(vc
, 0, vc
->vc_rows
);
923 static void speakup_win_say(struct vc_data
*vc
)
925 u_long start
, end
, from
, to
;
927 synth_printf("%s\n", msg_get(MSG_NO_WINDOW
));
930 start
= vc
->vc_origin
+ (win_top
* vc
->vc_size_row
);
931 end
= vc
->vc_origin
+ (win_bottom
* vc
->vc_size_row
);
932 while (start
<= end
) {
933 from
= start
+ (win_left
* 2);
934 to
= start
+ (win_right
* 2);
935 say_from_to(vc
, from
, to
, 1);
936 start
+= vc
->vc_size_row
;
940 static void top_edge(struct vc_data
*vc
)
943 spk_pos
= vc
->vc_origin
+ 2 * spk_x
;
948 static void bottom_edge(struct vc_data
*vc
)
951 spk_pos
+= (vc
->vc_rows
- spk_y
- 1) * vc
->vc_size_row
;
952 spk_y
= vc
->vc_rows
- 1;
956 static void left_edge(struct vc_data
*vc
)
959 spk_pos
-= spk_x
* 2;
964 static void right_edge(struct vc_data
*vc
)
967 spk_pos
+= (vc
->vc_cols
- spk_x
- 1) * 2;
968 spk_x
= vc
->vc_cols
- 1;
972 static void say_first_char(struct vc_data
*vc
)
974 int i
, len
= get_line(vc
);
978 synth_printf("%s\n", msg_get(MSG_BLANK
));
981 for (i
= 0; i
< len
; i
++)
985 spk_pos
-= (spk_x
- i
) * 2;
987 synth_printf("%d, ", ++i
);
991 static void say_last_char(struct vc_data
*vc
)
993 int len
= get_line(vc
);
997 synth_printf("%s\n", msg_get(MSG_BLANK
));
1001 spk_pos
-= (spk_x
- len
) * 2;
1003 synth_printf("%d, ", ++len
);
1007 static void say_position(struct vc_data
*vc
)
1009 synth_printf(msg_get(MSG_POS_INFO
), spk_y
+ 1, spk_x
+ 1,
1014 /* Added by brianb */
1015 static void say_char_num(struct vc_data
*vc
)
1018 u_short ch
= get_char(vc
, (u_short
*) spk_pos
, &tmp
);
1020 synth_printf(msg_get(MSG_CHAR_INFO
), ch
, ch
);
1023 /* these are stub functions to keep keyboard.c happy. */
1025 static void say_from_top(struct vc_data
*vc
)
1027 say_screen_from_to(vc
, 0, spk_y
);
1030 static void say_to_bottom(struct vc_data
*vc
)
1032 say_screen_from_to(vc
, spk_y
, vc
->vc_rows
);
1035 static void say_from_left(struct vc_data
*vc
)
1037 say_line_from_to(vc
, 0, spk_x
, 1);
1040 static void say_to_right(struct vc_data
*vc
)
1042 say_line_from_to(vc
, spk_x
, vc
->vc_cols
, 1);
1045 /* end of stub functions. */
1047 static void spkup_write(const char *in_buf
, int count
)
1049 static int rep_count
;
1050 static u_char ch
= '\0', old_ch
= '\0';
1051 static u_short char_type
, last_type
;
1052 int in_count
= count
;
1055 if (cursor_track
== read_all_mode
) {
1056 /* Insert Sentence Index */
1057 if ((in_buf
== sentmarks
[bn
][currsentence
]) &&
1058 (currsentence
<= numsentences
[bn
]))
1059 synth_insert_next_index(currsentence
++);
1061 ch
= (u_char
) *in_buf
++;
1062 char_type
= spk_chartab
[ch
];
1063 if (ch
== old_ch
&& !(char_type
& B_NUM
)) {
1064 if (++rep_count
> 2)
1067 if ((last_type
& CH_RPT
) && rep_count
> 2) {
1069 synth_printf(msg_get(MSG_REPEAT_DESC
),
1075 if (ch
== spk_lastkey
) {
1077 if (key_echo
== 1 && ch
>= MINECHOCHAR
)
1079 } else if (char_type
& B_ALPHA
) {
1080 if ((synth_flags
& SF_DEC
) && (last_type
& PUNC
))
1081 synth_buffer_add(SPACE
);
1082 synth_printf("%c", ch
);
1083 } else if (char_type
& B_NUM
) {
1085 synth_printf("%c", ch
);
1086 } else if (char_type
& punc_mask
) {
1088 char_type
&= ~PUNC
; /* for dec nospell processing */
1089 } else if (char_type
& SYNTH_OK
) {
1090 /* these are usually puncts like . and , which synth
1091 * needs for expression.
1092 * suppress multiple to get rid of long pauses and
1093 * clear repeat count
1095 * repeats on you don't get nothing repeated count */
1097 synth_printf("%c", ch
);
1101 /* send space and record position, if next is num overwrite space */
1103 synth_buffer_add(SPACE
);
1108 last_type
= char_type
;
1111 if (in_count
> 2 && rep_count
> 2) {
1112 if (last_type
& CH_RPT
) {
1114 synth_printf(msg_get(MSG_REPEAT_DESC2
), ++rep_count
);
1121 static const int NUM_CTL_LABELS
= (MSG_CTL_END
- MSG_CTL_START
+ 1);
1123 static void read_all_doc(struct vc_data
*vc
);
1124 static void cursor_done(u_long data
);
1125 static DEFINE_TIMER(cursor_timer
, cursor_done
, 0, 0);
1127 static void do_handle_shift(struct vc_data
*vc
, u_char value
, char up_flag
)
1129 unsigned long flags
;
1130 if (synth
== NULL
|| up_flag
|| spk_killed
)
1133 if (cursor_track
== read_all_mode
) {
1136 del_timer(&cursor_timer
);
1137 spk_shut_up
&= 0xfe;
1142 del_timer(&cursor_timer
);
1143 cursor_track
= prev_cursor_track
;
1144 spk_shut_up
&= 0xfe;
1149 spk_shut_up
&= 0xfe;
1152 if (say_ctrl
&& value
< NUM_CTL_LABELS
)
1153 synth_printf("%s", msg_get(MSG_CTL_START
+ value
));
1157 static void do_handle_latin(struct vc_data
*vc
, u_char value
, char up_flag
)
1159 unsigned long flags
;
1162 spk_lastkey
= spk_keydown
= 0;
1166 if (synth
== NULL
|| spk_killed
) {
1170 spk_shut_up
&= 0xfe;
1171 spk_lastkey
= value
;
1174 if (key_echo
== 2 && value
>= MINECHOCHAR
)
1179 int set_key_info(const u_char
*key_info
, u_char
*k_buffer
)
1181 int i
= 0, states
, key_data_len
;
1182 const u_char
*cp
= key_info
;
1183 u_char
*cp1
= k_buffer
;
1184 u_char ch
, version
, num_keys
;
1186 if (version
!= KEY_MAP_VER
)
1189 states
= (int)cp
[1];
1190 key_data_len
= (states
+ 1) * (num_keys
+ 1);
1191 if (key_data_len
+ SHIFT_TBL_SIZE
+ 4 >= sizeof(key_buf
))
1193 memset(k_buffer
, 0, SHIFT_TBL_SIZE
);
1194 memset(our_keys
, 0, sizeof(our_keys
));
1195 shift_table
= k_buffer
;
1196 our_keys
[0] = shift_table
;
1197 cp1
+= SHIFT_TBL_SIZE
;
1198 memcpy(cp1
, cp
, key_data_len
+ 3);
1199 /* get num_keys, states and data */
1200 cp1
+= 2; /* now pointing at shift states */
1201 for (i
= 1; i
<= states
; i
++) {
1203 if (ch
>= SHIFT_TBL_SIZE
)
1205 shift_table
[ch
] = i
;
1207 keymap_flags
= *cp1
++;
1208 while ((ch
= *cp1
)) {
1217 static struct var_t spk_vars
[] = {
1218 /* bell must be first to set high limit */
1219 {BELL_POS
, .u
.n
= {NULL
, 0, 0, 0, 0, 0, NULL
} },
1220 {SPELL_DELAY
, .u
.n
= {NULL
, 0, 0, 4, 0, 0, NULL
} },
1221 {ATTRIB_BLEEP
, .u
.n
= {NULL
, 1, 0, 3, 0, 0, NULL
} },
1222 {BLEEPS
, .u
.n
= {NULL
, 3, 0, 3, 0, 0, NULL
} },
1223 {BLEEP_TIME
, .u
.n
= {NULL
, 30, 1, 200, 0, 0, NULL
} },
1224 {PUNC_LEVEL
, .u
.n
= {NULL
, 1, 0, 4, 0, 0, NULL
} },
1225 {READING_PUNC
, .u
.n
= {NULL
, 1, 0, 4, 0, 0, NULL
} },
1226 {CURSOR_TIME
, .u
.n
= {NULL
, 120, 50, 600, 0, 0, NULL
} },
1227 {SAY_CONTROL
, TOGGLE_0
},
1228 {SAY_WORD_CTL
, TOGGLE_0
},
1229 {NO_INTERRUPT
, TOGGLE_0
},
1230 {KEY_ECHO
, .u
.n
= {NULL
, 1, 0, 2, 0, 0, NULL
} },
1234 static void toggle_cursoring(struct vc_data
*vc
)
1236 if (cursor_track
== read_all_mode
)
1237 cursor_track
= prev_cursor_track
;
1238 if (++cursor_track
>= CT_Max
)
1240 synth_printf("%s\n", msg_get(MSG_CURSOR_MSGS_START
+ cursor_track
));
1243 void reset_default_chars(void)
1247 /* First, free any non-default */
1248 for (i
= 0; i
< 256; i
++) {
1249 if ((characters
[i
] != NULL
)
1250 && (characters
[i
] != default_chars
[i
]))
1251 kfree(characters
[i
]);
1254 memcpy(characters
, default_chars
, sizeof(default_chars
));
1257 void reset_default_chartab(void)
1259 memcpy(spk_chartab
, default_chartab
, sizeof(default_chartab
));
1262 static const struct st_bits_data
*pb_edit
;
1264 static int edit_bits(struct vc_data
*vc
, u_char type
, u_char ch
, u_short key
)
1266 short mask
= pb_edit
->mask
, ch_type
= spk_chartab
[ch
];
1267 if (type
!= KT_LATIN
|| (ch_type
& B_NUM
) || ch
< SPACE
)
1270 synth_printf("%s\n", msg_get(MSG_EDIT_DONE
));
1271 special_handler
= NULL
;
1274 if (mask
< PUNC
&& !(ch_type
& PUNC
))
1276 spk_chartab
[ch
] ^= mask
;
1278 synth_printf(" %s\n",
1279 (spk_chartab
[ch
] & mask
) ? msg_get(MSG_ON
) :
1284 /* Allocation concurrency is protected by the console semaphore */
1285 int speakup_allocate(struct vc_data
*vc
)
1289 vc_num
= vc
->vc_num
;
1290 if (speakup_console
[vc_num
] == NULL
) {
1291 speakup_console
[vc_num
] = kzalloc(sizeof(*speakup_console
[0]),
1293 if (speakup_console
[vc_num
] == NULL
)
1296 } else if (!spk_parked
)
1302 void speakup_deallocate(struct vc_data
*vc
)
1306 vc_num
= vc
->vc_num
;
1307 kfree(speakup_console
[vc_num
]);
1308 speakup_console
[vc_num
] = NULL
;
1311 static u_char is_cursor
;
1312 static u_long old_cursor_pos
, old_cursor_x
, old_cursor_y
;
1313 static int cursor_con
;
1315 static void reset_highlight_buffers(struct vc_data
*);
1317 static int read_all_key
;
1319 static void start_read_all_timer(struct vc_data
*vc
, int command
);
1333 static void kbd_fakekey2(struct vc_data
*vc
, int command
)
1335 del_timer(&cursor_timer
);
1336 speakup_fake_down_arrow();
1337 start_read_all_timer(vc
, command
);
1340 static void read_all_doc(struct vc_data
*vc
)
1342 if ((vc
->vc_num
!= fg_console
) || synth
== NULL
|| spk_shut_up
)
1344 if (!synth_supports_indexing())
1346 if (cursor_track
!= read_all_mode
)
1347 prev_cursor_track
= cursor_track
;
1348 cursor_track
= read_all_mode
;
1349 reset_index_count(0);
1350 if (get_sentence_buf(vc
, 0) == -1)
1351 kbd_fakekey2(vc
, RA_DOWN_ARROW
);
1353 say_sentence_num(0, 0);
1354 synth_insert_next_index(0);
1355 start_read_all_timer(vc
, RA_TIMER
);
1359 static void stop_read_all(struct vc_data
*vc
)
1361 del_timer(&cursor_timer
);
1362 cursor_track
= prev_cursor_track
;
1363 spk_shut_up
&= 0xfe;
1367 static void start_read_all_timer(struct vc_data
*vc
, int command
)
1369 struct var_t
*cursor_timeout
;
1371 cursor_con
= vc
->vc_num
;
1372 read_all_key
= command
;
1373 cursor_timeout
= get_var(CURSOR_TIME
);
1374 mod_timer(&cursor_timer
,
1375 jiffies
+ msecs_to_jiffies(cursor_timeout
->u
.n
.value
));
1378 static void handle_cursor_read_all(struct vc_data
*vc
, int command
)
1380 int indcount
, sentcount
, rv
, sn
;
1384 /* Get Current Sentence */
1385 get_index_count(&indcount
, &sentcount
);
1386 /*printk("%d %d ", indcount, sentcount); */
1387 reset_index_count(sentcount
+ 1);
1388 if (indcount
== 1) {
1389 if (!say_sentence_num(sentcount
+ 1, 0)) {
1390 kbd_fakekey2(vc
, RA_FIND_NEXT_SENT
);
1393 synth_insert_next_index(0);
1396 if (!say_sentence_num(sentcount
+ 1, 1)) {
1398 reset_index_count(sn
);
1400 synth_insert_next_index(0);
1401 if (!say_sentence_num(sn
, 0)) {
1402 kbd_fakekey2(vc
, RA_FIND_NEXT_SENT
);
1405 synth_insert_next_index(0);
1407 start_read_all_timer(vc
, RA_TIMER
);
1417 if (get_sentence_buf(vc
, 0) == -1) {
1418 kbd_fakekey2(vc
, RA_DOWN_ARROW
);
1420 say_sentence_num(0, 0);
1421 synth_insert_next_index(0);
1422 start_read_all_timer(vc
, RA_TIMER
);
1425 case RA_FIND_NEXT_SENT
:
1426 rv
= get_sentence_buf(vc
, 0);
1430 kbd_fakekey2(vc
, RA_FIND_NEXT_SENT
);
1432 say_sentence_num(1, 0);
1433 synth_insert_next_index(0);
1434 start_read_all_timer(vc
, RA_TIMER
);
1437 case RA_FIND_PREV_SENT
:
1440 get_index_count(&indcount
, &sentcount
);
1442 kbd_fakekey2(vc
, RA_DOWN_ARROW
);
1444 start_read_all_timer(vc
, RA_TIMER
);
1449 static int pre_handle_cursor(struct vc_data
*vc
, u_char value
, char up_flag
)
1451 unsigned long flags
;
1453 if (cursor_track
== read_all_mode
) {
1455 if (synth
== NULL
|| up_flag
|| spk_shut_up
) {
1459 del_timer(&cursor_timer
);
1460 spk_shut_up
&= 0xfe;
1462 start_read_all_timer(vc
, value
+ 1);
1470 static void do_handle_cursor(struct vc_data
*vc
, u_char value
, char up_flag
)
1472 unsigned long flags
;
1473 struct var_t
*cursor_timeout
;
1477 if (synth
== NULL
|| up_flag
|| spk_shut_up
|| cursor_track
== CT_Off
) {
1481 spk_shut_up
&= 0xfe;
1484 /* the key press flushes if !no_inter but we want to flush on cursor
1485 * moves regardless of no_inter state */
1486 is_cursor
= value
+ 1;
1487 old_cursor_pos
= vc
->vc_pos
;
1488 old_cursor_x
= vc
->vc_x
;
1489 old_cursor_y
= vc
->vc_y
;
1490 speakup_console
[vc
->vc_num
]->ht
.cy
= vc
->vc_y
;
1491 cursor_con
= vc
->vc_num
;
1492 if (cursor_track
== CT_Highlight
)
1493 reset_highlight_buffers(vc
);
1494 cursor_timeout
= get_var(CURSOR_TIME
);
1495 mod_timer(&cursor_timer
,
1496 jiffies
+ msecs_to_jiffies(cursor_timeout
->u
.n
.value
));
1500 static void update_color_buffer(struct vc_data
*vc
, const char *ic
, int len
)
1503 int vc_num
= vc
->vc_num
;
1505 bi
= ((vc
->vc_attr
& 0x70) >> 4);
1506 hi
= speakup_console
[vc_num
]->ht
.highsize
[bi
];
1509 if (speakup_console
[vc_num
]->ht
.highsize
[bi
] == 0) {
1510 speakup_console
[vc_num
]->ht
.rpos
[bi
] = vc
->vc_pos
;
1511 speakup_console
[vc_num
]->ht
.rx
[bi
] = vc
->vc_x
;
1512 speakup_console
[vc_num
]->ht
.ry
[bi
] = vc
->vc_y
;
1514 while ((hi
< COLOR_BUFFER_SIZE
) && (i
< len
)) {
1515 if ((ic
[i
] > 32) && (ic
[i
] < 127)) {
1516 speakup_console
[vc_num
]->ht
.highbuf
[bi
][hi
] = ic
[i
];
1518 } else if ((ic
[i
] == 32) && (hi
!= 0)) {
1519 if (speakup_console
[vc_num
]->ht
.highbuf
[bi
][hi
- 1] !=
1521 speakup_console
[vc_num
]->ht
.highbuf
[bi
][hi
] =
1528 speakup_console
[vc_num
]->ht
.highsize
[bi
] = hi
;
1531 static void reset_highlight_buffers(struct vc_data
*vc
)
1534 int vc_num
= vc
->vc_num
;
1535 for (i
= 0; i
< 8; i
++)
1536 speakup_console
[vc_num
]->ht
.highsize
[i
] = 0;
1539 static int count_highlight_color(struct vc_data
*vc
)
1543 int vc_num
= vc
->vc_num
;
1545 u16
*start
= (u16
*) vc
->vc_origin
;
1547 for (i
= 0; i
< 8; i
++)
1548 speakup_console
[vc_num
]->ht
.bgcount
[i
] = 0;
1550 for (i
= 0; i
< vc
->vc_rows
; i
++) {
1551 u16
*end
= start
+ vc
->vc_cols
* 2;
1553 for (ptr
= start
; ptr
< end
; ptr
++) {
1554 ch
= get_attributes(ptr
);
1555 bg
= (ch
& 0x70) >> 4;
1556 speakup_console
[vc_num
]->ht
.bgcount
[bg
]++;
1558 start
+= vc
->vc_size_row
;
1562 for (i
= 0; i
< 8; i
++)
1563 if (speakup_console
[vc_num
]->ht
.bgcount
[i
] > 0)
1568 static int get_highlight_color(struct vc_data
*vc
)
1571 unsigned int cptr
[8], tmp
;
1572 int vc_num
= vc
->vc_num
;
1574 for (i
= 0; i
< 8; i
++)
1577 for (i
= 0; i
< 7; i
++)
1578 for (j
= i
+ 1; j
< 8; j
++)
1579 if (speakup_console
[vc_num
]->ht
.bgcount
[cptr
[i
]] >
1580 speakup_console
[vc_num
]->ht
.bgcount
[cptr
[j
]]) {
1586 for (i
= 0; i
< 8; i
++)
1587 if (speakup_console
[vc_num
]->ht
.bgcount
[cptr
[i
]] != 0)
1588 if (speakup_console
[vc_num
]->ht
.highsize
[cptr
[i
]] > 0)
1593 static int speak_highlight(struct vc_data
*vc
)
1596 int vc_num
= vc
->vc_num
;
1597 if (count_highlight_color(vc
) == 1)
1599 hc
= get_highlight_color(vc
);
1601 d
= vc
->vc_y
- speakup_console
[vc_num
]->ht
.cy
;
1602 if ((d
== 1) || (d
== -1))
1603 if (speakup_console
[vc_num
]->ht
.ry
[hc
] != vc
->vc_y
)
1607 spkup_write(speakup_console
[vc_num
]->ht
.highbuf
[hc
],
1608 speakup_console
[vc_num
]->ht
.highsize
[hc
]);
1609 spk_pos
= spk_cp
= speakup_console
[vc_num
]->ht
.rpos
[hc
];
1610 spk_x
= spk_cx
= speakup_console
[vc_num
]->ht
.rx
[hc
];
1611 spk_y
= spk_cy
= speakup_console
[vc_num
]->ht
.ry
[hc
];
1617 static void cursor_done(u_long data
)
1619 struct vc_data
*vc
= vc_cons
[cursor_con
].d
;
1620 unsigned long flags
;
1621 del_timer(&cursor_timer
);
1623 if (cursor_con
!= fg_console
) {
1629 if (vc
->vc_x
>= win_left
&& vc
->vc_x
<= win_right
&&
1630 vc
->vc_y
>= win_top
&& vc
->vc_y
<= win_bottom
) {
1631 spk_keydown
= is_cursor
= 0;
1635 if (cursor_track
== read_all_mode
) {
1636 handle_cursor_read_all(vc
, read_all_key
);
1639 if (cursor_track
== CT_Highlight
) {
1640 if (speak_highlight(vc
)) {
1641 spk_keydown
= is_cursor
= 0;
1645 if (cursor_track
== CT_Window
)
1646 speakup_win_say(vc
);
1647 else if (is_cursor
== 1 || is_cursor
== 4)
1648 say_line_from_to(vc
, 0, vc
->vc_cols
, 0);
1651 spk_keydown
= is_cursor
= 0;
1656 /* called by: vt_notifier_call() */
1657 static void speakup_bs(struct vc_data
*vc
)
1659 unsigned long flags
;
1660 if (!speakup_console
[vc
->vc_num
])
1662 if (!spk_trylock(flags
))
1663 /* Speakup output, discard */
1667 if (spk_shut_up
|| synth
== NULL
) {
1671 if (vc
->vc_num
== fg_console
&& spk_keydown
) {
1679 /* called by: vt_notifier_call() */
1680 static void speakup_con_write(struct vc_data
*vc
, const char *str
, int len
)
1682 unsigned long flags
;
1683 if ((vc
->vc_num
!= fg_console
) || spk_shut_up
|| synth
== NULL
)
1685 if (!spk_trylock(flags
))
1686 /* Speakup output, discard */
1688 if (bell_pos
&& spk_keydown
&& (vc
->vc_x
== bell_pos
- 1))
1690 if ((is_cursor
) || (cursor_track
== read_all_mode
)) {
1691 if (cursor_track
== CT_Highlight
)
1692 update_color_buffer(vc
, str
, len
);
1697 if (vc
->vc_x
>= win_left
&& vc
->vc_x
<= win_right
&&
1698 vc
->vc_y
>= win_top
&& vc
->vc_y
<= win_bottom
) {
1704 spkup_write(str
, len
);
1708 void speakup_con_update(struct vc_data
*vc
)
1710 unsigned long flags
;
1711 if (speakup_console
[vc
->vc_num
] == NULL
|| spk_parked
)
1713 if (!spk_trylock(flags
))
1714 /* Speakup output, discard */
1720 static void do_handle_spec(struct vc_data
*vc
, u_char value
, char up_flag
)
1722 unsigned long flags
;
1725 if (synth
== NULL
|| up_flag
|| spk_killed
)
1728 spk_shut_up
&= 0xfe;
1733 label
= msg_get(MSG_KEYNAME_CAPSLOCK
);
1734 on_off
= (vc_kbd_led(kbd_table
+ vc
->vc_num
, VC_CAPSLOCK
));
1737 label
= msg_get(MSG_KEYNAME_NUMLOCK
);
1738 on_off
= (vc_kbd_led(kbd_table
+ vc
->vc_num
, VC_NUMLOCK
));
1741 label
= msg_get(MSG_KEYNAME_SCROLLLOCK
);
1742 on_off
= (vc_kbd_led(kbd_table
+ vc
->vc_num
, VC_SCROLLOCK
));
1743 if (speakup_console
[vc
->vc_num
])
1744 speakup_console
[vc
->vc_num
]->tty_stopped
= on_off
;
1752 synth_printf("%s %s\n",
1753 label
, msg_get(MSG_STATUS_START
+ on_off
));
1757 static int inc_dec_var(u_char value
)
1759 struct st_var_header
*p_header
;
1760 struct var_t
*var_data
;
1764 int var_id
= (int)value
- VAR_START
;
1765 int how
= (var_id
& 1) ? E_INC
: E_DEC
;
1766 var_id
= var_id
/ 2 + FIRST_SET_VAR
;
1767 p_header
= get_var_header(var_id
);
1768 if (p_header
== NULL
)
1770 if (p_header
->var_type
!= VAR_NUM
)
1772 var_data
= p_header
->data
;
1773 if (set_num_var(1, p_header
, how
) != 0)
1775 if (!spk_close_press
) {
1776 for (pn
= p_header
->name
; *pn
; pn
++) {
1783 snprintf(cp
, sizeof(num_buf
) - (cp
- num_buf
), " %d ",
1784 var_data
->u
.n
.value
);
1785 synth_printf("%s", num_buf
);
1789 static void speakup_win_set(struct vc_data
*vc
)
1792 if (win_start
> 1) {
1793 synth_printf("%s\n", msg_get(MSG_WINDOW_ALREADY_SET
));
1796 if (spk_x
< win_left
|| spk_y
< win_top
) {
1797 synth_printf("%s\n", msg_get(MSG_END_BEFORE_START
));
1800 if (win_start
&& spk_x
== win_left
&& spk_y
== win_top
) {
1802 win_right
= vc
->vc_cols
- 1;
1804 snprintf(info
, sizeof(info
), msg_get(MSG_WINDOW_LINE
),
1814 snprintf(info
, sizeof(info
), msg_get(MSG_WINDOW_BOUNDARY
),
1815 (win_start
) ? msg_get(MSG_END
) : msg_get(MSG_START
),
1816 (int)spk_y
+ 1, (int)spk_x
+ 1);
1818 synth_printf("%s\n", info
);
1822 static void speakup_win_clear(struct vc_data
*vc
)
1824 win_top
= win_bottom
= 0;
1825 win_left
= win_right
= 0;
1827 synth_printf("%s\n", msg_get(MSG_WINDOW_CLEARED
));
1830 static void speakup_win_enable(struct vc_data
*vc
)
1832 if (win_start
< 2) {
1833 synth_printf("%s\n", msg_get(MSG_NO_WINDOW
));
1838 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCED
));
1840 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCE_DISABLED
));
1843 static void speakup_bits(struct vc_data
*vc
)
1845 int val
= this_speakup_key
- (FIRST_EDIT_BITS
- 1);
1846 if (special_handler
!= NULL
|| val
< 1 || val
> 6) {
1847 synth_printf("%s\n", msg_get(MSG_ERROR
));
1850 pb_edit
= &punc_info
[val
];
1851 synth_printf(msg_get(MSG_EDIT_PROMPT
), pb_edit
->name
);
1852 special_handler
= edit_bits
;
1855 static int handle_goto(struct vc_data
*vc
, u_char type
, u_char ch
, u_short key
)
1857 static u_char
*goto_buf
= "\0\0\0\0\0\0";
1861 if (type
== KT_SPKUP
&& ch
== SPEAKUP_GOTO
)
1863 if (type
== KT_LATIN
&& ch
== '\n')
1870 ch
= goto_buf
[--num
];
1871 goto_buf
[num
] = '\0';
1872 spkup_write(&ch
, 1);
1875 if (ch
< '+' || ch
> 'y')
1877 goto_buf
[num
++] = ch
;
1878 goto_buf
[num
] = '\0';
1879 spkup_write(&ch
, 1);
1880 maxlen
= (*goto_buf
>= '0') ? 3 : 4;
1881 if ((ch
== '+' || ch
== '-') && num
== 1)
1883 if (ch
>= '0' && ch
<= '9' && num
< maxlen
)
1885 if (num
< maxlen
- 1 || num
> maxlen
)
1887 if (ch
< 'x' || ch
> 'y') {
1890 synth_printf(" %s\n", msg_get(MSG_GOTO_CANCELED
));
1891 goto_buf
[num
= 0] = '\0';
1892 special_handler
= NULL
;
1895 cp
= speakup_s2i(goto_buf
, &go_pos
);
1896 goto_pos
= (u_long
) go_pos
;
1898 if (*goto_buf
< '0')
1904 if (goto_pos
>= vc
->vc_cols
)
1905 goto_pos
= vc
->vc_cols
- 1;
1908 if (*goto_buf
< '0')
1914 if (goto_pos
>= vc
->vc_rows
)
1915 goto_pos
= vc
->vc_rows
- 1;
1918 goto_buf
[num
= 0] = '\0';
1920 special_handler
= NULL
;
1923 spk_pos
-= spk_x
* 2;
1925 spk_pos
+= goto_pos
* 2;
1929 spk_pos
= vc
->vc_origin
+ (goto_pos
* vc
->vc_size_row
);
1935 static void speakup_goto(struct vc_data
*vc
)
1937 if (special_handler
!= NULL
) {
1938 synth_printf("%s\n", msg_get(MSG_ERROR
));
1941 synth_printf("%s\n", msg_get(MSG_GOTO
));
1942 special_handler
= handle_goto
;
1946 static void speakup_help(struct vc_data
*vc
)
1948 handle_help(vc
, KT_SPKUP
, SPEAKUP_HELP
, 0);
1951 static void do_nothing(struct vc_data
*vc
)
1953 return; /* flush done in do_spkup */
1956 static u_char key_speakup
, spk_key_locked
;
1958 static void speakup_lock(struct vc_data
*vc
)
1960 if (!spk_key_locked
)
1961 spk_key_locked
= key_speakup
= 16;
1963 spk_key_locked
= key_speakup
= 0;
1966 typedef void (*spkup_hand
) (struct vc_data
*);
1967 spkup_hand spkup_handler
[] = {
1968 /* must be ordered same as defines in speakup.h */
1969 do_nothing
, speakup_goto
, speech_kill
, speakup_shut_up
,
1970 speakup_cut
, speakup_paste
, say_first_char
, say_last_char
,
1971 say_char
, say_prev_char
, say_next_char
,
1972 say_word
, say_prev_word
, say_next_word
,
1973 say_line
, say_prev_line
, say_next_line
,
1974 top_edge
, bottom_edge
, left_edge
, right_edge
,
1975 spell_word
, spell_word
, say_screen
,
1976 say_position
, say_attributes
,
1977 speakup_off
, speakup_parked
, say_line
, /* this is for indent */
1978 say_from_top
, say_to_bottom
,
1979 say_from_left
, say_to_right
,
1980 say_char_num
, speakup_bits
, speakup_bits
, say_phonetic_char
,
1981 speakup_bits
, speakup_bits
, speakup_bits
,
1982 speakup_win_set
, speakup_win_clear
, speakup_win_enable
, speakup_win_say
,
1983 speakup_lock
, speakup_help
, toggle_cursoring
, read_all_doc
, NULL
1986 static void do_spkup(struct vc_data
*vc
, u_char value
)
1988 if (spk_killed
&& value
!= SPEECH_KILL
)
1992 spk_shut_up
&= 0xfe;
1993 this_speakup_key
= value
;
1994 if (value
< SPKUP_MAX_FUNC
&& spkup_handler
[value
]) {
1996 (*spkup_handler
[value
]) (vc
);
1998 if (inc_dec_var(value
) < 0)
2003 static const char *pad_chars
= "0123456789+-*/\015,.?()";
2006 speakup_key(struct vc_data
*vc
, int shift_state
, int keycode
, u_short keysym
,
2009 unsigned long flags
;
2012 u_char type
= KTYP(keysym
), value
= KVAL(keysym
), new_key
= 0;
2013 u_char shift_info
, offset
;
2023 && (vc_kbd_led(kbd_table
+ fg_console
, VC_NUMLOCK
))) {
2028 value
= spk_lastkey
= pad_chars
[value
];
2033 if (keycode
>= MAX_KEY
)
2035 key_info
= our_keys
[keycode
];
2038 /* Check valid read all mode keys */
2039 if ((cursor_track
== read_all_mode
) && (!up_flag
)) {
2053 shift_info
= (shift_state
& 0x0f) + key_speakup
;
2054 offset
= shift_table
[shift_info
];
2056 new_key
= key_info
[offset
];
2059 if (new_key
== SPK_KEY
) {
2060 if (!spk_key_locked
)
2061 key_speakup
= (up_flag
) ? 0 : 16;
2062 if (up_flag
|| spk_killed
)
2064 spk_shut_up
&= 0xfe;
2070 if (last_keycode
== keycode
&&
2071 last_spk_jiffy
+ MAX_DELAY
> jiffies
) {
2072 spk_close_press
= 1;
2073 offset
= shift_table
[shift_info
+ 32];
2075 if (offset
&& key_info
[offset
])
2076 new_key
= key_info
[offset
];
2078 last_keycode
= keycode
;
2079 last_spk_jiffy
= jiffies
;
2085 if (type
== KT_SPKUP
&& special_handler
== NULL
) {
2086 do_spkup(vc
, new_key
);
2087 spk_close_press
= 0;
2091 if (up_flag
|| spk_killed
|| type
== KT_SHIFT
)
2093 spk_shut_up
&= 0xfe;
2094 kh
= (value
== KVAL(K_DOWN
))
2095 || (value
== KVAL(K_UP
))
2096 || (value
== KVAL(K_LEFT
))
2097 || (value
== KVAL(K_RIGHT
));
2098 if ((cursor_track
!= read_all_mode
) || !kh
)
2101 if (special_handler
) {
2102 if (type
== KT_SPEC
&& value
== 1) {
2105 } else if (type
== KT_LETTER
)
2107 else if (value
== 0x7f)
2108 value
= 8; /* make del = backspace */
2109 ret
= (*special_handler
) (vc
, type
, value
, keycode
);
2110 spk_close_press
= 0;
2121 static int keyboard_notifier_call(struct notifier_block
*nb
,
2122 unsigned long code
, void *_param
)
2124 struct keyboard_notifier_param
*param
= _param
;
2125 struct vc_data
*vc
= param
->vc
;
2126 int up
= !param
->down
;
2127 int ret
= NOTIFY_OK
;
2128 static int keycode
; /* to hold the current keycode */
2130 if (vc
->vc_mode
== KD_GRAPHICS
)
2134 * First, determine whether we are handling a fake keypress on
2135 * the current processor. If we are, then return NOTIFY_OK,
2136 * to pass the keystroke up the chain. This prevents us from
2137 * trying to take the Speakup lock while it is held by the
2138 * processor on which the simulated keystroke was generated.
2139 * Also, the simulated keystrokes should be ignored by Speakup.
2142 if (speakup_fake_key_pressed())
2147 /* speakup requires keycode and keysym currently */
2148 keycode
= param
->value
;
2150 case KBD_UNBOUND_KEYCODE
:
2157 if (speakup_key(vc
, param
->shift
, keycode
, param
->value
, up
))
2159 else if (KTYP(param
->value
) == KT_CUR
)
2160 ret
= pre_handle_cursor(vc
, KVAL(param
->value
), up
);
2162 case KBD_POST_KEYSYM
:{
2163 unsigned char type
= KTYP(param
->value
) - 0xf0;
2164 unsigned char val
= KVAL(param
->value
);
2167 do_handle_shift(vc
, val
, up
);
2171 do_handle_latin(vc
, val
, up
);
2174 do_handle_cursor(vc
, val
, up
);
2177 do_handle_spec(vc
, val
, up
);
2186 static int vt_notifier_call(struct notifier_block
*nb
,
2187 unsigned long code
, void *_param
)
2189 struct vt_notifier_param
*param
= _param
;
2190 struct vc_data
*vc
= param
->vc
;
2193 if (vc
->vc_mode
== KD_TEXT
)
2194 speakup_allocate(vc
);
2197 speakup_deallocate(vc
);
2200 if (param
->c
== '\b')
2202 else if (param
->c
< 0x100) {
2204 speakup_con_write(vc
, &d
, 1);
2208 speakup_con_update(vc
);
2214 /* called by: module_exit() */
2215 static void __exit
speakup_exit(void)
2219 unregister_keyboard_notifier(&keyboard_notifier_block
);
2220 unregister_vt_notifier(&vt_notifier_block
);
2221 speakup_unregister_devsynth();
2222 del_timer(&cursor_timer
);
2223 kthread_stop(speakup_task
);
2224 speakup_task
= NULL
;
2225 mutex_lock(&spk_mutex
);
2227 mutex_unlock(&spk_mutex
);
2229 speakup_kobj_exit();
2231 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
2232 kfree(speakup_console
[i
]);
2234 speakup_remove_virtual_keyboard();
2236 for (i
= 0; i
< MAXVARS
; i
++)
2237 speakup_unregister_var(i
);
2239 for (i
= 0; i
< 256; i
++) {
2240 if (characters
[i
] != default_chars
[i
])
2241 kfree(characters
[i
]);
2247 /* call by: module_init() */
2248 static int __init
speakup_init(void)
2252 struct st_spk_t
*first_console
;
2253 struct vc_data
*vc
= vc_cons
[fg_console
].d
;
2256 /* These first few initializations cannot fail. */
2257 initialize_msgs(); /* Initialize arrays for i18n. */
2258 reset_default_chars();
2259 reset_default_chartab();
2261 spk_vars
[0].u
.n
.high
= vc
->vc_cols
;
2262 for (var
= spk_vars
; var
->var_id
!= MAXVARS
; var
++)
2263 speakup_register_var(var
);
2264 for (var
= synth_time_vars
;
2265 (var
->var_id
>= 0) && (var
->var_id
< MAXVARS
); var
++)
2266 speakup_register_var(var
);
2267 for (i
= 1; punc_info
[i
].mask
!= 0; i
++)
2268 set_mask_bits(0, i
, 2);
2270 set_key_info(key_defaults
, key_buf
);
2272 /* From here on out, initializations can fail. */
2273 err
= speakup_add_virtual_keyboard();
2275 goto error_virtkeyboard
;
2277 first_console
= kzalloc(sizeof(*first_console
), GFP_KERNEL
);
2278 if (!first_console
) {
2283 speakup_console
[vc
->vc_num
] = first_console
;
2286 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
2288 err
= speakup_allocate(vc_cons
[i
].d
);
2290 goto error_kobjects
;
2294 spk_shut_up
|= 0x01;
2296 err
= speakup_kobj_init();
2298 goto error_kobjects
;
2300 synth_init(synth_name
);
2301 speakup_register_devsynth();
2303 * register_devsynth might fail, but this error is not fatal.
2304 * /dev/synth is an extra feature; the rest of Speakup
2305 * will work fine without it.
2308 err
= register_keyboard_notifier(&keyboard_notifier_block
);
2310 goto error_kbdnotifier
;
2311 err
= register_vt_notifier(&vt_notifier_block
);
2313 goto error_vtnotifier
;
2315 speakup_task
= kthread_create(speakup_thread
, NULL
, "speakup");
2317 if (IS_ERR(speakup_task
)) {
2318 err
= PTR_ERR(speakup_task
);
2322 set_user_nice(speakup_task
, 10);
2323 wake_up_process(speakup_task
);
2325 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION
);
2326 pr_info("synth name on entry is: %s\n", synth_name
);
2330 unregister_vt_notifier(&vt_notifier_block
);
2333 unregister_keyboard_notifier(&keyboard_notifier_block
);
2334 del_timer(&cursor_timer
);
2337 speakup_unregister_devsynth();
2338 mutex_lock(&spk_mutex
);
2340 mutex_unlock(&spk_mutex
);
2341 speakup_kobj_exit();
2344 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
2345 kfree(speakup_console
[i
]);
2348 speakup_remove_virtual_keyboard();
2351 for (i
= 0; i
< MAXVARS
; i
++)
2352 speakup_unregister_var(i
);
2354 for (i
= 0; i
< 256; i
++) {
2355 if (characters
[i
] != default_chars
[i
])
2356 kfree(characters
[i
]);
2365 module_init(speakup_init
);
2366 module_exit(speakup_exit
);