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
54 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
55 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
56 MODULE_DESCRIPTION("Speakup console speech");
57 MODULE_LICENSE("GPL");
58 MODULE_VERSION(SPEAKUP_VERSION
);
61 module_param_named(synth
, synth_name
, charp
, S_IRUGO
);
62 module_param_named(quiet
, spk_quiet_boot
, bool, S_IRUGO
);
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 */
111 #define read_all_mode CT_Max
113 static struct tty_struct
*tty
;
115 static void spkup_write(const char *in_buf
, int count
);
117 static char *phonetic
[] = {
118 "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
119 "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
121 "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
122 "x ray", "yankee", "zulu"
125 /* array of 256 char pointers (one for each character description)
126 * initialized to default_chars and user selectable via
127 * /proc/speakup/characters
129 char *spk_characters
[256];
131 char *spk_default_chars
[256] = {
132 /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
133 /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
134 /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
135 /*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
137 /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
139 /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
142 /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
144 /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
145 /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
146 /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
147 /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
148 /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
151 /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
152 /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
153 /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
154 /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
155 /*127*/ "del", "control", "control", "control", "control", "control",
156 "control", "control", "control", "control", "control",
157 /*138*/ "control", "control", "control", "control", "control",
158 "control", "control", "control", "control", "control",
159 "control", "control",
160 /*150*/ "control", "control", "control", "control", "control",
161 "control", "control", "control", "control", "control",
162 /*160*/ "nbsp", "inverted bang",
163 /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
164 /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
165 /*172*/ "not", "soft hyphen", "registered", "macron",
166 /*176*/ "degrees", "plus or minus", "super two", "super three",
167 /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
168 /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
169 /*188*/ "one quarter", "one half", "three quarters",
171 /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
173 /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
175 /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
177 /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
178 /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
180 /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
181 /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
182 /*230*/ "ae", "c cidella", "e grave", "e acute",
183 /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
185 /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
187 /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
189 /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
192 /* array of 256 u_short (one for each character)
193 * initialized to default_chartab and user selectable via
194 * /sys/module/speakup/parameters/chartab
196 u_short spk_chartab
[256];
198 static u_short default_chartab
[256] = {
199 B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, /* 0-7 */
200 B_CTL
, B_CTL
, A_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, /* 8-15 */
201 B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, /*16-23 */
202 B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, /* 24-31 */
203 WDLM
, A_PUNC
, PUNC
, PUNC
, PUNC
, PUNC
, PUNC
, A_PUNC
, /* !"#$%&' */
204 PUNC
, PUNC
, PUNC
, PUNC
, A_PUNC
, A_PUNC
, A_PUNC
, PUNC
, /* ()*+, -./ */
205 NUM
, NUM
, NUM
, NUM
, NUM
, NUM
, NUM
, NUM
, /* 01234567 */
206 NUM
, NUM
, A_PUNC
, PUNC
, PUNC
, PUNC
, PUNC
, A_PUNC
, /* 89:;<=>? */
207 PUNC
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* @ABCDEFG */
208 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* HIJKLMNO */
209 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* PQRSTUVW */
210 A_CAP
, A_CAP
, A_CAP
, PUNC
, PUNC
, PUNC
, PUNC
, PUNC
, /* XYZ[\]^_ */
211 PUNC
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* `abcdefg */
212 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* hijklmno */
213 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* pqrstuvw */
214 ALPHA
, ALPHA
, ALPHA
, PUNC
, PUNC
, PUNC
, PUNC
, 0, /* xyz{|}~ */
215 B_CAPSYM
, B_CAPSYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 128-134 */
217 B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 136-142 */
219 B_CAPSYM
, B_CAPSYM
, B_SYM
, B_CAPSYM
, B_SYM
, B_SYM
, B_SYM
, /* 144-150 */
221 B_SYM
, B_SYM
, B_CAPSYM
, B_CAPSYM
, B_SYM
, B_SYM
, B_SYM
, /*152-158 */
223 WDLM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_CAPSYM
, /* 160-166 */
225 B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 168-175 */
226 B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 176-183 */
227 B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 184-191 */
228 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* 192-199 */
229 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* 200-207 */
230 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, B_SYM
, /* 208-215 */
231 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, ALPHA
, /* 216-223 */
232 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* 224-231 */
233 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* 232-239 */
234 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, B_SYM
, /* 240-247 */
235 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
/* 248-255 */
238 struct task_struct
*speakup_task
;
239 struct bleep spk_unprocessed_sound
;
240 static int spk_keydown
;
241 static u_char spk_lastkey
, spk_close_press
, keymap_flags
;
242 static u_char last_keycode
, this_speakup_key
;
243 static u_long last_spk_jiffy
;
245 struct st_spk_t
*speakup_console
[MAX_NR_CONSOLES
];
247 DEFINE_MUTEX(spk_mutex
);
249 static int keyboard_notifier_call(struct notifier_block
*,
250 unsigned long code
, void *param
);
252 static struct notifier_block keyboard_notifier_block
= {
253 .notifier_call
= keyboard_notifier_call
,
256 static int vt_notifier_call(struct notifier_block
*,
257 unsigned long code
, void *param
);
259 static struct notifier_block vt_notifier_block
= {
260 .notifier_call
= vt_notifier_call
,
263 static unsigned char get_attributes(struct vc_data
*vc
, u16
*pos
)
265 pos
= screen_pos(vc
, pos
- (u16
*)vc
->vc_origin
, 1);
266 return (scr_readw(pos
) & ~vc
->vc_hi_font_mask
) >> 8;
269 static void speakup_date(struct vc_data
*vc
)
271 spk_x
= spk_cx
= vc
->vc_x
;
272 spk_y
= spk_cy
= vc
->vc_y
;
273 spk_pos
= spk_cp
= vc
->vc_pos
;
274 spk_old_attr
= spk_attr
;
275 spk_attr
= get_attributes(vc
, (u_short
*)spk_pos
);
278 static void bleep(u_short val
)
280 static const short vals
[] = {
281 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
284 int time
= spk_bleep_time
;
286 freq
= vals
[val
% 12];
288 freq
*= (1 << (val
/ 12));
289 spk_unprocessed_sound
.freq
= freq
;
290 spk_unprocessed_sound
.jiffies
= msecs_to_jiffies(time
);
291 spk_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
);
313 /* re-enables synth, if disabled */
314 if (val
== 2 || spk_killed
) {
316 spk_shut_up
&= ~0x40;
317 synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE
));
319 synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP
));
324 static void speakup_off(struct vc_data
*vc
)
326 if (spk_shut_up
& 0x80) {
328 synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER
));
331 synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF
));
336 static void speakup_parked(struct vc_data
*vc
)
338 if (spk_parked
& 0x80) {
340 synth_printf("%s\n", spk_msg_get(MSG_UNPARKED
));
343 synth_printf("%s\n", spk_msg_get(MSG_PARKED
));
347 static void speakup_cut(struct vc_data
*vc
)
349 static const char err_buf
[] = "set selection failed";
352 if (!mark_cut_flag
) {
354 spk_xs
= (u_short
)spk_x
;
355 spk_ys
= (u_short
)spk_y
;
357 synth_printf("%s\n", spk_msg_get(MSG_MARK
));
360 spk_xe
= (u_short
)spk_x
;
361 spk_ye
= (u_short
)spk_y
;
363 synth_printf("%s\n", spk_msg_get(MSG_CUT
));
365 speakup_clear_selection();
366 ret
= speakup_set_selection(tty
);
370 break; /* no error */
372 pr_warn("%sEFAULT\n", err_buf
);
375 pr_warn("%sEINVAL\n", err_buf
);
378 pr_warn("%sENOMEM\n", err_buf
);
383 static void speakup_paste(struct vc_data
*vc
)
387 synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED
));
389 synth_printf("%s\n", spk_msg_get(MSG_PASTE
));
390 speakup_paste_selection(tty
);
394 static void say_attributes(struct vc_data
*vc
)
396 int fg
= spk_attr
& 0x0f;
397 int bg
= spk_attr
>> 4;
400 synth_printf("%s ", spk_msg_get(MSG_BRIGHT
));
403 synth_printf("%s", spk_msg_get(MSG_COLORS_START
+ fg
));
405 synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING
));
408 synth_printf(" %s ", spk_msg_get(MSG_ON
));
409 synth_printf("%s\n", spk_msg_get(MSG_COLORS_START
+ bg
));
420 static void announce_edge(struct vc_data
*vc
, int msg_id
)
424 if ((spk_bleeps
& 2) && (msg_id
< edge_quiet
))
426 spk_msg_get(MSG_EDGE_MSGS_START
+ msg_id
- 1));
429 static void speak_char(u_char ch
)
431 char *cp
= spk_characters
[ch
];
432 struct var_t
*direct
= spk_get_var(DIRECT
);
434 if (direct
&& direct
->u
.n
.value
) {
435 if (IS_CHAR(ch
, B_CAP
)) {
437 synth_printf("%s", spk_str_caps_start
);
439 synth_printf("%c", ch
);
440 if (IS_CHAR(ch
, B_CAP
))
441 synth_printf("%s", spk_str_caps_stop
);
445 pr_info("speak_char: cp == NULL!\n");
448 synth_buffer_add(SPACE
);
449 if (IS_CHAR(ch
, B_CAP
)) {
451 synth_printf("%s", spk_str_caps_start
);
452 synth_printf("%s", cp
);
453 synth_printf("%s", spk_str_caps_stop
);
456 synth_printf("%s", spk_msg_get(MSG_CTRL
));
459 synth_printf("%s", cp
);
461 synth_buffer_add(SPACE
);
464 static u16
get_char(struct vc_data
*vc
, u16
*pos
, u_char
*attribs
)
472 pos
= screen_pos(vc
, pos
- (u16
*)vc
->vc_origin
, 1);
476 if (w
& vc
->vc_hi_font_mask
) {
477 w
&= ~vc
->vc_hi_font_mask
;
481 ch
= inverse_translate(vc
, c
, 0);
482 *attribs
= (w
& 0xff00) >> 8;
487 static void say_char(struct vc_data
*vc
)
491 spk_old_attr
= spk_attr
;
492 ch
= get_char(vc
, (u_short
*)spk_pos
, &spk_attr
);
493 if (spk_attr
!= spk_old_attr
) {
494 if (spk_attrib_bleep
& 1)
496 if (spk_attrib_bleep
& 2)
499 speak_char(ch
& 0xff);
502 static void say_phonetic_char(struct vc_data
*vc
)
506 spk_old_attr
= spk_attr
;
507 ch
= get_char(vc
, (u_short
*)spk_pos
, &spk_attr
);
508 if (isascii(ch
) && isalpha(ch
)) {
510 synth_printf("%s\n", phonetic
[--ch
]);
512 if (IS_CHAR(ch
, B_NUM
))
513 synth_printf("%s ", spk_msg_get(MSG_NUMBER
));
518 static void say_prev_char(struct vc_data
*vc
)
522 announce_edge(vc
, edge_left
);
530 static void say_next_char(struct vc_data
*vc
)
533 if (spk_x
== vc
->vc_cols
- 1) {
534 announce_edge(vc
, edge_right
);
542 /* get_word - will first check to see if the character under the
543 * reading cursor is a space and if spk_say_word_ctl is true it will
544 * return the word space. If spk_say_word_ctl is not set it will check to
545 * see if there is a word starting on the next position to the right
546 * and return that word if it exists. If it does not exist it will
547 * move left to the beginning of any previous word on the line or the
548 * beginning off the line whichever comes first..
551 static u_long
get_word(struct vc_data
*vc
)
553 u_long cnt
= 0, tmpx
= spk_x
, tmp_pos
= spk_pos
;
558 spk_old_attr
= spk_attr
;
559 ch
= (char)get_char(vc
, (u_short
*)tmp_pos
, &temp
);
561 /* decided to take out the sayword if on a space (mis-information */
562 if (spk_say_word_ctl
&& ch
== SPACE
) {
564 synth_printf("%s\n", spk_msg_get(MSG_SPACE
));
566 } else if ((tmpx
< vc
->vc_cols
- 2)
567 && (ch
== SPACE
|| ch
== 0 || IS_WDLM(ch
))
568 && ((char)get_char(vc
, (u_short
*)&tmp_pos
+ 1, &temp
) >
574 ch
= (char)get_char(vc
, (u_short
*)tmp_pos
- 1, &temp
);
575 if ((ch
== SPACE
|| ch
== 0 || IS_WDLM(ch
))
576 && ((char)get_char(vc
, (u_short
*)tmp_pos
, &temp
) >
582 attr_ch
= get_char(vc
, (u_short
*)tmp_pos
, &spk_attr
);
583 buf
[cnt
++] = attr_ch
& 0xff;
584 while (tmpx
< vc
->vc_cols
- 1) {
587 ch
= (char)get_char(vc
, (u_short
*)tmp_pos
, &temp
);
588 if ((ch
== SPACE
) || ch
== 0
589 || (IS_WDLM(buf
[cnt
- 1]) && (ch
> SPACE
)))
597 static void say_word(struct vc_data
*vc
)
599 u_long cnt
= get_word(vc
);
600 u_short saved_punc_mask
= spk_punc_mask
;
604 spk_punc_mask
= PUNC
;
606 spkup_write(buf
, cnt
);
607 spk_punc_mask
= saved_punc_mask
;
610 static void say_prev_word(struct vc_data
*vc
)
614 u_short edge_said
= 0, last_state
= 0, state
= 0;
620 announce_edge(vc
, edge_top
);
625 edge_said
= edge_quiet
;
630 edge_said
= edge_top
;
633 if (edge_said
!= edge_quiet
)
634 edge_said
= edge_left
;
638 spk_x
= vc
->vc_cols
- 1;
642 ch
= (char)get_char(vc
, (u_short
*)spk_pos
, &temp
);
643 if (ch
== SPACE
|| ch
== 0)
645 else if (IS_WDLM(ch
))
649 if (state
< last_state
) {
656 if (spk_x
== 0 && edge_said
== edge_quiet
)
657 edge_said
= edge_left
;
658 if (edge_said
> 0 && edge_said
< edge_quiet
)
659 announce_edge(vc
, edge_said
);
663 static void say_next_word(struct vc_data
*vc
)
667 u_short edge_said
= 0, last_state
= 2, state
= 0;
670 if (spk_x
== vc
->vc_cols
- 1 && spk_y
== vc
->vc_rows
- 1) {
671 announce_edge(vc
, edge_bottom
);
675 ch
= (char)get_char(vc
, (u_short
*)spk_pos
, &temp
);
676 if (ch
== SPACE
|| ch
== 0)
678 else if (IS_WDLM(ch
))
682 if (state
> last_state
)
684 if (spk_x
>= vc
->vc_cols
- 1) {
685 if (spk_y
== vc
->vc_rows
- 1) {
686 edge_said
= edge_bottom
;
692 edge_said
= edge_right
;
699 announce_edge(vc
, edge_said
);
703 static void spell_word(struct vc_data
*vc
)
705 static char const *delay_str
[] = { "", ",", ".", ". .", ". . ." };
706 char *cp
= buf
, *str_cap
= spk_str_caps_stop
;
707 char *cp1
, *last_cap
= spk_str_caps_stop
;
712 while ((ch
= (u_char
)*cp
)) {
714 synth_printf(" %s ", delay_str
[spk_spell_delay
]);
715 if (IS_CHAR(ch
, B_CAP
)) {
716 str_cap
= spk_str_caps_start
;
717 if (*spk_str_caps_stop
)
719 else /* synth has no pitch */
720 last_cap
= spk_str_caps_stop
;
722 str_cap
= spk_str_caps_stop
;
723 if (str_cap
!= last_cap
) {
724 synth_printf("%s", str_cap
);
727 if (this_speakup_key
== SPELL_PHONETIC
728 && (isascii(ch
) && isalpha(ch
))) {
730 cp1
= phonetic
[--ch
];
732 cp1
= spk_characters
[ch
];
734 synth_printf("%s", spk_msg_get(MSG_CTRL
));
738 synth_printf("%s", cp1
);
741 if (str_cap
!= spk_str_caps_stop
)
742 synth_printf("%s", spk_str_caps_stop
);
745 static int get_line(struct vc_data
*vc
)
747 u_long tmp
= spk_pos
- (spk_x
* 2);
751 spk_old_attr
= spk_attr
;
752 spk_attr
= get_attributes(vc
, (u_short
*)spk_pos
);
753 for (i
= 0; i
< vc
->vc_cols
; i
++) {
754 buf
[i
] = (u_char
)get_char(vc
, (u_short
*)tmp
, &tmp2
);
757 for (--i
; i
>= 0; i
--)
763 static void say_line(struct vc_data
*vc
)
765 int i
= get_line(vc
);
767 u_short saved_punc_mask
= spk_punc_mask
;
770 synth_printf("%s\n", spk_msg_get(MSG_BLANK
));
774 if (this_speakup_key
== SAY_LINE_INDENT
) {
778 synth_printf("%d, ", (cp
- buf
) + 1);
780 spk_punc_mask
= spk_punc_masks
[spk_reading_punc
];
782 spk_punc_mask
= saved_punc_mask
;
785 static void say_prev_line(struct vc_data
*vc
)
789 announce_edge(vc
, edge_top
);
793 spk_pos
-= vc
->vc_size_row
;
797 static void say_next_line(struct vc_data
*vc
)
800 if (spk_y
== vc
->vc_rows
- 1) {
801 announce_edge(vc
, edge_bottom
);
805 spk_pos
+= vc
->vc_size_row
;
809 static int say_from_to(struct vc_data
*vc
, u_long from
, u_long to
,
814 u_short saved_punc_mask
= spk_punc_mask
;
816 spk_old_attr
= spk_attr
;
817 spk_attr
= get_attributes(vc
, (u_short
*)from
);
819 buf
[i
++] = (char)get_char(vc
, (u_short
*)from
, &tmp
);
821 if (i
>= vc
->vc_size_row
)
824 for (--i
; i
>= 0; i
--)
832 spk_punc_mask
= spk_punc_info
[spk_reading_punc
].mask
;
835 spk_punc_mask
= saved_punc_mask
;
839 static void say_line_from_to(struct vc_data
*vc
, u_long from
, u_long to
,
842 u_long start
= vc
->vc_origin
+ (spk_y
* vc
->vc_size_row
);
843 u_long end
= start
+ (to
* 2);
846 if (say_from_to(vc
, start
, end
, read_punc
) <= 0)
847 if (cursor_track
!= read_all_mode
)
848 synth_printf("%s\n", spk_msg_get(MSG_BLANK
));
851 /* Sentence Reading Commands */
853 static int currsentence
;
854 static int numsentences
[2];
855 static char *sentbufend
[2];
856 static char *sentmarks
[2][10];
859 static char sentbuf
[2][256];
861 static int say_sentence_num(int num
, int prev
)
864 currsentence
= num
+ 1;
865 if (prev
&& --bn
== -1)
868 if (num
> numsentences
[bn
])
871 spkup_write(sentmarks
[bn
][num
], sentbufend
[bn
] - sentmarks
[bn
][num
]);
875 static int get_sentence_buf(struct vc_data
*vc
, int read_punc
)
885 start
= vc
->vc_origin
+ ((spk_y
) * vc
->vc_size_row
);
886 end
= vc
->vc_origin
+ ((spk_y
) * vc
->vc_size_row
) + vc
->vc_cols
* 2;
888 numsentences
[bn
] = 0;
889 sentmarks
[bn
][0] = &sentbuf
[bn
][0];
891 spk_old_attr
= spk_attr
;
892 spk_attr
= get_attributes(vc
, (u_short
*)start
);
894 while (start
< end
) {
895 sentbuf
[bn
][i
] = (char)get_char(vc
, (u_short
*)start
, &tmp
);
897 if (sentbuf
[bn
][i
] == SPACE
&& sentbuf
[bn
][i
- 1] == '.'
898 && numsentences
[bn
] < 9) {
899 /* Sentence Marker */
901 sentmarks
[bn
][numsentences
[bn
]] =
907 if (i
>= vc
->vc_size_row
)
911 for (--i
; i
>= 0; i
--)
912 if (sentbuf
[bn
][i
] != SPACE
)
918 sentbuf
[bn
][++i
] = SPACE
;
919 sentbuf
[bn
][++i
] = '\0';
921 sentbufend
[bn
] = &sentbuf
[bn
][i
];
922 return numsentences
[bn
];
925 static void say_screen_from_to(struct vc_data
*vc
, u_long from
, u_long to
)
927 u_long start
= vc
->vc_origin
, end
;
930 start
+= from
* vc
->vc_size_row
;
931 if (to
> vc
->vc_rows
)
933 end
= vc
->vc_origin
+ (to
* vc
->vc_size_row
);
934 for (from
= start
; from
< end
; from
= to
) {
935 to
= from
+ vc
->vc_size_row
;
936 say_from_to(vc
, from
, to
, 1);
940 static void say_screen(struct vc_data
*vc
)
942 say_screen_from_to(vc
, 0, vc
->vc_rows
);
945 static void speakup_win_say(struct vc_data
*vc
)
947 u_long start
, end
, from
, to
;
950 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW
));
953 start
= vc
->vc_origin
+ (win_top
* vc
->vc_size_row
);
954 end
= vc
->vc_origin
+ (win_bottom
* vc
->vc_size_row
);
955 while (start
<= end
) {
956 from
= start
+ (win_left
* 2);
957 to
= start
+ (win_right
* 2);
958 say_from_to(vc
, from
, to
, 1);
959 start
+= vc
->vc_size_row
;
963 static void top_edge(struct vc_data
*vc
)
966 spk_pos
= vc
->vc_origin
+ 2 * spk_x
;
971 static void bottom_edge(struct vc_data
*vc
)
974 spk_pos
+= (vc
->vc_rows
- spk_y
- 1) * vc
->vc_size_row
;
975 spk_y
= vc
->vc_rows
- 1;
979 static void left_edge(struct vc_data
*vc
)
982 spk_pos
-= spk_x
* 2;
987 static void right_edge(struct vc_data
*vc
)
990 spk_pos
+= (vc
->vc_cols
- spk_x
- 1) * 2;
991 spk_x
= vc
->vc_cols
- 1;
995 static void say_first_char(struct vc_data
*vc
)
997 int i
, len
= get_line(vc
);
1002 synth_printf("%s\n", spk_msg_get(MSG_BLANK
));
1005 for (i
= 0; i
< len
; i
++)
1006 if (buf
[i
] != SPACE
)
1009 spk_pos
-= (spk_x
- i
) * 2;
1011 synth_printf("%d, ", ++i
);
1015 static void say_last_char(struct vc_data
*vc
)
1017 int len
= get_line(vc
);
1022 synth_printf("%s\n", spk_msg_get(MSG_BLANK
));
1026 spk_pos
-= (spk_x
- len
) * 2;
1028 synth_printf("%d, ", ++len
);
1032 static void say_position(struct vc_data
*vc
)
1034 synth_printf(spk_msg_get(MSG_POS_INFO
), spk_y
+ 1, spk_x
+ 1,
1039 /* Added by brianb */
1040 static void say_char_num(struct vc_data
*vc
)
1043 u_short ch
= get_char(vc
, (u_short
*)spk_pos
, &tmp
);
1046 synth_printf(spk_msg_get(MSG_CHAR_INFO
), ch
, ch
);
1049 /* these are stub functions to keep keyboard.c happy. */
1051 static void say_from_top(struct vc_data
*vc
)
1053 say_screen_from_to(vc
, 0, spk_y
);
1056 static void say_to_bottom(struct vc_data
*vc
)
1058 say_screen_from_to(vc
, spk_y
, vc
->vc_rows
);
1061 static void say_from_left(struct vc_data
*vc
)
1063 say_line_from_to(vc
, 0, spk_x
, 1);
1066 static void say_to_right(struct vc_data
*vc
)
1068 say_line_from_to(vc
, spk_x
, vc
->vc_cols
, 1);
1071 /* end of stub functions. */
1073 static void spkup_write(const char *in_buf
, int count
)
1075 static int rep_count
;
1076 static u_char ch
= '\0', old_ch
= '\0';
1077 static u_short char_type
, last_type
;
1078 int in_count
= count
;
1082 if (cursor_track
== read_all_mode
) {
1083 /* Insert Sentence Index */
1084 if ((in_buf
== sentmarks
[bn
][currsentence
]) &&
1085 (currsentence
<= numsentences
[bn
]))
1086 synth_insert_next_index(currsentence
++);
1088 ch
= (u_char
)*in_buf
++;
1089 char_type
= spk_chartab
[ch
];
1090 if (ch
== old_ch
&& !(char_type
& B_NUM
)) {
1091 if (++rep_count
> 2)
1094 if ((last_type
& CH_RPT
) && rep_count
> 2) {
1096 synth_printf(spk_msg_get(MSG_REPEAT_DESC
),
1102 if (ch
== spk_lastkey
) {
1104 if (spk_key_echo
== 1 && ch
>= MINECHOCHAR
)
1106 } else if (char_type
& B_ALPHA
) {
1107 if ((synth_flags
& SF_DEC
) && (last_type
& PUNC
))
1108 synth_buffer_add(SPACE
);
1109 synth_printf("%c", ch
);
1110 } else if (char_type
& B_NUM
) {
1112 synth_printf("%c", ch
);
1113 } else if (char_type
& spk_punc_mask
) {
1115 char_type
&= ~PUNC
; /* for dec nospell processing */
1116 } else if (char_type
& SYNTH_OK
) {
1117 /* these are usually puncts like . and , which synth
1118 * needs for expression.
1119 * suppress multiple to get rid of long pauses and
1120 * clear repeat count
1122 * repeats on you don't get nothing repeated count
1125 synth_printf("%c", ch
);
1129 /* send space and record position, if next is num overwrite space */
1131 synth_buffer_add(SPACE
);
1136 last_type
= char_type
;
1139 if (in_count
> 2 && rep_count
> 2) {
1140 if (last_type
& CH_RPT
) {
1142 synth_printf(spk_msg_get(MSG_REPEAT_DESC2
),
1150 static const int NUM_CTL_LABELS
= (MSG_CTL_END
- MSG_CTL_START
+ 1);
1152 static void read_all_doc(struct vc_data
*vc
);
1153 static void cursor_done(u_long data
);
1154 static DEFINE_TIMER(cursor_timer
, cursor_done
, 0, 0);
1156 static void do_handle_shift(struct vc_data
*vc
, u_char value
, char up_flag
)
1158 unsigned long flags
;
1160 if (synth
== NULL
|| up_flag
|| spk_killed
)
1162 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
1163 if (cursor_track
== read_all_mode
) {
1166 del_timer(&cursor_timer
);
1167 spk_shut_up
&= 0xfe;
1172 del_timer(&cursor_timer
);
1173 cursor_track
= prev_cursor_track
;
1174 spk_shut_up
&= 0xfe;
1179 spk_shut_up
&= 0xfe;
1182 if (spk_say_ctrl
&& value
< NUM_CTL_LABELS
)
1183 synth_printf("%s", spk_msg_get(MSG_CTL_START
+ value
));
1184 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1187 static void do_handle_latin(struct vc_data
*vc
, u_char value
, char up_flag
)
1189 unsigned long flags
;
1191 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
1195 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1198 if (synth
== NULL
|| spk_killed
) {
1199 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1202 spk_shut_up
&= 0xfe;
1203 spk_lastkey
= value
;
1206 if (spk_key_echo
== 2 && value
>= MINECHOCHAR
)
1208 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1211 int spk_set_key_info(const u_char
*key_info
, u_char
*k_buffer
)
1213 int i
= 0, states
, key_data_len
;
1214 const u_char
*cp
= key_info
;
1215 u_char
*cp1
= k_buffer
;
1216 u_char ch
, version
, num_keys
;
1219 if (version
!= KEY_MAP_VER
)
1222 states
= (int)cp
[1];
1223 key_data_len
= (states
+ 1) * (num_keys
+ 1);
1224 if (key_data_len
+ SHIFT_TBL_SIZE
+ 4 >= sizeof(spk_key_buf
))
1226 memset(k_buffer
, 0, SHIFT_TBL_SIZE
);
1227 memset(spk_our_keys
, 0, sizeof(spk_our_keys
));
1228 spk_shift_table
= k_buffer
;
1229 spk_our_keys
[0] = spk_shift_table
;
1230 cp1
+= SHIFT_TBL_SIZE
;
1231 memcpy(cp1
, cp
, key_data_len
+ 3);
1232 /* get num_keys, states and data */
1233 cp1
+= 2; /* now pointing at shift states */
1234 for (i
= 1; i
<= states
; i
++) {
1236 if (ch
>= SHIFT_TBL_SIZE
)
1238 spk_shift_table
[ch
] = i
;
1240 keymap_flags
= *cp1
++;
1241 while ((ch
= *cp1
)) {
1244 spk_our_keys
[ch
] = cp1
;
1250 static struct var_t spk_vars
[] = {
1251 /* bell must be first to set high limit */
1252 {BELL_POS
, .u
.n
= {NULL
, 0, 0, 0, 0, 0, NULL
} },
1253 {SPELL_DELAY
, .u
.n
= {NULL
, 0, 0, 4, 0, 0, NULL
} },
1254 {ATTRIB_BLEEP
, .u
.n
= {NULL
, 1, 0, 3, 0, 0, NULL
} },
1255 {BLEEPS
, .u
.n
= {NULL
, 3, 0, 3, 0, 0, NULL
} },
1256 {BLEEP_TIME
, .u
.n
= {NULL
, 30, 1, 200, 0, 0, NULL
} },
1257 {PUNC_LEVEL
, .u
.n
= {NULL
, 1, 0, 4, 0, 0, NULL
} },
1258 {READING_PUNC
, .u
.n
= {NULL
, 1, 0, 4, 0, 0, NULL
} },
1259 {CURSOR_TIME
, .u
.n
= {NULL
, 120, 50, 600, 0, 0, NULL
} },
1260 {SAY_CONTROL
, TOGGLE_0
},
1261 {SAY_WORD_CTL
, TOGGLE_0
},
1262 {NO_INTERRUPT
, TOGGLE_0
},
1263 {KEY_ECHO
, .u
.n
= {NULL
, 1, 0, 2, 0, 0, NULL
} },
1267 static void toggle_cursoring(struct vc_data
*vc
)
1269 if (cursor_track
== read_all_mode
)
1270 cursor_track
= prev_cursor_track
;
1271 if (++cursor_track
>= CT_Max
)
1273 synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START
+ cursor_track
));
1276 void spk_reset_default_chars(void)
1280 /* First, free any non-default */
1281 for (i
= 0; i
< 256; i
++) {
1282 if ((spk_characters
[i
] != NULL
)
1283 && (spk_characters
[i
] != spk_default_chars
[i
]))
1284 kfree(spk_characters
[i
]);
1287 memcpy(spk_characters
, spk_default_chars
, sizeof(spk_default_chars
));
1290 void spk_reset_default_chartab(void)
1292 memcpy(spk_chartab
, default_chartab
, sizeof(default_chartab
));
1295 static const struct st_bits_data
*pb_edit
;
1297 static int edit_bits(struct vc_data
*vc
, u_char type
, u_char ch
, u_short key
)
1299 short mask
= pb_edit
->mask
, ch_type
= spk_chartab
[ch
];
1301 if (type
!= KT_LATIN
|| (ch_type
& B_NUM
) || ch
< SPACE
)
1304 synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE
));
1305 spk_special_handler
= NULL
;
1308 if (mask
< PUNC
&& !(ch_type
& PUNC
))
1310 spk_chartab
[ch
] ^= mask
;
1312 synth_printf(" %s\n",
1313 (spk_chartab
[ch
] & mask
) ? spk_msg_get(MSG_ON
) :
1314 spk_msg_get(MSG_OFF
));
1318 /* Allocation concurrency is protected by the console semaphore */
1319 static int speakup_allocate(struct vc_data
*vc
)
1323 vc_num
= vc
->vc_num
;
1324 if (speakup_console
[vc_num
] == NULL
) {
1325 speakup_console
[vc_num
] = kzalloc(sizeof(*speakup_console
[0]),
1327 if (speakup_console
[vc_num
] == NULL
)
1330 } else if (!spk_parked
)
1336 static void speakup_deallocate(struct vc_data
*vc
)
1340 vc_num
= vc
->vc_num
;
1341 kfree(speakup_console
[vc_num
]);
1342 speakup_console
[vc_num
] = NULL
;
1345 static u_char is_cursor
;
1346 static u_long old_cursor_pos
, old_cursor_x
, old_cursor_y
;
1347 static int cursor_con
;
1349 static void reset_highlight_buffers(struct vc_data
*);
1351 static int read_all_key
;
1353 static void start_read_all_timer(struct vc_data
*vc
, int command
);
1367 static void kbd_fakekey2(struct vc_data
*vc
, int command
)
1369 del_timer(&cursor_timer
);
1370 speakup_fake_down_arrow();
1371 start_read_all_timer(vc
, command
);
1374 static void read_all_doc(struct vc_data
*vc
)
1376 if ((vc
->vc_num
!= fg_console
) || synth
== NULL
|| spk_shut_up
)
1378 if (!synth_supports_indexing())
1380 if (cursor_track
!= read_all_mode
)
1381 prev_cursor_track
= cursor_track
;
1382 cursor_track
= read_all_mode
;
1383 spk_reset_index_count(0);
1384 if (get_sentence_buf(vc
, 0) == -1)
1385 kbd_fakekey2(vc
, RA_DOWN_ARROW
);
1387 say_sentence_num(0, 0);
1388 synth_insert_next_index(0);
1389 start_read_all_timer(vc
, RA_TIMER
);
1393 static void stop_read_all(struct vc_data
*vc
)
1395 del_timer(&cursor_timer
);
1396 cursor_track
= prev_cursor_track
;
1397 spk_shut_up
&= 0xfe;
1401 static void start_read_all_timer(struct vc_data
*vc
, int command
)
1403 struct var_t
*cursor_timeout
;
1405 cursor_con
= vc
->vc_num
;
1406 read_all_key
= command
;
1407 cursor_timeout
= spk_get_var(CURSOR_TIME
);
1408 mod_timer(&cursor_timer
,
1409 jiffies
+ msecs_to_jiffies(cursor_timeout
->u
.n
.value
));
1412 static void handle_cursor_read_all(struct vc_data
*vc
, int command
)
1414 int indcount
, sentcount
, rv
, sn
;
1418 /* Get Current Sentence */
1419 spk_get_index_count(&indcount
, &sentcount
);
1420 /*printk("%d %d ", indcount, sentcount); */
1421 spk_reset_index_count(sentcount
+ 1);
1422 if (indcount
== 1) {
1423 if (!say_sentence_num(sentcount
+ 1, 0)) {
1424 kbd_fakekey2(vc
, RA_FIND_NEXT_SENT
);
1427 synth_insert_next_index(0);
1430 if (!say_sentence_num(sentcount
+ 1, 1)) {
1432 spk_reset_index_count(sn
);
1434 synth_insert_next_index(0);
1435 if (!say_sentence_num(sn
, 0)) {
1436 kbd_fakekey2(vc
, RA_FIND_NEXT_SENT
);
1439 synth_insert_next_index(0);
1441 start_read_all_timer(vc
, RA_TIMER
);
1451 if (get_sentence_buf(vc
, 0) == -1) {
1452 kbd_fakekey2(vc
, RA_DOWN_ARROW
);
1454 say_sentence_num(0, 0);
1455 synth_insert_next_index(0);
1456 start_read_all_timer(vc
, RA_TIMER
);
1459 case RA_FIND_NEXT_SENT
:
1460 rv
= get_sentence_buf(vc
, 0);
1464 kbd_fakekey2(vc
, RA_FIND_NEXT_SENT
);
1466 say_sentence_num(1, 0);
1467 synth_insert_next_index(0);
1468 start_read_all_timer(vc
, RA_TIMER
);
1471 case RA_FIND_PREV_SENT
:
1474 spk_get_index_count(&indcount
, &sentcount
);
1476 kbd_fakekey2(vc
, RA_DOWN_ARROW
);
1478 start_read_all_timer(vc
, RA_TIMER
);
1483 static int pre_handle_cursor(struct vc_data
*vc
, u_char value
, char up_flag
)
1485 unsigned long flags
;
1487 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
1488 if (cursor_track
== read_all_mode
) {
1490 if (synth
== NULL
|| up_flag
|| spk_shut_up
) {
1491 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1494 del_timer(&cursor_timer
);
1495 spk_shut_up
&= 0xfe;
1497 start_read_all_timer(vc
, value
+ 1);
1498 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1501 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1505 static void do_handle_cursor(struct vc_data
*vc
, u_char value
, char up_flag
)
1507 unsigned long flags
;
1508 struct var_t
*cursor_timeout
;
1510 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
1512 if (synth
== NULL
|| up_flag
|| spk_shut_up
|| cursor_track
== CT_Off
) {
1513 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1516 spk_shut_up
&= 0xfe;
1519 /* the key press flushes if !no_inter but we want to flush on cursor
1520 * moves regardless of no_inter state
1522 is_cursor
= value
+ 1;
1523 old_cursor_pos
= vc
->vc_pos
;
1524 old_cursor_x
= vc
->vc_x
;
1525 old_cursor_y
= vc
->vc_y
;
1526 speakup_console
[vc
->vc_num
]->ht
.cy
= vc
->vc_y
;
1527 cursor_con
= vc
->vc_num
;
1528 if (cursor_track
== CT_Highlight
)
1529 reset_highlight_buffers(vc
);
1530 cursor_timeout
= spk_get_var(CURSOR_TIME
);
1531 mod_timer(&cursor_timer
,
1532 jiffies
+ msecs_to_jiffies(cursor_timeout
->u
.n
.value
));
1533 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1536 static void update_color_buffer(struct vc_data
*vc
, const char *ic
, int len
)
1539 int vc_num
= vc
->vc_num
;
1541 bi
= (vc
->vc_attr
& 0x70) >> 4;
1542 hi
= speakup_console
[vc_num
]->ht
.highsize
[bi
];
1545 if (speakup_console
[vc_num
]->ht
.highsize
[bi
] == 0) {
1546 speakup_console
[vc_num
]->ht
.rpos
[bi
] = vc
->vc_pos
;
1547 speakup_console
[vc_num
]->ht
.rx
[bi
] = vc
->vc_x
;
1548 speakup_console
[vc_num
]->ht
.ry
[bi
] = vc
->vc_y
;
1550 while ((hi
< COLOR_BUFFER_SIZE
) && (i
< len
)) {
1551 if ((ic
[i
] > 32) && (ic
[i
] < 127)) {
1552 speakup_console
[vc_num
]->ht
.highbuf
[bi
][hi
] = ic
[i
];
1554 } else if ((ic
[i
] == 32) && (hi
!= 0)) {
1555 if (speakup_console
[vc_num
]->ht
.highbuf
[bi
][hi
- 1] !=
1557 speakup_console
[vc_num
]->ht
.highbuf
[bi
][hi
] =
1564 speakup_console
[vc_num
]->ht
.highsize
[bi
] = hi
;
1567 static void reset_highlight_buffers(struct vc_data
*vc
)
1570 int vc_num
= vc
->vc_num
;
1572 for (i
= 0; i
< 8; i
++)
1573 speakup_console
[vc_num
]->ht
.highsize
[i
] = 0;
1576 static int count_highlight_color(struct vc_data
*vc
)
1580 int vc_num
= vc
->vc_num
;
1582 u16
*start
= (u16
*)vc
->vc_origin
;
1584 for (i
= 0; i
< 8; i
++)
1585 speakup_console
[vc_num
]->ht
.bgcount
[i
] = 0;
1587 for (i
= 0; i
< vc
->vc_rows
; i
++) {
1588 u16
*end
= start
+ vc
->vc_cols
* 2;
1591 for (ptr
= start
; ptr
< end
; ptr
++) {
1592 ch
= get_attributes(vc
, ptr
);
1593 bg
= (ch
& 0x70) >> 4;
1594 speakup_console
[vc_num
]->ht
.bgcount
[bg
]++;
1596 start
+= vc
->vc_size_row
;
1600 for (i
= 0; i
< 8; i
++)
1601 if (speakup_console
[vc_num
]->ht
.bgcount
[i
] > 0)
1606 static int get_highlight_color(struct vc_data
*vc
)
1609 unsigned int cptr
[8];
1610 int vc_num
= vc
->vc_num
;
1612 for (i
= 0; i
< 8; i
++)
1615 for (i
= 0; i
< 7; i
++)
1616 for (j
= i
+ 1; j
< 8; j
++)
1617 if (speakup_console
[vc_num
]->ht
.bgcount
[cptr
[i
]] >
1618 speakup_console
[vc_num
]->ht
.bgcount
[cptr
[j
]])
1619 swap(cptr
[i
], cptr
[j
]);
1621 for (i
= 0; i
< 8; i
++)
1622 if (speakup_console
[vc_num
]->ht
.bgcount
[cptr
[i
]] != 0)
1623 if (speakup_console
[vc_num
]->ht
.highsize
[cptr
[i
]] > 0)
1628 static int speak_highlight(struct vc_data
*vc
)
1631 int vc_num
= vc
->vc_num
;
1633 if (count_highlight_color(vc
) == 1)
1635 hc
= get_highlight_color(vc
);
1637 d
= vc
->vc_y
- speakup_console
[vc_num
]->ht
.cy
;
1638 if ((d
== 1) || (d
== -1))
1639 if (speakup_console
[vc_num
]->ht
.ry
[hc
] != vc
->vc_y
)
1643 spkup_write(speakup_console
[vc_num
]->ht
.highbuf
[hc
],
1644 speakup_console
[vc_num
]->ht
.highsize
[hc
]);
1645 spk_pos
= spk_cp
= speakup_console
[vc_num
]->ht
.rpos
[hc
];
1646 spk_x
= spk_cx
= speakup_console
[vc_num
]->ht
.rx
[hc
];
1647 spk_y
= spk_cy
= speakup_console
[vc_num
]->ht
.ry
[hc
];
1653 static void cursor_done(u_long data
)
1655 struct vc_data
*vc
= vc_cons
[cursor_con
].d
;
1656 unsigned long flags
;
1658 del_timer(&cursor_timer
);
1659 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
1660 if (cursor_con
!= fg_console
) {
1666 if (vc
->vc_x
>= win_left
&& vc
->vc_x
<= win_right
&&
1667 vc
->vc_y
>= win_top
&& vc
->vc_y
<= win_bottom
) {
1673 if (cursor_track
== read_all_mode
) {
1674 handle_cursor_read_all(vc
, read_all_key
);
1677 if (cursor_track
== CT_Highlight
) {
1678 if (speak_highlight(vc
)) {
1684 if (cursor_track
== CT_Window
)
1685 speakup_win_say(vc
);
1686 else if (is_cursor
== 1 || is_cursor
== 4)
1687 say_line_from_to(vc
, 0, vc
->vc_cols
, 0);
1693 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1696 /* called by: vt_notifier_call() */
1697 static void speakup_bs(struct vc_data
*vc
)
1699 unsigned long flags
;
1701 if (!speakup_console
[vc
->vc_num
])
1703 if (!spin_trylock_irqsave(&speakup_info
.spinlock
, flags
))
1704 /* Speakup output, discard */
1708 if (spk_shut_up
|| synth
== NULL
) {
1709 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1712 if (vc
->vc_num
== fg_console
&& spk_keydown
) {
1717 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1720 /* called by: vt_notifier_call() */
1721 static void speakup_con_write(struct vc_data
*vc
, const char *str
, int len
)
1723 unsigned long flags
;
1725 if ((vc
->vc_num
!= fg_console
) || spk_shut_up
|| synth
== NULL
)
1727 if (!spin_trylock_irqsave(&speakup_info
.spinlock
, flags
))
1728 /* Speakup output, discard */
1730 if (spk_bell_pos
&& spk_keydown
&& (vc
->vc_x
== spk_bell_pos
- 1))
1732 if ((is_cursor
) || (cursor_track
== read_all_mode
)) {
1733 if (cursor_track
== CT_Highlight
)
1734 update_color_buffer(vc
, str
, len
);
1735 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1739 if (vc
->vc_x
>= win_left
&& vc
->vc_x
<= win_right
&&
1740 vc
->vc_y
>= win_top
&& vc
->vc_y
<= win_bottom
) {
1741 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1746 spkup_write(str
, len
);
1747 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1750 static void speakup_con_update(struct vc_data
*vc
)
1752 unsigned long flags
;
1754 if (speakup_console
[vc
->vc_num
] == NULL
|| spk_parked
)
1756 if (!spin_trylock_irqsave(&speakup_info
.spinlock
, flags
))
1757 /* Speakup output, discard */
1760 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1763 static void do_handle_spec(struct vc_data
*vc
, u_char value
, char up_flag
)
1765 unsigned long flags
;
1769 if (synth
== NULL
|| up_flag
|| spk_killed
)
1771 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
1772 spk_shut_up
&= 0xfe;
1777 label
= spk_msg_get(MSG_KEYNAME_CAPSLOCK
);
1778 on_off
= vt_get_leds(fg_console
, VC_CAPSLOCK
);
1781 label
= spk_msg_get(MSG_KEYNAME_NUMLOCK
);
1782 on_off
= vt_get_leds(fg_console
, VC_NUMLOCK
);
1785 label
= spk_msg_get(MSG_KEYNAME_SCROLLLOCK
);
1786 on_off
= vt_get_leds(fg_console
, VC_SCROLLOCK
);
1787 if (speakup_console
[vc
->vc_num
])
1788 speakup_console
[vc
->vc_num
]->tty_stopped
= on_off
;
1792 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1796 synth_printf("%s %s\n",
1797 label
, spk_msg_get(MSG_STATUS_START
+ on_off
));
1798 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
1801 static int inc_dec_var(u_char value
)
1803 struct st_var_header
*p_header
;
1804 struct var_t
*var_data
;
1808 int var_id
= (int)value
- VAR_START
;
1809 int how
= (var_id
& 1) ? E_INC
: E_DEC
;
1811 var_id
= var_id
/ 2 + FIRST_SET_VAR
;
1812 p_header
= spk_get_var_header(var_id
);
1813 if (p_header
== NULL
)
1815 if (p_header
->var_type
!= VAR_NUM
)
1817 var_data
= p_header
->data
;
1818 if (spk_set_num_var(1, p_header
, how
) != 0)
1820 if (!spk_close_press
) {
1821 for (pn
= p_header
->name
; *pn
; pn
++) {
1828 snprintf(cp
, sizeof(num_buf
) - (cp
- num_buf
), " %d ",
1829 var_data
->u
.n
.value
);
1830 synth_printf("%s", num_buf
);
1834 static void speakup_win_set(struct vc_data
*vc
)
1838 if (win_start
> 1) {
1839 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET
));
1842 if (spk_x
< win_left
|| spk_y
< win_top
) {
1843 synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START
));
1846 if (win_start
&& spk_x
== win_left
&& spk_y
== win_top
) {
1848 win_right
= vc
->vc_cols
- 1;
1850 snprintf(info
, sizeof(info
), spk_msg_get(MSG_WINDOW_LINE
),
1860 snprintf(info
, sizeof(info
), spk_msg_get(MSG_WINDOW_BOUNDARY
),
1862 spk_msg_get(MSG_END
) : spk_msg_get(MSG_START
),
1863 (int)spk_y
+ 1, (int)spk_x
+ 1);
1865 synth_printf("%s\n", info
);
1869 static void speakup_win_clear(struct vc_data
*vc
)
1876 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED
));
1879 static void speakup_win_enable(struct vc_data
*vc
)
1881 if (win_start
< 2) {
1882 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW
));
1887 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED
));
1889 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED
));
1892 static void speakup_bits(struct vc_data
*vc
)
1894 int val
= this_speakup_key
- (FIRST_EDIT_BITS
- 1);
1896 if (spk_special_handler
!= NULL
|| val
< 1 || val
> 6) {
1897 synth_printf("%s\n", spk_msg_get(MSG_ERROR
));
1900 pb_edit
= &spk_punc_info
[val
];
1901 synth_printf(spk_msg_get(MSG_EDIT_PROMPT
), pb_edit
->name
);
1902 spk_special_handler
= edit_bits
;
1905 static int handle_goto(struct vc_data
*vc
, u_char type
, u_char ch
, u_short key
)
1907 static u_char goto_buf
[8];
1912 if (type
== KT_SPKUP
&& ch
== SPEAKUP_GOTO
)
1914 if (type
== KT_LATIN
&& ch
== '\n')
1921 ch
= goto_buf
[--num
];
1922 goto_buf
[num
] = '\0';
1923 spkup_write(&ch
, 1);
1926 if (ch
< '+' || ch
> 'y')
1928 goto_buf
[num
++] = ch
;
1929 goto_buf
[num
] = '\0';
1930 spkup_write(&ch
, 1);
1931 maxlen
= (*goto_buf
>= '0') ? 3 : 4;
1932 if ((ch
== '+' || ch
== '-') && num
== 1)
1934 if (ch
>= '0' && ch
<= '9' && num
< maxlen
)
1936 if (num
< maxlen
- 1 || num
> maxlen
)
1938 if (ch
< 'x' || ch
> 'y') {
1941 synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED
));
1942 goto_buf
[num
= 0] = '\0';
1943 spk_special_handler
= NULL
;
1947 goto_pos
= simple_strtoul(goto_buf
, &cp
, 10);
1950 if (*goto_buf
< '0')
1952 else if (goto_pos
> 0)
1955 if (goto_pos
>= vc
->vc_cols
)
1956 goto_pos
= vc
->vc_cols
- 1;
1959 if (*goto_buf
< '0')
1961 else if (goto_pos
> 0)
1964 if (goto_pos
>= vc
->vc_rows
)
1965 goto_pos
= vc
->vc_rows
- 1;
1968 goto_buf
[num
= 0] = '\0';
1970 spk_special_handler
= NULL
;
1973 spk_pos
-= spk_x
* 2;
1975 spk_pos
+= goto_pos
* 2;
1979 spk_pos
= vc
->vc_origin
+ (goto_pos
* vc
->vc_size_row
);
1985 static void speakup_goto(struct vc_data
*vc
)
1987 if (spk_special_handler
!= NULL
) {
1988 synth_printf("%s\n", spk_msg_get(MSG_ERROR
));
1991 synth_printf("%s\n", spk_msg_get(MSG_GOTO
));
1992 spk_special_handler
= handle_goto
;
1995 static void speakup_help(struct vc_data
*vc
)
1997 spk_handle_help(vc
, KT_SPKUP
, SPEAKUP_HELP
, 0);
2000 static void do_nothing(struct vc_data
*vc
)
2002 return; /* flush done in do_spkup */
2005 static u_char key_speakup
, spk_key_locked
;
2007 static void speakup_lock(struct vc_data
*vc
)
2009 if (!spk_key_locked
) {
2010 spk_key_locked
= 16;
2018 typedef void (*spkup_hand
) (struct vc_data
*);
2019 static spkup_hand spkup_handler
[] = {
2020 /* must be ordered same as defines in speakup.h */
2021 do_nothing
, speakup_goto
, speech_kill
, speakup_shut_up
,
2022 speakup_cut
, speakup_paste
, say_first_char
, say_last_char
,
2023 say_char
, say_prev_char
, say_next_char
,
2024 say_word
, say_prev_word
, say_next_word
,
2025 say_line
, say_prev_line
, say_next_line
,
2026 top_edge
, bottom_edge
, left_edge
, right_edge
,
2027 spell_word
, spell_word
, say_screen
,
2028 say_position
, say_attributes
,
2029 speakup_off
, speakup_parked
, say_line
, /* this is for indent */
2030 say_from_top
, say_to_bottom
,
2031 say_from_left
, say_to_right
,
2032 say_char_num
, speakup_bits
, speakup_bits
, say_phonetic_char
,
2033 speakup_bits
, speakup_bits
, speakup_bits
,
2034 speakup_win_set
, speakup_win_clear
, speakup_win_enable
, speakup_win_say
,
2035 speakup_lock
, speakup_help
, toggle_cursoring
, read_all_doc
, NULL
2038 static void do_spkup(struct vc_data
*vc
, u_char value
)
2040 if (spk_killed
&& value
!= SPEECH_KILL
)
2044 spk_shut_up
&= 0xfe;
2045 this_speakup_key
= value
;
2046 if (value
< SPKUP_MAX_FUNC
&& spkup_handler
[value
]) {
2048 (*spkup_handler
[value
]) (vc
);
2050 if (inc_dec_var(value
) < 0)
2055 static const char *pad_chars
= "0123456789+-*/\015,.?()";
2058 speakup_key(struct vc_data
*vc
, int shift_state
, int keycode
, u_short keysym
,
2061 unsigned long flags
;
2064 u_char type
= KTYP(keysym
), value
= KVAL(keysym
), new_key
= 0;
2065 u_char shift_info
, offset
;
2071 spin_lock_irqsave(&speakup_info
.spinlock
, flags
);
2076 && (vt_get_leds(fg_console
, VC_NUMLOCK
))) {
2081 value
= spk_lastkey
= pad_chars
[value
];
2086 if (keycode
>= MAX_KEY
)
2088 key_info
= spk_our_keys
[keycode
];
2091 /* Check valid read all mode keys */
2092 if ((cursor_track
== read_all_mode
) && (!up_flag
)) {
2106 shift_info
= (shift_state
& 0x0f) + key_speakup
;
2107 offset
= spk_shift_table
[shift_info
];
2109 new_key
= key_info
[offset
];
2112 if (new_key
== SPK_KEY
) {
2113 if (!spk_key_locked
)
2114 key_speakup
= (up_flag
) ? 0 : 16;
2115 if (up_flag
|| spk_killed
)
2117 spk_shut_up
&= 0xfe;
2123 if (last_keycode
== keycode
&&
2124 time_after(last_spk_jiffy
+ MAX_DELAY
, jiffies
)) {
2125 spk_close_press
= 1;
2126 offset
= spk_shift_table
[shift_info
+ 32];
2128 if (offset
&& key_info
[offset
])
2129 new_key
= key_info
[offset
];
2131 last_keycode
= keycode
;
2132 last_spk_jiffy
= jiffies
;
2138 if (type
== KT_SPKUP
&& spk_special_handler
== NULL
) {
2139 do_spkup(vc
, new_key
);
2140 spk_close_press
= 0;
2144 if (up_flag
|| spk_killed
|| type
== KT_SHIFT
)
2146 spk_shut_up
&= 0xfe;
2147 kh
= (value
== KVAL(K_DOWN
))
2148 || (value
== KVAL(K_UP
))
2149 || (value
== KVAL(K_LEFT
))
2150 || (value
== KVAL(K_RIGHT
));
2151 if ((cursor_track
!= read_all_mode
) || !kh
)
2154 if (spk_special_handler
) {
2155 if (type
== KT_SPEC
&& value
== 1) {
2158 } else if (type
== KT_LETTER
)
2160 else if (value
== 0x7f)
2161 value
= 8; /* make del = backspace */
2162 ret
= (*spk_special_handler
) (vc
, type
, value
, keycode
);
2163 spk_close_press
= 0;
2170 spin_unlock_irqrestore(&speakup_info
.spinlock
, flags
);
2174 static int keyboard_notifier_call(struct notifier_block
*nb
,
2175 unsigned long code
, void *_param
)
2177 struct keyboard_notifier_param
*param
= _param
;
2178 struct vc_data
*vc
= param
->vc
;
2179 int up
= !param
->down
;
2180 int ret
= NOTIFY_OK
;
2181 static int keycode
; /* to hold the current keycode */
2183 if (vc
->vc_mode
== KD_GRAPHICS
)
2187 * First, determine whether we are handling a fake keypress on
2188 * the current processor. If we are, then return NOTIFY_OK,
2189 * to pass the keystroke up the chain. This prevents us from
2190 * trying to take the Speakup lock while it is held by the
2191 * processor on which the simulated keystroke was generated.
2192 * Also, the simulated keystrokes should be ignored by Speakup.
2195 if (speakup_fake_key_pressed())
2200 /* speakup requires keycode and keysym currently */
2201 keycode
= param
->value
;
2203 case KBD_UNBOUND_KEYCODE
:
2210 if (speakup_key(vc
, param
->shift
, keycode
, param
->value
, up
))
2212 else if (KTYP(param
->value
) == KT_CUR
)
2213 ret
= pre_handle_cursor(vc
, KVAL(param
->value
), up
);
2215 case KBD_POST_KEYSYM
:{
2216 unsigned char type
= KTYP(param
->value
) - 0xf0;
2217 unsigned char val
= KVAL(param
->value
);
2221 do_handle_shift(vc
, val
, up
);
2225 do_handle_latin(vc
, val
, up
);
2228 do_handle_cursor(vc
, val
, up
);
2231 do_handle_spec(vc
, val
, up
);
2240 static int vt_notifier_call(struct notifier_block
*nb
,
2241 unsigned long code
, void *_param
)
2243 struct vt_notifier_param
*param
= _param
;
2244 struct vc_data
*vc
= param
->vc
;
2248 if (vc
->vc_mode
== KD_TEXT
)
2249 speakup_allocate(vc
);
2252 speakup_deallocate(vc
);
2255 if (param
->c
== '\b')
2257 else if (param
->c
< 0x100) {
2260 speakup_con_write(vc
, &d
, 1);
2264 speakup_con_update(vc
);
2270 /* called by: module_exit() */
2271 static void __exit
speakup_exit(void)
2275 unregister_keyboard_notifier(&keyboard_notifier_block
);
2276 unregister_vt_notifier(&vt_notifier_block
);
2277 speakup_unregister_devsynth();
2278 speakup_cancel_paste();
2279 del_timer_sync(&cursor_timer
);
2280 kthread_stop(speakup_task
);
2281 speakup_task
= NULL
;
2282 mutex_lock(&spk_mutex
);
2284 mutex_unlock(&spk_mutex
);
2286 speakup_kobj_exit();
2288 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
2289 kfree(speakup_console
[i
]);
2291 speakup_remove_virtual_keyboard();
2293 for (i
= 0; i
< MAXVARS
; i
++)
2294 speakup_unregister_var(i
);
2296 for (i
= 0; i
< 256; i
++) {
2297 if (spk_characters
[i
] != spk_default_chars
[i
])
2298 kfree(spk_characters
[i
]);
2301 spk_free_user_msgs();
2304 /* call by: module_init() */
2305 static int __init
speakup_init(void)
2309 struct st_spk_t
*first_console
;
2310 struct vc_data
*vc
= vc_cons
[fg_console
].d
;
2313 /* These first few initializations cannot fail. */
2314 spk_initialize_msgs(); /* Initialize arrays for i18n. */
2315 spk_reset_default_chars();
2316 spk_reset_default_chartab();
2317 spk_strlwr(synth_name
);
2318 spk_vars
[0].u
.n
.high
= vc
->vc_cols
;
2319 for (var
= spk_vars
; var
->var_id
!= MAXVARS
; var
++)
2320 speakup_register_var(var
);
2321 for (var
= synth_time_vars
;
2322 (var
->var_id
>= 0) && (var
->var_id
< MAXVARS
); var
++)
2323 speakup_register_var(var
);
2324 for (i
= 1; spk_punc_info
[i
].mask
!= 0; i
++)
2325 spk_set_mask_bits(NULL
, i
, 2);
2327 spk_set_key_info(spk_key_defaults
, spk_key_buf
);
2329 /* From here on out, initializations can fail. */
2330 err
= speakup_add_virtual_keyboard();
2332 goto error_virtkeyboard
;
2334 first_console
= kzalloc(sizeof(*first_console
), GFP_KERNEL
);
2335 if (!first_console
) {
2340 speakup_console
[vc
->vc_num
] = first_console
;
2343 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
2345 err
= speakup_allocate(vc_cons
[i
].d
);
2347 goto error_kobjects
;
2351 spk_shut_up
|= 0x01;
2353 err
= speakup_kobj_init();
2355 goto error_kobjects
;
2357 synth_init(synth_name
);
2358 speakup_register_devsynth();
2360 * register_devsynth might fail, but this error is not fatal.
2361 * /dev/synth is an extra feature; the rest of Speakup
2362 * will work fine without it.
2365 err
= register_keyboard_notifier(&keyboard_notifier_block
);
2367 goto error_kbdnotifier
;
2368 err
= register_vt_notifier(&vt_notifier_block
);
2370 goto error_vtnotifier
;
2372 speakup_task
= kthread_create(speakup_thread
, NULL
, "speakup");
2374 if (IS_ERR(speakup_task
)) {
2375 err
= PTR_ERR(speakup_task
);
2379 set_user_nice(speakup_task
, 10);
2380 wake_up_process(speakup_task
);
2382 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION
);
2383 pr_info("synth name on entry is: %s\n", synth_name
);
2387 unregister_vt_notifier(&vt_notifier_block
);
2390 unregister_keyboard_notifier(&keyboard_notifier_block
);
2391 del_timer(&cursor_timer
);
2394 speakup_unregister_devsynth();
2395 mutex_lock(&spk_mutex
);
2397 mutex_unlock(&spk_mutex
);
2398 speakup_kobj_exit();
2401 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
2402 kfree(speakup_console
[i
]);
2405 speakup_remove_virtual_keyboard();
2408 for (i
= 0; i
< MAXVARS
; i
++)
2409 speakup_unregister_var(i
);
2411 for (i
= 0; i
< 256; i
++) {
2412 if (spk_characters
[i
] != spk_default_chars
[i
])
2413 kfree(spk_characters
[i
]);
2416 spk_free_user_msgs();
2422 module_init(speakup_init
);
2423 module_exit(speakup_exit
);