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>
26 #include <linux/version.h>
28 #include <linux/tty.h>
29 #include <linux/mm.h> /* __get_free_page() and friends */
30 #include <linux/vt_kern.h>
31 #include <linux/ctype.h>
32 #include <linux/selection.h>
33 #include <linux/unistd.h>
34 #include <linux/jiffies.h>
35 #include <linux/kthread.h>
36 #include <linux/keyboard.h> /* for KT_SHIFT */
37 #include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
38 #include <linux/input.h>
39 #include <linux/kmod.h>
41 #include <linux/bootmem.h> /* for alloc_bootmem */
43 /* speakup_*_selection */
44 #include <linux/module.h>
45 #include <linux/sched.h>
46 #include <linux/slab.h>
47 #include <linux/types.h>
48 #include <linux/consolemap.h>
50 #include <linux/spinlock.h>
51 #include <linux/notifier.h>
53 #include <linux/uaccess.h> /* copy_from|to|user() and others */
58 #define MAX_DELAY msecs_to_jiffies(500)
59 #define MINECHOCHAR SPACE
61 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
62 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
63 MODULE_DESCRIPTION("Speakup console speech");
64 MODULE_LICENSE("GPL");
65 MODULE_VERSION(SPEAKUP_VERSION
);
68 module_param_named(synth
, synth_name
, charp
, S_IRUGO
);
69 module_param_named(quiet
, quiet_boot
, bool, S_IRUGO
);
71 MODULE_PARM_DESC(synth
, "Synth to start if speakup is built in.");
72 MODULE_PARM_DESC(quiet
, "Do not announce when the synthesizer is found.");
74 special_func special_handler
;
76 short pitch_shift
, synth_flags
;
78 int attrib_bleep
, bleeps
, bleep_time
= 10;
79 int no_intr
, spell_delay
;
80 int key_echo
, say_word_ctl
;
81 int say_ctrl
, bell_pos
;
83 int punc_level
, reading_punc
;
84 char str_caps_start
[MAXVARLEN
+ 1] = "\0", str_caps_stop
[MAXVARLEN
+ 1] = "\0";
85 const struct st_bits_data punc_info
[] = {
87 {"some", "/$%&@", SOME
},
88 {"most", "$%&#()=+*/@^<>|\\", MOST
},
89 {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC
},
90 {"delimiters", "", B_WDLM
},
91 {"repeats", "()", CH_RPT
},
92 {"extended numeric", "", B_EXNUM
},
93 {"symbols", "", B_SYM
},
97 static char mark_cut_flag
;
99 u_char
*our_keys
[MAX_KEY
], *shift_table
;
101 const u_char key_defaults
[] = {
102 #include "speakupmap.h"
105 /* Speakup Cursor Track Variables */
106 static int cursor_track
= 1, prev_cursor_track
= 1;
108 /* cursor track modes, must be ordered same as cursor_msgs */
116 #define read_all_mode CT_Max
118 static struct tty_struct
*tty
;
120 static void spkup_write(const char *in_buf
, int count
);
122 static char *phonetic
[] = {
123 "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
124 "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
126 "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
127 "x ray", "yankee", "zulu"
130 /* array of 256 char pointers (one for each character description)
131 * initialized to default_chars and user selectable via
132 * /proc/speakup/characters */
133 char *characters
[256];
135 char *default_chars
[256] = {
136 /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
137 /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
138 /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
139 /*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
141 /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
143 /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
146 /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
148 /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
149 /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
150 /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
151 /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
152 /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
155 /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
156 /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
157 /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
158 /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
159 /*127*/ "del", "control", "control", "control", "control", "control",
160 "control", "control", "control", "control", "control",
161 /*138*/ "control", "control", "control", "control", "control",
162 "control", "control", "control", "control", "control",
163 "control", "control",
164 /*150*/ "control", "control", "control", "control", "control",
165 "control", "control", "control", "control", "control",
166 /*160*/ "nbsp", "inverted bang",
167 /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
168 /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
169 /*172*/ "not", "soft hyphen", "registered", "macron",
170 /*176*/ "degrees", "plus or minus", "super two", "super three",
171 /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
172 /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
173 /*188*/ "one quarter", "one half", "three quarters",
175 /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
177 /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
179 /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
181 /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
182 /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
184 /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
185 /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
186 /*230*/ "ae", "c cidella", "e grave", "e acute",
187 /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
189 /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
191 /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
193 /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
196 /* array of 256 u_short (one for each character)
197 * initialized to default_chartab and user selectable via
198 * /sys/module/speakup/parameters/chartab */
199 u_short spk_chartab
[256];
201 static u_short default_chartab
[256] = {
202 B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, /* 0-7 */
203 B_CTL
, B_CTL
, A_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, /* 8-15 */
204 B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, /*16-23 */
205 B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, B_CTL
, /* 24-31 */
206 WDLM
, A_PUNC
, PUNC
, PUNC
, PUNC
, PUNC
, PUNC
, A_PUNC
, /* !"#$%&' */
207 PUNC
, PUNC
, PUNC
, PUNC
, A_PUNC
, A_PUNC
, A_PUNC
, PUNC
, /* ()*+, -./ */
208 NUM
, NUM
, NUM
, NUM
, NUM
, NUM
, NUM
, NUM
, /* 01234567 */
209 NUM
, NUM
, A_PUNC
, PUNC
, PUNC
, PUNC
, PUNC
, A_PUNC
, /* 89:;<=>? */
210 PUNC
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* @ABCDEFG */
211 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* HIJKLMNO */
212 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* PQRSTUVW */
213 A_CAP
, A_CAP
, A_CAP
, PUNC
, PUNC
, PUNC
, PUNC
, PUNC
, /* XYZ[\]^_ */
214 PUNC
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* `abcdefg */
215 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* hijklmno */
216 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* pqrstuvw */
217 ALPHA
, ALPHA
, ALPHA
, PUNC
, PUNC
, PUNC
, PUNC
, 0, /* xyz{|}~ */
218 B_CAPSYM
, B_CAPSYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 128-134 */
220 B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 136-142 */
222 B_CAPSYM
, B_CAPSYM
, B_SYM
, B_CAPSYM
, B_SYM
, B_SYM
, B_SYM
, /* 144-150 */
224 B_SYM
, B_SYM
, B_CAPSYM
, B_CAPSYM
, B_SYM
, B_SYM
, B_SYM
, /*152-158 */
226 WDLM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_CAPSYM
, /* 160-166 */
228 B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 168-175 */
229 B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 176-183 */
230 B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, B_SYM
, /* 184-191 */
231 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* 192-199 */
232 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, /* 200-207 */
233 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, B_SYM
, /* 208-215 */
234 A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, A_CAP
, ALPHA
, /* 216-223 */
235 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* 224-231 */
236 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, /* 232-239 */
237 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, B_SYM
, /* 240-247 */
238 ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
, ALPHA
/* 248-255 */
241 struct task_struct
*speakup_task
;
242 struct bleep unprocessed_sound
;
243 static int spk_keydown
;
244 static u_char spk_lastkey
, spk_close_press
, keymap_flags
;
245 static u_char last_keycode
, this_speakup_key
;
246 static u_long last_spk_jiffy
;
248 struct st_spk_t
*speakup_console
[MAX_NR_CONSOLES
];
250 DEFINE_MUTEX(spk_mutex
);
252 static int keyboard_notifier_call(struct notifier_block
*,
253 unsigned long code
, void *param
);
255 struct notifier_block keyboard_notifier_block
= {
256 .notifier_call
= keyboard_notifier_call
,
259 static int vt_notifier_call(struct notifier_block
*,
260 unsigned long code
, void *param
);
262 struct notifier_block vt_notifier_block
= {
263 .notifier_call
= vt_notifier_call
,
266 static unsigned char get_attributes(u16
*pos
)
268 return (u_char
) (scr_readw(pos
) >> 8);
271 static void speakup_date(struct vc_data
*vc
)
273 spk_x
= spk_cx
= vc
->vc_x
;
274 spk_y
= spk_cy
= vc
->vc_y
;
275 spk_pos
= spk_cp
= vc
->vc_pos
;
276 spk_old_attr
= spk_attr
;
277 spk_attr
= get_attributes((u_short
*) spk_pos
);
280 static void bleep(u_short val
)
282 static const short vals
[] = {
283 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
286 int time
= bleep_time
;
287 freq
= vals
[val
% 12];
289 freq
*= (1 << (val
/ 12));
290 unprocessed_sound
.freq
= freq
;
291 unprocessed_sound
.jiffies
= msecs_to_jiffies(time
);
292 unprocessed_sound
.active
= 1;
293 /* We can only have 1 active sound at a time. */
296 static void speakup_shut_up(struct vc_data
*vc
)
307 static void speech_kill(struct vc_data
*vc
)
309 char val
= synth
->is_alive(synth
);
313 /* re-enables synth, if disabled */
314 if (val
== 2 || spk_killed
) {
316 spk_shut_up
&= ~0x40;
317 synth_printf("%s\n", msg_get(MSG_IAM_ALIVE
));
319 synth_printf("%s\n", 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", msg_get(MSG_HEY_THATS_BETTER
));
331 synth_printf("%s\n", 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", msg_get(MSG_UNPARKED
));
343 synth_printf("%s\n", 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 xs
= (u_short
) spk_x
;
355 ys
= (u_short
) spk_y
;
357 synth_printf("%s\n", msg_get(MSG_MARK
));
360 xe
= (u_short
) spk_x
;
361 ye
= (u_short
) spk_y
;
363 synth_printf("%s\n", 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", msg_get(MSG_MARK_CLEARED
));
389 synth_printf("%s\n", 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;
399 synth_printf("%s ", msg_get(MSG_BRIGHT
));
402 synth_printf("%s", msg_get(MSG_COLORS_START
+ fg
));
404 synth_printf(" %s ", msg_get(MSG_ON_BLINKING
));
407 synth_printf(" %s ", msg_get(MSG_ON
));
408 synth_printf("%s\n", msg_get(MSG_COLORS_START
+ bg
));
419 static void announce_edge(struct vc_data
*vc
, int msg_id
)
423 if ((bleeps
& 2) && (msg_id
< edge_quiet
))
424 synth_printf("%s\n", msg_get(MSG_EDGE_MSGS_START
+ msg_id
- 1));
427 static void speak_char(u_char ch
)
429 char *cp
= characters
[ch
];
430 struct var_t
*direct
= get_var(DIRECT
);
431 if (direct
&& direct
->u
.n
.value
) {
432 if (IS_CHAR(ch
, B_CAP
)) {
434 synth_printf("%s", str_caps_start
);
436 synth_printf("%c", ch
);
437 if (IS_CHAR(ch
, B_CAP
))
438 synth_printf("%s", str_caps_stop
);
442 pr_info("speak_char: cp == NULL!\n");
445 synth_buffer_add(SPACE
);
446 if (IS_CHAR(ch
, B_CAP
)) {
448 synth_printf("%s", str_caps_start
);
449 synth_printf("%s", cp
);
450 synth_printf("%s", str_caps_stop
);
453 synth_printf("%s", msg_get(MSG_CTRL
));
456 synth_printf("%s", cp
);
458 synth_buffer_add(SPACE
);
461 static u16
get_char(struct vc_data
*vc
, u16
* pos
, u_char
* attribs
)
465 u16 w
= scr_readw(pos
);
468 if (w
& vc
->vc_hi_font_mask
)
471 ch
= inverse_translate(vc
, c
, 0);
472 *attribs
= (w
& 0xff00) >> 8;
477 static void say_char(struct vc_data
*vc
)
480 spk_old_attr
= spk_attr
;
481 ch
= get_char(vc
, (u_short
*) spk_pos
, &spk_attr
);
482 if (spk_attr
!= spk_old_attr
) {
483 if (attrib_bleep
& 1)
485 if (attrib_bleep
& 2)
488 speak_char(ch
& 0xff);
491 static void say_phonetic_char(struct vc_data
*vc
)
494 spk_old_attr
= spk_attr
;
495 ch
= get_char(vc
, (u_short
*) spk_pos
, &spk_attr
);
496 if (isascii(ch
) && isalpha(ch
)) {
498 synth_printf("%s\n", phonetic
[--ch
]);
500 if (IS_CHAR(ch
, B_NUM
))
501 synth_printf("%s ", msg_get(MSG_NUMBER
));
506 static void say_prev_char(struct vc_data
*vc
)
510 announce_edge(vc
, edge_left
);
518 static void say_next_char(struct vc_data
*vc
)
521 if (spk_x
== vc
->vc_cols
- 1) {
522 announce_edge(vc
, edge_right
);
530 /* get_word - will first check to see if the character under the
531 * reading cursor is a space and if say_word_ctl is true it will
532 * return the word space. If say_word_ctl is not set it will check to
533 * see if there is a word starting on the next position to the right
534 * and return that word if it exists. If it does not exist it will
535 * move left to the beginning of any previous word on the line or the
536 * beginning off the line whichever comes first.. */
538 static u_long
get_word(struct vc_data
*vc
)
540 u_long cnt
= 0, tmpx
= spk_x
, tmp_pos
= spk_pos
;
544 spk_old_attr
= spk_attr
;
545 ch
= (char)get_char(vc
, (u_short
*) tmp_pos
, &temp
);
547 /* decided to take out the sayword if on a space (mis-information */
548 if (say_word_ctl
&& ch
== SPACE
) {
550 synth_printf("%s\n", msg_get(MSG_SPACE
));
552 } else if ((tmpx
< vc
->vc_cols
- 2)
553 && (ch
== SPACE
|| ch
== 0 || IS_WDLM(ch
))
554 && ((char)get_char(vc
, (u_short
*) &tmp_pos
+ 1, &temp
) >
560 ch
= (char)get_char(vc
, (u_short
*) tmp_pos
- 1, &temp
);
561 if ((ch
== SPACE
|| ch
== 0 || IS_WDLM(ch
))
562 && ((char)get_char(vc
, (u_short
*) tmp_pos
, &temp
) >
568 attr_ch
= get_char(vc
, (u_short
*) tmp_pos
, &spk_attr
);
569 buf
[cnt
++] = attr_ch
& 0xff;
570 while (tmpx
< vc
->vc_cols
- 1) {
573 ch
= (char)get_char(vc
, (u_short
*) tmp_pos
, &temp
);
574 if ((ch
== SPACE
) || ch
== 0
575 || (IS_WDLM(buf
[cnt
- 1]) && (ch
> SPACE
)))
583 static void say_word(struct vc_data
*vc
)
585 u_long cnt
= get_word(vc
);
586 u_short saved_punc_mask
= punc_mask
;
591 spkup_write(buf
, cnt
);
592 punc_mask
= saved_punc_mask
;
595 static void say_prev_word(struct vc_data
*vc
)
599 u_short edge_said
= 0, last_state
= 0, state
= 0;
604 announce_edge(vc
, edge_top
);
609 edge_said
= edge_quiet
;
614 edge_said
= edge_top
;
617 if (edge_said
!= edge_quiet
)
618 edge_said
= edge_left
;
622 spk_x
= vc
->vc_cols
- 1;
626 ch
= (char)get_char(vc
, (u_short
*) spk_pos
, &temp
);
627 if (ch
== SPACE
|| ch
== 0)
629 else if (IS_WDLM(ch
))
633 if (state
< last_state
) {
640 if (spk_x
== 0 && edge_said
== edge_quiet
)
641 edge_said
= edge_left
;
642 if (edge_said
> 0 && edge_said
< edge_quiet
)
643 announce_edge(vc
, edge_said
);
647 static void say_next_word(struct vc_data
*vc
)
651 u_short edge_said
= 0, last_state
= 2, state
= 0;
654 if (spk_x
== vc
->vc_cols
- 1 && spk_y
== vc
->vc_rows
- 1) {
655 announce_edge(vc
, edge_bottom
);
659 ch
= (char)get_char(vc
, (u_short
*) spk_pos
, &temp
);
660 if (ch
== SPACE
|| ch
== 0)
662 else if (IS_WDLM(ch
))
666 if (state
> last_state
)
668 if (spk_x
>= vc
->vc_cols
- 1) {
669 if (spk_y
== vc
->vc_rows
- 1) {
670 edge_said
= edge_bottom
;
676 edge_said
= edge_right
;
683 announce_edge(vc
, edge_said
);
687 static void spell_word(struct vc_data
*vc
)
689 static char *delay_str
[] = { "", ",", ".", ". .", ". . ." };
690 char *cp
= buf
, *str_cap
= str_caps_stop
;
691 char *cp1
, *last_cap
= str_caps_stop
;
695 while ((ch
= (u_char
) *cp
)) {
697 synth_printf(" %s ", delay_str
[spell_delay
]);
698 if (IS_CHAR(ch
, B_CAP
)) {
699 str_cap
= str_caps_start
;
702 else /* synth has no pitch */
703 last_cap
= str_caps_stop
;
705 str_cap
= str_caps_stop
;
706 if (str_cap
!= last_cap
) {
707 synth_printf("%s", str_cap
);
710 if (this_speakup_key
== SPELL_PHONETIC
711 && (isascii(ch
) && isalpha(ch
))) {
713 cp1
= phonetic
[--ch
];
715 cp1
= characters
[ch
];
717 synth_printf("%s", msg_get(MSG_CTRL
));
721 synth_printf("%s", cp1
);
724 if (str_cap
!= str_caps_stop
)
725 synth_printf("%s", str_caps_stop
);
728 static int get_line(struct vc_data
*vc
)
730 u_long tmp
= spk_pos
- (spk_x
* 2);
734 spk_old_attr
= spk_attr
;
735 spk_attr
= get_attributes((u_short
*) spk_pos
);
736 for (i
= 0; i
< vc
->vc_cols
; i
++) {
737 buf
[i
] = (u_char
) get_char(vc
, (u_short
*) tmp
, &tmp2
);
740 for (--i
; i
>= 0; i
--)
746 static void say_line(struct vc_data
*vc
)
748 int i
= get_line(vc
);
750 u_short saved_punc_mask
= punc_mask
;
752 synth_printf("%s\n", msg_get(MSG_BLANK
));
756 if (this_speakup_key
== SAY_LINE_INDENT
) {
760 synth_printf("%d, ", (cp
- buf
) + 1);
762 punc_mask
= punc_masks
[reading_punc
];
764 punc_mask
= saved_punc_mask
;
767 static void say_prev_line(struct vc_data
*vc
)
771 announce_edge(vc
, edge_top
);
775 spk_pos
-= vc
->vc_size_row
;
779 static void say_next_line(struct vc_data
*vc
)
782 if (spk_y
== vc
->vc_rows
- 1) {
783 announce_edge(vc
, edge_bottom
);
787 spk_pos
+= vc
->vc_size_row
;
791 static int say_from_to(struct vc_data
*vc
, u_long from
, u_long to
,
796 u_short saved_punc_mask
= punc_mask
;
797 spk_old_attr
= spk_attr
;
798 spk_attr
= get_attributes((u_short
*) from
);
800 buf
[i
++] = (char)get_char(vc
, (u_short
*) from
, &tmp
);
802 if (i
>= vc
->vc_size_row
)
805 for (--i
; i
>= 0; i
--)
813 punc_mask
= punc_info
[reading_punc
].mask
;
816 punc_mask
= saved_punc_mask
;
820 static void say_line_from_to(struct vc_data
*vc
, u_long from
, u_long to
,
823 u_long start
= vc
->vc_origin
+ (spk_y
* vc
->vc_size_row
);
824 u_long end
= start
+ (to
* 2);
826 if (say_from_to(vc
, start
, end
, read_punc
) <= 0)
827 if (cursor_track
!= read_all_mode
)
828 synth_printf("%s\n", msg_get(MSG_BLANK
));
831 /* Sentence Reading Commands */
833 static int currsentence
;
834 static int numsentences
[2];
835 static char *sentbufend
[2];
836 static char *sentmarks
[2][10];
839 static char sentbuf
[2][256];
841 static int say_sentence_num(int num
, int prev
)
844 currsentence
= num
+ 1;
845 if (prev
&& --bn
== -1)
848 if (num
> numsentences
[bn
])
851 spkup_write(sentmarks
[bn
][num
], sentbufend
[bn
] - sentmarks
[bn
][num
]);
855 static int get_sentence_buf(struct vc_data
*vc
, int read_punc
)
865 start
= vc
->vc_origin
+ ((spk_y
) * vc
->vc_size_row
);
866 end
= vc
->vc_origin
+ ((spk_y
) * vc
->vc_size_row
) + vc
->vc_cols
* 2;
868 numsentences
[bn
] = 0;
869 sentmarks
[bn
][0] = &sentbuf
[bn
][0];
871 spk_old_attr
= spk_attr
;
872 spk_attr
= get_attributes((u_short
*) start
);
874 while (start
< end
) {
875 sentbuf
[bn
][i
] = (char)get_char(vc
, (u_short
*) start
, &tmp
);
877 if (sentbuf
[bn
][i
] == SPACE
&& sentbuf
[bn
][i
- 1] == '.'
878 && numsentences
[bn
] < 9) {
879 /* Sentence Marker */
881 sentmarks
[bn
][numsentences
[bn
]] =
887 if (i
>= vc
->vc_size_row
)
891 for (--i
; i
>= 0; i
--)
892 if (sentbuf
[bn
][i
] != SPACE
)
898 sentbuf
[bn
][++i
] = SPACE
;
899 sentbuf
[bn
][++i
] = '\0';
901 sentbufend
[bn
] = &sentbuf
[bn
][i
];
902 return numsentences
[bn
];
905 static void say_screen_from_to(struct vc_data
*vc
, u_long from
, u_long to
)
907 u_long start
= vc
->vc_origin
, end
;
909 start
+= from
* vc
->vc_size_row
;
910 if (to
> vc
->vc_rows
)
912 end
= vc
->vc_origin
+ (to
* vc
->vc_size_row
);
913 for (from
= start
; from
< end
; from
= to
) {
914 to
= from
+ vc
->vc_size_row
;
915 say_from_to(vc
, from
, to
, 1);
919 static void say_screen(struct vc_data
*vc
)
921 say_screen_from_to(vc
, 0, vc
->vc_rows
);
924 static void speakup_win_say(struct vc_data
*vc
)
926 u_long start
, end
, from
, to
;
928 synth_printf("%s\n", msg_get(MSG_NO_WINDOW
));
931 start
= vc
->vc_origin
+ (win_top
* vc
->vc_size_row
);
932 end
= vc
->vc_origin
+ (win_bottom
* vc
->vc_size_row
);
933 while (start
<= end
) {
934 from
= start
+ (win_left
* 2);
935 to
= start
+ (win_right
* 2);
936 say_from_to(vc
, from
, to
, 1);
937 start
+= vc
->vc_size_row
;
941 static void top_edge(struct vc_data
*vc
)
944 spk_pos
= vc
->vc_origin
+ 2 * spk_x
;
949 static void bottom_edge(struct vc_data
*vc
)
952 spk_pos
+= (vc
->vc_rows
- spk_y
- 1) * vc
->vc_size_row
;
953 spk_y
= vc
->vc_rows
- 1;
957 static void left_edge(struct vc_data
*vc
)
960 spk_pos
-= spk_x
* 2;
965 static void right_edge(struct vc_data
*vc
)
968 spk_pos
+= (vc
->vc_cols
- spk_x
- 1) * 2;
969 spk_x
= vc
->vc_cols
- 1;
973 static void say_first_char(struct vc_data
*vc
)
975 int i
, len
= get_line(vc
);
979 synth_printf("%s\n", msg_get(MSG_BLANK
));
982 for (i
= 0; i
< len
; i
++)
986 spk_pos
-= (spk_x
- i
) * 2;
988 synth_printf("%d, ", ++i
);
992 static void say_last_char(struct vc_data
*vc
)
994 int len
= get_line(vc
);
998 synth_printf("%s\n", msg_get(MSG_BLANK
));
1002 spk_pos
-= (spk_x
- len
) * 2;
1004 synth_printf("%d, ", ++len
);
1008 static void say_position(struct vc_data
*vc
)
1010 synth_printf(msg_get(MSG_POS_INFO
), spk_y
+ 1, spk_x
+ 1,
1015 /* Added by brianb */
1016 static void say_char_num(struct vc_data
*vc
)
1019 u_short ch
= get_char(vc
, (u_short
*) spk_pos
, &tmp
);
1021 synth_printf(msg_get(MSG_CHAR_INFO
), ch
, ch
);
1024 /* these are stub functions to keep keyboard.c happy. */
1026 static void say_from_top(struct vc_data
*vc
)
1028 say_screen_from_to(vc
, 0, spk_y
);
1031 static void say_to_bottom(struct vc_data
*vc
)
1033 say_screen_from_to(vc
, spk_y
, vc
->vc_rows
);
1036 static void say_from_left(struct vc_data
*vc
)
1038 say_line_from_to(vc
, 0, spk_x
, 1);
1041 static void say_to_right(struct vc_data
*vc
)
1043 say_line_from_to(vc
, spk_x
, vc
->vc_cols
, 1);
1046 /* end of stub functions. */
1048 static void spkup_write(const char *in_buf
, int count
)
1050 static int rep_count
;
1051 static u_char ch
= '\0', old_ch
= '\0';
1052 static u_short char_type
, last_type
;
1053 int in_count
= count
;
1056 if (cursor_track
== read_all_mode
) {
1057 /* Insert Sentence Index */
1058 if ((in_buf
== sentmarks
[bn
][currsentence
]) &&
1059 (currsentence
<= numsentences
[bn
]))
1060 synth_insert_next_index(currsentence
++);
1062 ch
= (u_char
) *in_buf
++;
1063 char_type
= spk_chartab
[ch
];
1064 if (ch
== old_ch
&& !(char_type
& B_NUM
)) {
1065 if (++rep_count
> 2)
1068 if ((last_type
& CH_RPT
) && rep_count
> 2) {
1070 synth_printf(msg_get(MSG_REPEAT_DESC
),
1076 if (ch
== spk_lastkey
) {
1078 if (key_echo
== 1 && ch
>= MINECHOCHAR
)
1080 } else if (char_type
& B_ALPHA
) {
1081 if ((synth_flags
& SF_DEC
) && (last_type
& PUNC
))
1082 synth_buffer_add(SPACE
);
1083 synth_printf("%c", ch
);
1084 } else if (char_type
& B_NUM
) {
1086 synth_printf("%c", ch
);
1087 } else if (char_type
& punc_mask
) {
1089 char_type
&= ~PUNC
; /* for dec nospell processing */
1090 } else if (char_type
& SYNTH_OK
) {
1091 /* these are usually puncts like . and , which synth
1092 * needs for expression.
1093 * suppress multiple to get rid of long pauses and
1094 * clear repeat count
1096 * repeats on you don't get nothing repeated count */
1098 synth_printf("%c", ch
);
1102 /* send space and record position, if next is num overwrite space */
1104 synth_buffer_add(SPACE
);
1109 last_type
= char_type
;
1112 if (in_count
> 2 && rep_count
> 2) {
1113 if (last_type
& CH_RPT
) {
1115 synth_printf(msg_get(MSG_REPEAT_DESC2
), ++rep_count
);
1122 static const int NUM_CTL_LABELS
= (MSG_CTL_END
- MSG_CTL_START
+ 1);
1124 static void read_all_doc(struct vc_data
*vc
);
1125 static void cursor_done(u_long data
);
1126 static DEFINE_TIMER(cursor_timer
, cursor_done
, 0, 0);
1128 static void do_handle_shift(struct vc_data
*vc
, u_char value
, char up_flag
)
1130 unsigned long flags
;
1131 if (synth
== NULL
|| up_flag
|| spk_killed
)
1134 if (cursor_track
== read_all_mode
) {
1137 del_timer(&cursor_timer
);
1138 spk_shut_up
&= 0xfe;
1143 del_timer(&cursor_timer
);
1144 cursor_track
= prev_cursor_track
;
1145 spk_shut_up
&= 0xfe;
1150 spk_shut_up
&= 0xfe;
1153 if (say_ctrl
&& value
< NUM_CTL_LABELS
)
1154 synth_printf("%s", msg_get(MSG_CTL_START
+ value
));
1158 static void do_handle_latin(struct vc_data
*vc
, u_char value
, char up_flag
)
1160 unsigned long flags
;
1163 spk_lastkey
= spk_keydown
= 0;
1167 if (synth
== NULL
|| spk_killed
) {
1171 spk_shut_up
&= 0xfe;
1172 spk_lastkey
= value
;
1175 if (key_echo
== 2 && value
>= MINECHOCHAR
)
1180 int set_key_info(const u_char
*key_info
, u_char
*k_buffer
)
1182 int i
= 0, states
, key_data_len
;
1183 const u_char
*cp
= key_info
;
1184 u_char
*cp1
= k_buffer
;
1185 u_char ch
, version
, num_keys
;
1187 if (version
!= KEY_MAP_VER
)
1190 states
= (int)cp
[1];
1191 key_data_len
= (states
+ 1) * (num_keys
+ 1);
1192 if (key_data_len
+ SHIFT_TBL_SIZE
+ 4 >= sizeof(key_buf
))
1194 memset(k_buffer
, 0, SHIFT_TBL_SIZE
);
1195 memset(our_keys
, 0, sizeof(our_keys
));
1196 shift_table
= k_buffer
;
1197 our_keys
[0] = shift_table
;
1198 cp1
+= SHIFT_TBL_SIZE
;
1199 memcpy(cp1
, cp
, key_data_len
+ 3);
1200 /* get num_keys, states and data */
1201 cp1
+= 2; /* now pointing at shift states */
1202 for (i
= 1; i
<= states
; i
++) {
1204 if (ch
>= SHIFT_TBL_SIZE
)
1206 shift_table
[ch
] = i
;
1208 keymap_flags
= *cp1
++;
1209 while ((ch
= *cp1
)) {
1218 static struct var_t spk_vars
[] = {
1219 /* bell must be first to set high limit */
1220 {BELL_POS
, .u
.n
= {NULL
, 0, 0, 0, 0, 0, NULL
} },
1221 {SPELL_DELAY
, .u
.n
= {NULL
, 0, 0, 4, 0, 0, NULL
} },
1222 {ATTRIB_BLEEP
, .u
.n
= {NULL
, 1, 0, 3, 0, 0, NULL
} },
1223 {BLEEPS
, .u
.n
= {NULL
, 3, 0, 3, 0, 0, NULL
} },
1224 {BLEEP_TIME
, .u
.n
= {NULL
, 30, 1, 200, 0, 0, NULL
} },
1225 {PUNC_LEVEL
, .u
.n
= {NULL
, 1, 0, 4, 0, 0, NULL
} },
1226 {READING_PUNC
, .u
.n
= {NULL
, 1, 0, 4, 0, 0, NULL
} },
1227 {CURSOR_TIME
, .u
.n
= {NULL
, 120, 50, 600, 0, 0, NULL
} },
1228 {SAY_CONTROL
, TOGGLE_0
},
1229 {SAY_WORD_CTL
, TOGGLE_0
},
1230 {NO_INTERRUPT
, TOGGLE_0
},
1231 {KEY_ECHO
, .u
.n
= {NULL
, 1, 0, 2, 0, 0, NULL
} },
1235 static void toggle_cursoring(struct vc_data
*vc
)
1237 if (cursor_track
== read_all_mode
)
1238 cursor_track
= prev_cursor_track
;
1239 if (++cursor_track
>= CT_Max
)
1241 synth_printf("%s\n", msg_get(MSG_CURSOR_MSGS_START
+ cursor_track
));
1244 void reset_default_chars(void)
1248 /* First, free any non-default */
1249 for (i
= 0; i
< 256; i
++) {
1250 if ((characters
[i
] != NULL
)
1251 && (characters
[i
] != default_chars
[i
]))
1252 kfree(characters
[i
]);
1255 memcpy(characters
, default_chars
, sizeof(default_chars
));
1258 void reset_default_chartab(void)
1260 memcpy(spk_chartab
, default_chartab
, sizeof(default_chartab
));
1263 static const struct st_bits_data
*pb_edit
;
1265 static int edit_bits(struct vc_data
*vc
, u_char type
, u_char ch
, u_short key
)
1267 short mask
= pb_edit
->mask
, ch_type
= spk_chartab
[ch
];
1268 if (type
!= KT_LATIN
|| (ch_type
& B_NUM
) || ch
< SPACE
)
1271 synth_printf("%s\n", msg_get(MSG_EDIT_DONE
));
1272 special_handler
= NULL
;
1275 if (mask
< PUNC
&& !(ch_type
& PUNC
))
1277 spk_chartab
[ch
] ^= mask
;
1279 synth_printf(" %s\n",
1280 (spk_chartab
[ch
] & mask
) ? msg_get(MSG_ON
) :
1285 /* Allocation concurrency is protected by the console semaphore */
1286 void speakup_allocate(struct vc_data
*vc
)
1290 vc_num
= vc
->vc_num
;
1291 if (speakup_console
[vc_num
] == NULL
) {
1292 speakup_console
[vc_num
] = kzalloc(sizeof(*speakup_console
[0]),
1294 if (speakup_console
[vc_num
] == NULL
)
1297 } else if (!spk_parked
)
1301 void speakup_deallocate(struct vc_data
*vc
)
1305 vc_num
= vc
->vc_num
;
1306 if (speakup_console
[vc_num
] != NULL
) {
1307 kfree(speakup_console
[vc_num
]);
1308 speakup_console
[vc_num
] = NULL
;
1312 static u_char is_cursor
;
1313 static u_long old_cursor_pos
, old_cursor_x
, old_cursor_y
;
1314 static int cursor_con
;
1316 static void reset_highlight_buffers(struct vc_data
*);
1318 static int read_all_key
;
1320 static void start_read_all_timer(struct vc_data
*vc
, int command
);
1334 static void kbd_fakekey2(struct vc_data
*vc
, int command
)
1336 del_timer(&cursor_timer
);
1337 speakup_fake_down_arrow();
1338 start_read_all_timer(vc
, command
);
1341 static void read_all_doc(struct vc_data
*vc
)
1343 if ((vc
->vc_num
!= fg_console
) || synth
== NULL
|| spk_shut_up
)
1345 if (!synth_supports_indexing())
1347 if (cursor_track
!= read_all_mode
)
1348 prev_cursor_track
= cursor_track
;
1349 cursor_track
= read_all_mode
;
1350 reset_index_count(0);
1351 if (get_sentence_buf(vc
, 0) == -1)
1352 kbd_fakekey2(vc
, RA_DOWN_ARROW
);
1354 say_sentence_num(0, 0);
1355 synth_insert_next_index(0);
1356 start_read_all_timer(vc
, RA_TIMER
);
1360 static void stop_read_all(struct vc_data
*vc
)
1362 del_timer(&cursor_timer
);
1363 cursor_track
= prev_cursor_track
;
1364 spk_shut_up
&= 0xfe;
1368 static void start_read_all_timer(struct vc_data
*vc
, int command
)
1370 struct var_t
*cursor_timeout
;
1372 cursor_con
= vc
->vc_num
;
1373 read_all_key
= command
;
1374 cursor_timeout
= get_var(CURSOR_TIME
);
1375 mod_timer(&cursor_timer
,
1376 jiffies
+ msecs_to_jiffies(cursor_timeout
->u
.n
.value
));
1379 static void handle_cursor_read_all(struct vc_data
*vc
, int command
)
1381 int indcount
, sentcount
, rv
, sn
;
1385 /* Get Current Sentence */
1386 get_index_count(&indcount
, &sentcount
);
1387 /*printk("%d %d ", indcount, sentcount); */
1388 reset_index_count(sentcount
+ 1);
1389 if (indcount
== 1) {
1390 if (!say_sentence_num(sentcount
+ 1, 0)) {
1391 kbd_fakekey2(vc
, RA_FIND_NEXT_SENT
);
1394 synth_insert_next_index(0);
1397 if (!say_sentence_num(sentcount
+ 1, 1)) {
1399 reset_index_count(sn
);
1401 synth_insert_next_index(0);
1402 if (!say_sentence_num(sn
, 0)) {
1403 kbd_fakekey2(vc
, RA_FIND_NEXT_SENT
);
1406 synth_insert_next_index(0);
1408 start_read_all_timer(vc
, RA_TIMER
);
1418 if (get_sentence_buf(vc
, 0) == -1) {
1419 kbd_fakekey2(vc
, RA_DOWN_ARROW
);
1421 say_sentence_num(0, 0);
1422 synth_insert_next_index(0);
1423 start_read_all_timer(vc
, RA_TIMER
);
1426 case RA_FIND_NEXT_SENT
:
1427 rv
= get_sentence_buf(vc
, 0);
1431 kbd_fakekey2(vc
, RA_FIND_NEXT_SENT
);
1433 say_sentence_num(1, 0);
1434 synth_insert_next_index(0);
1435 start_read_all_timer(vc
, RA_TIMER
);
1438 case RA_FIND_PREV_SENT
:
1441 get_index_count(&indcount
, &sentcount
);
1443 kbd_fakekey2(vc
, RA_DOWN_ARROW
);
1445 start_read_all_timer(vc
, RA_TIMER
);
1450 static int pre_handle_cursor(struct vc_data
*vc
, u_char value
, char up_flag
)
1452 unsigned long flags
;
1454 if (cursor_track
== read_all_mode
) {
1456 if (synth
== NULL
|| up_flag
|| spk_shut_up
) {
1460 del_timer(&cursor_timer
);
1461 spk_shut_up
&= 0xfe;
1463 start_read_all_timer(vc
, value
+ 1);
1471 static void do_handle_cursor(struct vc_data
*vc
, u_char value
, char up_flag
)
1473 unsigned long flags
;
1474 struct var_t
*cursor_timeout
;
1478 if (synth
== NULL
|| up_flag
|| spk_shut_up
|| cursor_track
== CT_Off
) {
1482 spk_shut_up
&= 0xfe;
1485 /* the key press flushes if !no_inter but we want to flush on cursor
1486 * moves regardless of no_inter state */
1487 is_cursor
= value
+ 1;
1488 old_cursor_pos
= vc
->vc_pos
;
1489 old_cursor_x
= vc
->vc_x
;
1490 old_cursor_y
= vc
->vc_y
;
1491 speakup_console
[vc
->vc_num
]->ht
.cy
= vc
->vc_y
;
1492 cursor_con
= vc
->vc_num
;
1493 if (cursor_track
== CT_Highlight
)
1494 reset_highlight_buffers(vc
);
1495 cursor_timeout
= get_var(CURSOR_TIME
);
1496 mod_timer(&cursor_timer
,
1497 jiffies
+ msecs_to_jiffies(cursor_timeout
->u
.n
.value
));
1501 static void update_color_buffer(struct vc_data
*vc
, const char *ic
, int len
)
1504 int vc_num
= vc
->vc_num
;
1506 bi
= ((vc
->vc_attr
& 0x70) >> 4);
1507 hi
= speakup_console
[vc_num
]->ht
.highsize
[bi
];
1510 if (speakup_console
[vc_num
]->ht
.highsize
[bi
] == 0) {
1511 speakup_console
[vc_num
]->ht
.rpos
[bi
] = vc
->vc_pos
;
1512 speakup_console
[vc_num
]->ht
.rx
[bi
] = vc
->vc_x
;
1513 speakup_console
[vc_num
]->ht
.ry
[bi
] = vc
->vc_y
;
1515 while ((hi
< COLOR_BUFFER_SIZE
) && (i
< len
)) {
1516 if ((ic
[i
] > 32) && (ic
[i
] < 127)) {
1517 speakup_console
[vc_num
]->ht
.highbuf
[bi
][hi
] = ic
[i
];
1519 } else if ((ic
[i
] == 32) && (hi
!= 0)) {
1520 if (speakup_console
[vc_num
]->ht
.highbuf
[bi
][hi
- 1] !=
1522 speakup_console
[vc_num
]->ht
.highbuf
[bi
][hi
] =
1529 speakup_console
[vc_num
]->ht
.highsize
[bi
] = hi
;
1532 static void reset_highlight_buffers(struct vc_data
*vc
)
1535 int vc_num
= vc
->vc_num
;
1536 for (i
= 0; i
< 8; i
++)
1537 speakup_console
[vc_num
]->ht
.highsize
[i
] = 0;
1540 static int count_highlight_color(struct vc_data
*vc
)
1544 int vc_num
= vc
->vc_num
;
1546 u16
*start
= (u16
*) vc
->vc_origin
;
1548 for (i
= 0; i
< 8; i
++)
1549 speakup_console
[vc_num
]->ht
.bgcount
[i
] = 0;
1551 for (i
= 0; i
< vc
->vc_rows
; i
++) {
1552 u16
*end
= start
+ vc
->vc_cols
* 2;
1554 for (ptr
= start
; ptr
< end
; ptr
++) {
1555 ch
= get_attributes(ptr
);
1556 bg
= (ch
& 0x70) >> 4;
1557 speakup_console
[vc_num
]->ht
.bgcount
[bg
]++;
1559 start
+= vc
->vc_size_row
;
1563 for (i
= 0; i
< 8; i
++)
1564 if (speakup_console
[vc_num
]->ht
.bgcount
[i
] > 0)
1569 static int get_highlight_color(struct vc_data
*vc
)
1572 unsigned int cptr
[8], tmp
;
1573 int vc_num
= vc
->vc_num
;
1575 for (i
= 0; i
< 8; i
++)
1578 for (i
= 0; i
< 7; i
++)
1579 for (j
= i
+ 1; j
< 8; j
++)
1580 if (speakup_console
[vc_num
]->ht
.bgcount
[cptr
[i
]] >
1581 speakup_console
[vc_num
]->ht
.bgcount
[cptr
[j
]]) {
1587 for (i
= 0; i
< 8; i
++)
1588 if (speakup_console
[vc_num
]->ht
.bgcount
[cptr
[i
]] != 0)
1589 if (speakup_console
[vc_num
]->ht
.highsize
[cptr
[i
]] > 0)
1594 static int speak_highlight(struct vc_data
*vc
)
1597 int vc_num
= vc
->vc_num
;
1598 if (count_highlight_color(vc
) == 1)
1600 hc
= get_highlight_color(vc
);
1602 d
= vc
->vc_y
- speakup_console
[vc_num
]->ht
.cy
;
1603 if ((d
== 1) || (d
== -1))
1604 if (speakup_console
[vc_num
]->ht
.ry
[hc
] != vc
->vc_y
)
1608 spkup_write(speakup_console
[vc_num
]->ht
.highbuf
[hc
],
1609 speakup_console
[vc_num
]->ht
.highsize
[hc
]);
1610 spk_pos
= spk_cp
= speakup_console
[vc_num
]->ht
.rpos
[hc
];
1611 spk_x
= spk_cx
= speakup_console
[vc_num
]->ht
.rx
[hc
];
1612 spk_y
= spk_cy
= speakup_console
[vc_num
]->ht
.ry
[hc
];
1618 static void cursor_done(u_long data
)
1620 struct vc_data
*vc
= vc_cons
[cursor_con
].d
;
1621 unsigned long flags
;
1622 del_timer(&cursor_timer
);
1624 if (cursor_con
!= fg_console
) {
1630 if (vc
->vc_x
>= win_left
&& vc
->vc_x
<= win_right
&&
1631 vc
->vc_y
>= win_top
&& vc
->vc_y
<= win_bottom
) {
1632 spk_keydown
= is_cursor
= 0;
1636 if (cursor_track
== read_all_mode
) {
1637 handle_cursor_read_all(vc
, read_all_key
);
1640 if (cursor_track
== CT_Highlight
) {
1641 if (speak_highlight(vc
)) {
1642 spk_keydown
= is_cursor
= 0;
1646 if (cursor_track
== CT_Window
)
1647 speakup_win_say(vc
);
1648 else if (is_cursor
== 1 || is_cursor
== 4)
1649 say_line_from_to(vc
, 0, vc
->vc_cols
, 0);
1652 spk_keydown
= is_cursor
= 0;
1657 /* called by: vt_notifier_call() */
1658 static void speakup_bs(struct vc_data
*vc
)
1660 unsigned long flags
;
1661 if (!speakup_console
[vc
->vc_num
])
1663 if (!spk_trylock(flags
))
1664 /* Speakup output, discard */
1668 if (spk_shut_up
|| synth
== NULL
) {
1672 if (vc
->vc_num
== fg_console
&& spk_keydown
) {
1680 /* called by: vt_notifier_call() */
1681 static void speakup_con_write(struct vc_data
*vc
, const char *str
, int len
)
1683 unsigned long flags
;
1684 if ((vc
->vc_num
!= fg_console
) || spk_shut_up
|| synth
== NULL
)
1686 if (!spk_trylock(flags
))
1687 /* Speakup output, discard */
1689 if (bell_pos
&& spk_keydown
&& (vc
->vc_x
== bell_pos
- 1))
1691 if ((is_cursor
) || (cursor_track
== read_all_mode
)) {
1692 if (cursor_track
== CT_Highlight
)
1693 update_color_buffer(vc
, str
, len
);
1698 if (vc
->vc_x
>= win_left
&& vc
->vc_x
<= win_right
&&
1699 vc
->vc_y
>= win_top
&& vc
->vc_y
<= win_bottom
) {
1705 spkup_write(str
, len
);
1709 void speakup_con_update(struct vc_data
*vc
)
1711 unsigned long flags
;
1712 if (speakup_console
[vc
->vc_num
] == NULL
|| spk_parked
)
1714 if (!spk_trylock(flags
))
1715 /* Speakup output, discard */
1721 static void do_handle_spec(struct vc_data
*vc
, u_char value
, char up_flag
)
1723 unsigned long flags
;
1726 if (synth
== NULL
|| up_flag
|| spk_killed
)
1729 spk_shut_up
&= 0xfe;
1734 label
= msg_get(MSG_KEYNAME_CAPSLOCK
);
1735 on_off
= (vc_kbd_led(kbd_table
+ vc
->vc_num
, VC_CAPSLOCK
));
1738 label
= msg_get(MSG_KEYNAME_NUMLOCK
);
1739 on_off
= (vc_kbd_led(kbd_table
+ vc
->vc_num
, VC_NUMLOCK
));
1742 label
= msg_get(MSG_KEYNAME_SCROLLLOCK
);
1743 on_off
= (vc_kbd_led(kbd_table
+ vc
->vc_num
, VC_SCROLLOCK
));
1744 if (speakup_console
[vc
->vc_num
])
1745 speakup_console
[vc
->vc_num
]->tty_stopped
= on_off
;
1753 synth_printf("%s %s\n",
1754 label
, msg_get(MSG_STATUS_START
+ on_off
));
1758 static int inc_dec_var(u_char value
)
1760 struct st_var_header
*p_header
;
1761 struct var_t
*var_data
;
1765 int var_id
= (int)value
- VAR_START
;
1766 int how
= (var_id
& 1) ? E_INC
: E_DEC
;
1767 var_id
= var_id
/ 2 + FIRST_SET_VAR
;
1768 p_header
= get_var_header(var_id
);
1769 if (p_header
== NULL
)
1771 if (p_header
->var_type
!= VAR_NUM
)
1773 var_data
= p_header
->data
;
1774 if (set_num_var(1, p_header
, how
) != 0)
1776 if (!spk_close_press
) {
1777 for (pn
= p_header
->name
; *pn
; pn
++) {
1784 snprintf(cp
, sizeof(num_buf
) - (cp
- num_buf
), " %d ",
1785 var_data
->u
.n
.value
);
1786 synth_printf("%s", num_buf
);
1790 static void speakup_win_set(struct vc_data
*vc
)
1793 if (win_start
> 1) {
1794 synth_printf("%s\n", msg_get(MSG_WINDOW_ALREADY_SET
));
1797 if (spk_x
< win_left
|| spk_y
< win_top
) {
1798 synth_printf("%s\n", msg_get(MSG_END_BEFORE_START
));
1801 if (win_start
&& spk_x
== win_left
&& spk_y
== win_top
) {
1803 win_right
= vc
->vc_cols
- 1;
1805 snprintf(info
, sizeof(info
), msg_get(MSG_WINDOW_LINE
),
1815 snprintf(info
, sizeof(info
), msg_get(MSG_WINDOW_BOUNDARY
),
1816 (win_start
) ? msg_get(MSG_END
) : msg_get(MSG_START
),
1817 (int)spk_y
+ 1, (int)spk_x
+ 1);
1819 synth_printf("%s\n", info
);
1823 static void speakup_win_clear(struct vc_data
*vc
)
1825 win_top
= win_bottom
= 0;
1826 win_left
= win_right
= 0;
1828 synth_printf("%s\n", msg_get(MSG_WINDOW_CLEARED
));
1831 static void speakup_win_enable(struct vc_data
*vc
)
1833 if (win_start
< 2) {
1834 synth_printf("%s\n", msg_get(MSG_NO_WINDOW
));
1839 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCED
));
1841 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCE_DISABLED
));
1844 static void speakup_bits(struct vc_data
*vc
)
1846 int val
= this_speakup_key
- (FIRST_EDIT_BITS
- 1);
1847 if (special_handler
!= NULL
|| val
< 1 || val
> 6) {
1848 synth_printf("%s\n", msg_get(MSG_ERROR
));
1851 pb_edit
= &punc_info
[val
];
1852 synth_printf(msg_get(MSG_EDIT_PROMPT
), pb_edit
->name
);
1853 special_handler
= edit_bits
;
1856 static int handle_goto(struct vc_data
*vc
, u_char type
, u_char ch
, u_short key
)
1858 static u_char
*goto_buf
= "\0\0\0\0\0\0";
1862 if (type
== KT_SPKUP
&& ch
== SPEAKUP_GOTO
)
1864 if (type
== KT_LATIN
&& ch
== '\n')
1871 ch
= goto_buf
[--num
];
1872 goto_buf
[num
] = '\0';
1873 spkup_write(&ch
, 1);
1876 if (ch
< '+' || ch
> 'y')
1878 goto_buf
[num
++] = ch
;
1879 goto_buf
[num
] = '\0';
1880 spkup_write(&ch
, 1);
1881 maxlen
= (*goto_buf
>= '0') ? 3 : 4;
1882 if ((ch
== '+' || ch
== '-') && num
== 1)
1884 if (ch
>= '0' && ch
<= '9' && num
< maxlen
)
1886 if (num
< maxlen
- 1 || num
> maxlen
)
1888 if (ch
< 'x' || ch
> 'y') {
1891 synth_printf(" %s\n", msg_get(MSG_GOTO_CANCELED
));
1892 goto_buf
[num
= 0] = '\0';
1893 special_handler
= NULL
;
1896 cp
= speakup_s2i(goto_buf
, &go_pos
);
1897 goto_pos
= (u_long
) go_pos
;
1899 if (*goto_buf
< '0')
1905 if (goto_pos
>= vc
->vc_cols
)
1906 goto_pos
= vc
->vc_cols
- 1;
1909 if (*goto_buf
< '0')
1915 if (goto_pos
>= vc
->vc_rows
)
1916 goto_pos
= vc
->vc_rows
- 1;
1919 goto_buf
[num
= 0] = '\0';
1921 special_handler
= NULL
;
1924 spk_pos
-= spk_x
* 2;
1926 spk_pos
+= goto_pos
* 2;
1930 spk_pos
= vc
->vc_origin
+ (goto_pos
* vc
->vc_size_row
);
1936 static void speakup_goto(struct vc_data
*vc
)
1938 if (special_handler
!= NULL
) {
1939 synth_printf("%s\n", msg_get(MSG_ERROR
));
1942 synth_printf("%s\n", msg_get(MSG_GOTO
));
1943 special_handler
= handle_goto
;
1947 static void speakup_help(struct vc_data
*vc
)
1949 handle_help(vc
, KT_SPKUP
, SPEAKUP_HELP
, 0);
1952 static void do_nothing(struct vc_data
*vc
)
1954 return; /* flush done in do_spkup */
1957 static u_char key_speakup
, spk_key_locked
;
1959 static void speakup_lock(struct vc_data
*vc
)
1961 if (!spk_key_locked
)
1962 spk_key_locked
= key_speakup
= 16;
1964 spk_key_locked
= key_speakup
= 0;
1967 typedef void (*spkup_hand
) (struct vc_data
*);
1968 spkup_hand spkup_handler
[] = {
1969 /* must be ordered same as defines in speakup.h */
1970 do_nothing
, speakup_goto
, speech_kill
, speakup_shut_up
,
1971 speakup_cut
, speakup_paste
, say_first_char
, say_last_char
,
1972 say_char
, say_prev_char
, say_next_char
,
1973 say_word
, say_prev_word
, say_next_word
,
1974 say_line
, say_prev_line
, say_next_line
,
1975 top_edge
, bottom_edge
, left_edge
, right_edge
,
1976 spell_word
, spell_word
, say_screen
,
1977 say_position
, say_attributes
,
1978 speakup_off
, speakup_parked
, say_line
, /* this is for indent */
1979 say_from_top
, say_to_bottom
,
1980 say_from_left
, say_to_right
,
1981 say_char_num
, speakup_bits
, speakup_bits
, say_phonetic_char
,
1982 speakup_bits
, speakup_bits
, speakup_bits
,
1983 speakup_win_set
, speakup_win_clear
, speakup_win_enable
, speakup_win_say
,
1984 speakup_lock
, speakup_help
, toggle_cursoring
, read_all_doc
, NULL
1987 static void do_spkup(struct vc_data
*vc
, u_char value
)
1989 if (spk_killed
&& value
!= SPEECH_KILL
)
1993 spk_shut_up
&= 0xfe;
1994 this_speakup_key
= value
;
1995 if (value
< SPKUP_MAX_FUNC
&& spkup_handler
[value
]) {
1997 (*spkup_handler
[value
]) (vc
);
1999 if (inc_dec_var(value
) < 0)
2004 static const char *pad_chars
= "0123456789+-*/\015,.?()";
2007 speakup_key(struct vc_data
*vc
, int shift_state
, int keycode
, u_short keysym
,
2010 unsigned long flags
;
2013 u_char type
= KTYP(keysym
), value
= KVAL(keysym
), new_key
= 0;
2014 u_char shift_info
, offset
;
2024 && (vc_kbd_led(kbd_table
+ fg_console
, VC_NUMLOCK
))) {
2029 value
= spk_lastkey
= pad_chars
[value
];
2034 if (keycode
>= MAX_KEY
)
2036 key_info
= our_keys
[keycode
];
2039 /* Check valid read all mode keys */
2040 if ((cursor_track
== read_all_mode
) && (!up_flag
)) {
2054 shift_info
= (shift_state
& 0x0f) + key_speakup
;
2055 offset
= shift_table
[shift_info
];
2057 new_key
= key_info
[offset
];
2060 if (new_key
== SPK_KEY
) {
2061 if (!spk_key_locked
)
2062 key_speakup
= (up_flag
) ? 0 : 16;
2063 if (up_flag
|| spk_killed
)
2065 spk_shut_up
&= 0xfe;
2071 if (last_keycode
== keycode
&&
2072 last_spk_jiffy
+ MAX_DELAY
> jiffies
) {
2073 spk_close_press
= 1;
2074 offset
= shift_table
[shift_info
+ 32];
2076 if (offset
&& key_info
[offset
])
2077 new_key
= key_info
[offset
];
2079 last_keycode
= keycode
;
2080 last_spk_jiffy
= jiffies
;
2086 if (type
== KT_SPKUP
&& special_handler
== NULL
) {
2087 do_spkup(vc
, new_key
);
2088 spk_close_press
= 0;
2092 if (up_flag
|| spk_killed
|| type
== KT_SHIFT
)
2094 spk_shut_up
&= 0xfe;
2095 kh
= (value
== KVAL(K_DOWN
))
2096 || (value
== KVAL(K_UP
))
2097 || (value
== KVAL(K_LEFT
))
2098 || (value
== KVAL(K_RIGHT
));
2099 if ((cursor_track
!= read_all_mode
) || !kh
)
2102 if (special_handler
) {
2103 if (type
== KT_SPEC
&& value
== 1) {
2106 } else if (type
== KT_LETTER
)
2108 else if (value
== 0x7f)
2109 value
= 8; /* make del = backspace */
2110 ret
= (*special_handler
) (vc
, type
, value
, keycode
);
2111 spk_close_press
= 0;
2122 static int keyboard_notifier_call(struct notifier_block
*nb
,
2123 unsigned long code
, void *_param
)
2125 struct keyboard_notifier_param
*param
= _param
;
2126 struct vc_data
*vc
= param
->vc
;
2127 int up
= !param
->down
;
2128 int ret
= NOTIFY_OK
;
2129 static int keycode
; /* to hold the current keycode */
2131 if (vc
->vc_mode
== KD_GRAPHICS
)
2135 * First, determine whether we are handling a fake keypress on
2136 * the current processor. If we are, then return NOTIFY_OK,
2137 * to pass the keystroke up the chain. This prevents us from
2138 * trying to take the Speakup lock while it is held by the
2139 * processor on which the simulated keystroke was generated.
2140 * Also, the simulated keystrokes should be ignored by Speakup.
2143 if (speakup_fake_key_pressed())
2148 /* speakup requires keycode and keysym currently */
2149 keycode
= param
->value
;
2151 case KBD_UNBOUND_KEYCODE
:
2158 if (speakup_key(vc
, param
->shift
, keycode
, param
->value
, up
))
2160 else if (KTYP(param
->value
) == KT_CUR
)
2161 ret
= pre_handle_cursor(vc
, KVAL(param
->value
), up
);
2163 case KBD_POST_KEYSYM
:{
2164 unsigned char type
= KTYP(param
->value
) - 0xf0;
2165 unsigned char val
= KVAL(param
->value
);
2168 do_handle_shift(vc
, val
, up
);
2172 do_handle_latin(vc
, val
, up
);
2175 do_handle_cursor(vc
, val
, up
);
2178 do_handle_spec(vc
, val
, up
);
2187 static int vt_notifier_call(struct notifier_block
*nb
,
2188 unsigned long code
, void *_param
)
2190 struct vt_notifier_param
*param
= _param
;
2191 struct vc_data
*vc
= param
->vc
;
2194 if (vc
->vc_mode
== KD_TEXT
)
2195 speakup_allocate(vc
);
2198 speakup_deallocate(vc
);
2201 if (param
->c
== '\b')
2203 else if (param
->c
< 0x100) {
2205 speakup_con_write(vc
, &d
, 1);
2209 speakup_con_update(vc
);
2215 /* called by: module_exit() */
2216 static void __exit
speakup_exit(void)
2221 unregister_keyboard_notifier(&keyboard_notifier_block
);
2222 unregister_vt_notifier(&vt_notifier_block
);
2223 speakup_unregister_devsynth();
2224 del_timer(&cursor_timer
);
2226 kthread_stop(speakup_task
);
2227 speakup_task
= NULL
;
2228 mutex_lock(&spk_mutex
);
2230 mutex_unlock(&spk_mutex
);
2232 for (i
= 0; i
< MAXVARS
; i
++)
2233 speakup_unregister_var(i
);
2235 for (i
= 0; i
< 256; i
++) {
2236 if (characters
[i
] != default_chars
[i
])
2237 kfree(characters
[i
]);
2239 for (i
= 0; speakup_console
[i
]; i
++)
2240 kfree(speakup_console
[i
]);
2241 speakup_kobj_exit();
2242 speakup_remove_virtual_keyboard();
2245 /* call by: module_init() */
2246 static int __init
speakup_init(void)
2250 struct st_spk_t
*first_console
;
2251 struct vc_data
*vc
= vc_cons
[fg_console
].d
;
2254 err
= speakup_add_virtual_keyboard();
2258 initialize_msgs(); /* Initialize arrays for i18n. */
2259 first_console
= kzalloc(sizeof(*first_console
), GFP_KERNEL
);
2262 err
= speakup_kobj_init();
2264 kfree(first_console
);
2268 reset_default_chars();
2269 reset_default_chartab();
2271 speakup_console
[vc
->vc_num
] = first_console
;
2273 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION
);
2276 spk_vars
[0].u
.n
.high
= vc
->vc_cols
;
2277 for (var
= spk_vars
; var
->var_id
!= MAXVARS
; var
++)
2278 speakup_register_var(var
);
2279 for (var
= synth_time_vars
;
2280 (var
->var_id
>= 0) && (var
->var_id
< MAXVARS
); var
++)
2281 speakup_register_var(var
);
2282 for (i
= 1; punc_info
[i
].mask
!= 0; i
++)
2283 set_mask_bits(0, i
, 2);
2285 set_key_info(key_defaults
, key_buf
);
2287 spk_shut_up
|= 0x01;
2289 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
2291 speakup_allocate(vc_cons
[i
].d
);
2293 pr_warn("synth name on entry is: %s\n", synth_name
);
2294 synth_init(synth_name
);
2295 speakup_register_devsynth();
2297 register_keyboard_notifier(&keyboard_notifier_block
);
2298 register_vt_notifier(&vt_notifier_block
);
2300 speakup_task
= kthread_create(speakup_thread
, NULL
, "speakup");
2301 set_user_nice(speakup_task
, 10);
2302 if (!IS_ERR(speakup_task
))
2303 wake_up_process(speakup_task
);
2309 module_init(speakup_init
);
2310 module_exit(speakup_exit
);