Line 0
Link Here
|
|
|
1 |
/* speakup.c |
2 |
review functions for the speakup screen review package. |
3 |
originally written by: Kirk Reiser and Andy Berdan. |
4 |
|
5 |
extensively modified by David Borowski. |
6 |
|
7 |
Copyright (C ) 1998 Kirk Reiser. |
8 |
Copyright (C ) 2003 David Borowski. |
9 |
|
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. |
14 |
|
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. |
19 |
|
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 |
23 |
*/ |
24 |
|
25 |
#include <linux/kernel.h> |
26 |
#include <linux/version.h> |
27 |
#include <linux/vt.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 <asm/uaccess.h> /* copy_from|to|user( ) and others */ |
34 |
#include <linux/unistd.h> |
35 |
|
36 |
#include <linux/keyboard.h> /* for KT_SHIFT */ |
37 |
#include <linux/kbd_kern.h> /* for vc_kbd_* and friends */ |
38 |
#include <linux/vt_kern.h> |
39 |
#include <linux/input.h> |
40 |
#include <linux/kmod.h> |
41 |
#include <linux/speakup.h> |
42 |
|
43 |
#include "cvsversion.h" |
44 |
#include "spk_priv.h" |
45 |
#include <linux/bootmem.h> /* for alloc_bootmem */ |
46 |
|
47 |
/* speakup_*_selection */ |
48 |
#include <linux/module.h> |
49 |
#include <linux/sched.h> |
50 |
#include <linux/slab.h> |
51 |
#include <linux/types.h> |
52 |
#include <asm/uaccess.h> |
53 |
#include <linux/consolemap.h> |
54 |
|
55 |
#define SPEAKUP_VERSION "Speakup v-2.00" CVSVERSION |
56 |
#define MAX_DELAY ( (500 * HZ ) / 1000 ) |
57 |
#define KEY_MAP_VER 119 |
58 |
#define MINECHOCHAR SPACE |
59 |
|
60 |
/* these are globals from the kernel code */ |
61 |
extern struct kbd_struct * kbd; |
62 |
extern int fg_console; |
63 |
extern short punc_masks[]; |
64 |
|
65 |
static special_func special_handler = NULL; |
66 |
special_func help_handler = NULL; |
67 |
|
68 |
short pitch_shift = 0, synth_flags = 0; |
69 |
static char buf[256]; |
70 |
short attrib_bleep = 0, bleeps = 0, bleep_time = 1; |
71 |
short no_intr = 0, spell_delay = 0; |
72 |
short key_echo = 0, cursor_timeout = 120, say_word_ctl = 0; |
73 |
short say_ctrl = 0, bell_pos = 0; |
74 |
short punc_mask = 0, punc_level = 0, reading_punc = 0; |
75 |
char str_caps_start[MAXVARLEN+1] = "\0", str_caps_stop[MAXVARLEN+1] = "\0"; |
76 |
static const struct st_bits_data punc_info[] = { |
77 |
{ "none", "", 0 }, |
78 |
{ "some", "/$%&@", SOME }, |
79 |
{ "most", "$%&#()=+*/@^<>|\\", MOST }, |
80 |
{ "all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC }, |
81 |
{ "delimiters", "", B_WDLM }, |
82 |
{ "repeats", "()", CH_RPT }, |
83 |
{ "extended numeric", "", B_EXNUM }, |
84 |
{ "symbols", "", B_SYM }, |
85 |
{ 0, 0 } |
86 |
}; |
87 |
static char mark_cut_flag = 0; |
88 |
char synth_name[10] = CONFIG_SPEAKUP_DEFAULT; |
89 |
#define MAX_KEY 160 |
90 |
u_char *our_keys[MAX_KEY], *shift_table; |
91 |
static u_char key_buf[600]; |
92 |
static const u_char key_defaults[] = { |
93 |
#include "speakupmap.h" |
94 |
}; |
95 |
|
96 |
/* Speakup Cursor Track Variables */ |
97 |
static int cursor_track = 1, prev_cursor_track = 1; |
98 |
|
99 |
/* cursor track modes, must be ordered same as cursor_msgs */ |
100 |
enum { |
101 |
CT_Off = 0, |
102 |
CT_On, |
103 |
CT_Highlight, |
104 |
CT_Window, |
105 |
CT_Max |
106 |
}; |
107 |
#define read_all_mode CT_Max |
108 |
|
109 |
struct tty_struct *tty; |
110 |
#define key_handler k_handler |
111 |
typedef void (*k_handler_fn)(struct vc_data *vc, unsigned char value, |
112 |
char up_flag); |
113 |
extern k_handler_fn key_handler[16]; |
114 |
static k_handler_fn do_shift, do_spec, do_latin, do_cursor; |
115 |
EXPORT_SYMBOL_GPL(help_handler); |
116 |
EXPORT_SYMBOL_GPL(special_handler); |
117 |
EXPORT_SYMBOL_GPL(our_keys); |
118 |
EXPORT_SYMBOL_GPL(synth_name); |
119 |
|
120 |
static void spkup_write(const char *in_buf, int count); |
121 |
static int set_mask_bits(const char *input, const int which, const int how); |
122 |
|
123 |
static const char str_ctl[] = "control-"; |
124 |
static const char *colors[] = { |
125 |
"black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", |
126 |
"grey" |
127 |
}; |
128 |
|
129 |
static char *phonetic[] = { |
130 |
"alpha", "beta", "charley", "delta", "echo", "fox", "gamma", "hotel", |
131 |
"india", "juleiet", "keelo", "leema", "mike", "november", "oscar", |
132 |
"papa", |
133 |
"quebec", "romeo", "seeara", "tango", "uniform", "victer", "wiskey", |
134 |
"x ray", "yankee", "zooloo" |
135 |
}; |
136 |
|
137 |
// array of 256 char pointers (one for each character description ) |
138 |
// initialized to default_chars and user selectable via /proc/speakup/characters |
139 |
static char *characters[256]; |
140 |
|
141 |
static char *default_chars[256] = { |
142 |
"null", "^a", "^b", "^c", "^d", "^e", "^f", "^g", |
143 |
"^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o", |
144 |
"^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w", |
145 |
"^x", "^y", "^z", NULL, NULL, NULL, NULL, NULL, |
146 |
"space", "bang!", "quote", "number", "dollar", "percent", "and", |
147 |
"tick", |
148 |
"left paren", "right paren", "star", "plus", "comma", "dash", "dot", |
149 |
"slash", |
150 |
"zero", "one", "two", "three", "four", "five", "six", "seven", |
151 |
"eight", "nine", |
152 |
"colon", "semmy", "less", "equals", "greater", "question", "at", |
153 |
"eigh", "b", "c", "d", "e", "f", "g", |
154 |
"h", "i", "j", "k", "l", "m", "n", "o", |
155 |
"p", "q", "r", "s", "t", "u", "v", "w", "x", |
156 |
"y", "zehd", "left bracket", "backslash", "right bracket", "caret", |
157 |
"line", |
158 |
"accent", NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
159 |
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
160 |
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
161 |
NULL, NULL, NULL, "left brace", "bar", "right brace", "tihlduh", |
162 |
"delta", "see cedilla", "u oomlout", "e acute", /* 128 */ |
163 |
"eigh circumflex", "eigh oomlout", "eigh grave", "eigh ring", /* 132 */ |
164 |
"see cedilla", "e circumflex", "e oomlout", "e grave", /* 136 */ |
165 |
"i oomlout", "i circumflex", "i grave", "eigh oomlout", /* 140 */ |
166 |
"eigh ring", "e acute", "eigh e dipthong", "eigh e dipthong", /* 144 */ |
167 |
"o circumflex", "o oomlout", "o grave", "u circumflex", /* 148 */ |
168 |
"u grave", "y oomlout", "o oomlout", "u oomlout", /* 152 */ |
169 |
"cents", "pounds", "yen", "peseta", /* 156 */ |
170 |
"florin", "eigh acute", "i acute", "o acute", /* 160 */ |
171 |
"u acute", "n tilde", "n tilde", "feminine ordinal", /* 164 */ |
172 |
"masculin ordinal", "inverted question", "reversed not", "not", /* 168 */ |
173 |
"half", "quarter", "inverted bang", "much less than", /* 172 */ |
174 |
"much greater than", "dark shading", "medium shading", /* 176 */ |
175 |
"light shading", "verticle line", "left tee", /* 179 */ |
176 |
"double left tee", "left double tee", "double top right", /* 182 */ |
177 |
"top double right", "double left double tee", /* 185 */ |
178 |
"double vertical line", "double top double right", /* 187 */ |
179 |
"double bottom double right", "double bottom right", /* 189 */ |
180 |
"bottom double right", "top right", "left bottom", /* 191 */ |
181 |
"up tee", "tee down", "tee right", "horizontal line", /* 194 */ |
182 |
"cross bars", "tee double right", "double tee right", /* 198 */ |
183 |
"double left double bottom", "double left double top", /* 201 */ |
184 |
"double up double tee", "double tee double down", /* 203 */ |
185 |
"double tee double right", "double horizontal line", /* 205 */ |
186 |
"double cross bars", "up double tee", "double up tee", /* 207 */ |
187 |
"double tee down", "tee double down", /* 210 */ |
188 |
"double left bottom", "left double bottom", /* 212 */ |
189 |
"double left top", "left double top", /* 214 */ |
190 |
"double vertical cross", "double horizontal cross", /* 216 */ |
191 |
"bottom right", "left top", "solid square", /* 218 */ |
192 |
"solid lower half", "solid left half", "solid right half", /* 221 */ |
193 |
"solid upper half", "alpha", "beta", "gamma", /* 224 */ |
194 |
"pie", "sigma", "sigma", "mu", /* 228 */ |
195 |
"tou", "phigh", "thayta", "ohmega", /* 232 */ |
196 |
"delta", "infinity", "phigh", "epsilaun", /* 236 */ |
197 |
"intersection", "identical to", "plus or minus", "equal grater than", /* 240 */ |
198 |
"less than equal", "upper integral", "lower integral", /* 244 */ |
199 |
"divided by", "almost equal", "degrees", /* 247 */ |
200 |
"centre dot", "bullet", "square root", /* 250 */ |
201 |
"power", "squared", "black square", "white space" /* 252 */ |
202 |
}; |
203 |
|
204 |
// array of 256 u_short (one for each character) |
205 |
// initialized to default_chartab and user selectable via /proc/speakup/chartab |
206 |
static u_short spk_chartab[256]; |
207 |
|
208 |
static u_short default_chartab[256] = { |
209 |
B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */ |
210 |
B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */ |
211 |
B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */ |
212 |
B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */ |
213 |
WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */ |
214 |
PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ( )*+, -./ */ |
215 |
NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */ |
216 |
NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */ |
217 |
PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */ |
218 |
A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */ |
219 |
A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */ |
220 |
A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */ |
221 |
PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */ |
222 |
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */ |
223 |
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */ |
224 |
ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */ |
225 |
B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-135 */ |
226 |
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 136-143 */ |
227 |
B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 144-151 */ |
228 |
B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 152-159 */ |
229 |
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, B_SYM, /* 160-167 */ |
230 |
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */ |
231 |
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */ |
232 |
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */ |
233 |
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 192-199 */ |
234 |
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 200-207 */ |
235 |
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 208-215 */ |
236 |
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 216-223 */ |
237 |
B_SYM, B_SYM, B_SYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, /* 224-231 */ |
238 |
B_SYM, B_CAPSYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 232-239 */ |
239 |
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 240-247 */ |
240 |
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM /* 248-255 */ |
241 |
}; |
242 |
|
243 |
static int spk_keydown = 0; |
244 |
static u_char spk_lastkey = 0, spk_close_press = 0, keymap_flags = 0; |
245 |
static u_char last_keycode = 0, this_speakup_key = 0; |
246 |
static u_long last_spk_jiffy = 0; |
247 |
|
248 |
struct st_spk_t *speakup_console[MAX_NR_CONSOLES]; |
249 |
|
250 |
static int spk_setup(char *str) |
251 |
{ |
252 |
int ints[4]; |
253 |
str = get_options(str, ARRAY_SIZE (ints), ints); |
254 |
if (ints[0] > 0 && ints[1] >= 0) |
255 |
synth_port_forced = ints[1]; |
256 |
return 1; |
257 |
} |
258 |
|
259 |
static int spk_ser_setup(char *str) |
260 |
{ |
261 |
const int lookup[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; |
262 |
int ints[4]; |
263 |
str = get_options(str, ARRAY_SIZE (ints), ints); |
264 |
if (ints[0] > 0 && ints[1] >= 0) |
265 |
synth_port_forced = lookup[ints[1]]; |
266 |
return 1; |
267 |
} |
268 |
|
269 |
static int spk_synth_setup(char *str) |
270 |
{ |
271 |
size_t len = min_t(size_t, strlen(str), 9); |
272 |
memcpy (synth_name, str, len); |
273 |
synth_name[len] = '\0'; |
274 |
return 1; |
275 |
} |
276 |
|
277 |
static int spk_quiet_setup(char *str) |
278 |
{ |
279 |
if (strchr("1yt", *str) != NULL) |
280 |
quiet_boot = 1; |
281 |
return 1; |
282 |
} |
283 |
|
284 |
__setup("speakup_port=", spk_setup); |
285 |
__setup("speakup_ser=", spk_ser_setup); |
286 |
__setup("speakup_synth=", spk_synth_setup); |
287 |
__setup("speakup_quiet=", spk_quiet_setup); |
288 |
|
289 |
static unsigned char get_attributes(u16 *pos) |
290 |
{ |
291 |
return (u_char)(scr_readw(pos) >> 8); |
292 |
} |
293 |
|
294 |
static void speakup_date(struct vc_data *vc) |
295 |
{ |
296 |
spk_x = spk_cx = vc->vc_x; |
297 |
spk_y = spk_cy = vc->vc_y; |
298 |
spk_pos = spk_cp = vc->vc_pos; |
299 |
spk_old_attr = spk_attr; |
300 |
spk_attr = get_attributes((u_short *) spk_pos); |
301 |
} |
302 |
|
303 |
char *strlwr(char *s) |
304 |
{ |
305 |
char *p; |
306 |
for (p = s; *p; p++) |
307 |
if (*p >= CAP_A && *p <= CAP_Z) |
308 |
*p |= 32; |
309 |
return s; |
310 |
} |
311 |
|
312 |
static void bleep(u_short val) |
313 |
{ |
314 |
static const short vals[] = { |
315 |
350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659 |
316 |
}; |
317 |
short freq; |
318 |
int time = bleep_time; |
319 |
freq = vals[val%12]; |
320 |
if (val > 11) |
321 |
freq *= (1 << (val/12)); |
322 |
kd_mksound(freq, time); |
323 |
} |
324 |
|
325 |
static void speakup_shut_up(struct vc_data *vc) |
326 |
{ |
327 |
if (spk_killed) |
328 |
return; |
329 |
spk_shut_up |= 0x01; |
330 |
spk_parked &= 0xfe; |
331 |
speakup_date(vc); |
332 |
if (synth != NULL) |
333 |
do_flush(); |
334 |
} |
335 |
|
336 |
static void speech_kill(struct vc_data *vc) |
337 |
{ |
338 |
char val = synth->is_alive(); |
339 |
if (val == 0) |
340 |
return; |
341 |
|
342 |
/* re-enables synth, if disabled */ |
343 |
if (val == 2 || spk_killed) { /* dead */ |
344 |
spk_shut_up &= ~0x40; |
345 |
synth_write_msg("Eyem a Lighve!"); |
346 |
} else { |
347 |
synth_write_msg("You killed speak up!"); |
348 |
spk_shut_up |= 0x40; |
349 |
} |
350 |
} |
351 |
|
352 |
static void speakup_off(struct vc_data *vc) |
353 |
{ |
354 |
if (spk_shut_up & 0x80) { |
355 |
spk_shut_up &= 0x7f; |
356 |
synth_write_msg("hey. That's better!" ); |
357 |
} else { |
358 |
spk_shut_up |= 0x80; |
359 |
synth_write_msg("You turned me off!" ); |
360 |
} |
361 |
speakup_date(vc); |
362 |
} |
363 |
|
364 |
static void speakup_parked(struct vc_data *vc) |
365 |
{ |
366 |
if (spk_parked & 0x80) { |
367 |
spk_parked = 0; |
368 |
synth_write_msg ("unparked!"); |
369 |
} else { |
370 |
spk_parked |= 0x80; |
371 |
synth_write_msg ("parked!"); |
372 |
} |
373 |
} |
374 |
|
375 |
/* ------ cut and paste ----- */ |
376 |
/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ |
377 |
#undef isspace |
378 |
#define isspace(c) ((c) == ' ') |
379 |
/* Variables for selection control. */ |
380 |
static struct vc_data *spk_sel_cons; /* defined in selection.c must not be disallocated */ |
381 |
static volatile int sel_start = -1; /* cleared by clear_selection */ |
382 |
static int sel_end; |
383 |
static int sel_buffer_lth; |
384 |
static char *sel_buffer; |
385 |
|
386 |
static unsigned char sel_pos(int n) |
387 |
{ |
388 |
return inverse_translate(spk_sel_cons, screen_glyph(spk_sel_cons, n)); |
389 |
} |
390 |
|
391 |
static u16 get_char(struct vc_data *vc, u16 *pos) |
392 |
{ |
393 |
u16 ch = ' '; |
394 |
if (vc && pos) { |
395 |
u16 w = scr_readw(pos); |
396 |
u16 c = w & 0xff; |
397 |
|
398 |
if (w & vc->vc_hi_font_mask) |
399 |
c |= 0x100; |
400 |
|
401 |
ch = w & 0xff00; |
402 |
ch |= inverse_translate(vc, c); |
403 |
} |
404 |
return ch; |
405 |
} |
406 |
|
407 |
static void speakup_clear_selection(void) |
408 |
{ |
409 |
sel_start = -1; |
410 |
} |
411 |
|
412 |
/* does screen address p correspond to character at LH/RH edge of screen? */ |
413 |
static int atedge(const int p, int size_row) |
414 |
{ |
415 |
return (!(p % size_row) || !((p + 2) % size_row)); |
416 |
} |
417 |
|
418 |
/* constrain v such that v <= u */ |
419 |
static unsigned short limit(const unsigned short v, const unsigned short u) |
420 |
{ |
421 |
return (v > u) ? u : v; |
422 |
} |
423 |
|
424 |
static unsigned short xs, ys, xe, ye; /* our region points */ |
425 |
|
426 |
static int speakup_set_selection(struct tty_struct *tty) |
427 |
{ |
428 |
int new_sel_start, new_sel_end; |
429 |
char *bp, *obp; |
430 |
int i, ps, pe; |
431 |
struct vc_data *vc = vc_cons[fg_console].d; |
432 |
|
433 |
xs = limit(xs, vc->vc_cols - 1); |
434 |
ys = limit(ys, vc->vc_rows - 1); |
435 |
xe = limit(xe, vc->vc_cols - 1); |
436 |
ye = limit(ye, vc->vc_rows - 1); |
437 |
ps = ys * vc->vc_size_row + (xs << 1); |
438 |
pe = ye * vc->vc_size_row + (xe << 1); |
439 |
|
440 |
if (ps > pe) { /* make sel_start <= sel_end */ |
441 |
int tmp = ps; |
442 |
ps = pe; |
443 |
pe = tmp; |
444 |
} |
445 |
|
446 |
if (spk_sel_cons != vc_cons[fg_console].d) { |
447 |
speakup_clear_selection(); |
448 |
spk_sel_cons = vc_cons[fg_console].d; |
449 |
printk(KERN_WARNING "Selection: mark console not the same as cut\n"); |
450 |
return -EINVAL; |
451 |
} |
452 |
|
453 |
new_sel_start = ps; |
454 |
new_sel_end = pe; |
455 |
|
456 |
/* select to end of line if on trailing space */ |
457 |
if (new_sel_end > new_sel_start && |
458 |
!atedge(new_sel_end, vc->vc_size_row) && |
459 |
isspace(sel_pos(new_sel_end))) { |
460 |
for (pe = new_sel_end + 2; ; pe += 2) |
461 |
if (!isspace(sel_pos(pe)) || |
462 |
atedge(pe, vc->vc_size_row)) |
463 |
break; |
464 |
if (isspace(sel_pos(pe))) |
465 |
new_sel_end = pe; |
466 |
} |
467 |
if ((new_sel_start == sel_start) && (new_sel_end == sel_end)) |
468 |
return 0; /* no action required */ |
469 |
|
470 |
sel_start = new_sel_start; |
471 |
sel_end = new_sel_end; |
472 |
/* Allocate a new buffer before freeing the old one ... */ |
473 |
bp = kmalloc((sel_end-sel_start)/2+1, GFP_ATOMIC); |
474 |
if (!bp) { |
475 |
printk(KERN_WARNING "selection: kmalloc() failed\n"); |
476 |
speakup_clear_selection(); |
477 |
return -ENOMEM; |
478 |
} |
479 |
if (sel_buffer) |
480 |
kfree(sel_buffer); |
481 |
sel_buffer = bp; |
482 |
|
483 |
obp = bp; |
484 |
for (i = sel_start; i <= sel_end; i += 2) { |
485 |
*bp = sel_pos(i); |
486 |
if (!isspace(*bp++)) |
487 |
obp = bp; |
488 |
if (! ((i + 2) % vc->vc_size_row)) { |
489 |
/* strip trailing blanks from line and add newline, |
490 |
unless non-space at end of line. */ |
491 |
if (obp != bp) { |
492 |
bp = obp; |
493 |
*bp++ = '\r'; |
494 |
} |
495 |
obp = bp; |
496 |
} |
497 |
} |
498 |
sel_buffer_lth = bp - sel_buffer; |
499 |
return 0; |
500 |
} |
501 |
|
502 |
static int speakup_paste_selection(struct tty_struct *tty) |
503 |
{ |
504 |
struct vc_data *vc = (struct vc_data *) tty->driver_data; |
505 |
int pasted = 0, count; |
506 |
DECLARE_WAITQUEUE(wait, current); |
507 |
add_wait_queue(&vc->paste_wait, &wait); |
508 |
while (sel_buffer && sel_buffer_lth > pasted) { |
509 |
set_current_state(TASK_INTERRUPTIBLE); |
510 |
if (test_bit(TTY_THROTTLED, &tty->flags)) { |
511 |
schedule(); |
512 |
continue; |
513 |
} |
514 |
count = sel_buffer_lth - pasted; |
515 |
count = min_t(int, count, tty->receive_room); |
516 |
tty->ldisc.receive_buf(tty, sel_buffer + pasted, 0, count); |
517 |
pasted += count; |
518 |
} |
519 |
remove_wait_queue(&vc->paste_wait, &wait); |
520 |
current->state = TASK_RUNNING; |
521 |
return 0; |
522 |
} |
523 |
|
524 |
static void speakup_cut(struct vc_data *vc) |
525 |
{ |
526 |
static const char err_buf[] = "set selection failed"; |
527 |
int ret; |
528 |
|
529 |
if (!mark_cut_flag) { |
530 |
mark_cut_flag = 1; |
531 |
xs = spk_x; |
532 |
ys = spk_y; |
533 |
spk_sel_cons = vc; |
534 |
synth_write_msg("mark"); |
535 |
return; |
536 |
} |
537 |
xe = (u_short) spk_x; |
538 |
ye = (u_short) spk_y; |
539 |
mark_cut_flag = 0; |
540 |
synth_write_msg ("cut"); |
541 |
|
542 |
speakup_clear_selection(); |
543 |
ret = speakup_set_selection(tty); |
544 |
|
545 |
switch (ret) { |
546 |
case 0: |
547 |
break; /* no error */ |
548 |
case -EFAULT : |
549 |
pr_warn( "%sEFAULT\n", err_buf ); |
550 |
break; |
551 |
case -EINVAL : |
552 |
pr_warn( "%sEINVAL\n", err_buf ); |
553 |
break; |
554 |
case -ENOMEM : |
555 |
pr_warn( "%sENOMEM\n", err_buf ); |
556 |
break; |
557 |
} |
558 |
} |
559 |
|
560 |
static void speakup_paste(struct vc_data *vc) |
561 |
{ |
562 |
if (mark_cut_flag) { |
563 |
mark_cut_flag = 0; |
564 |
synth_write_msg("mark, cleared"); |
565 |
} else { |
566 |
synth_write_msg ("paste"); |
567 |
speakup_paste_selection(tty); |
568 |
} |
569 |
} |
570 |
|
571 |
static void say_attributes(struct vc_data *vc ) |
572 |
{ |
573 |
int fg = spk_attr & 0x0f; |
574 |
int bg = spk_attr>>4; |
575 |
if (fg > 8) { |
576 |
synth_write_string("bright "); |
577 |
fg -= 8; |
578 |
} |
579 |
synth_write_string(colors[fg]); |
580 |
if (bg > 7) { |
581 |
synth_write_string(" on blinking "); |
582 |
bg -= 8; |
583 |
} else |
584 |
synth_write_string(" on "); |
585 |
synth_write_msg(colors[bg]); |
586 |
} |
587 |
|
588 |
static char *blank_msg = "blank"; |
589 |
static char *edges[] = { "top, ", "bottom, ", "left, ", "right, ", "" }; |
590 |
enum { |
591 |
edge_top = 1, |
592 |
edge_bottom, |
593 |
edge_left, |
594 |
edge_right, |
595 |
edge_quiet |
596 |
}; |
597 |
|
598 |
static void announce_edge(struct vc_data *vc, int msg_id) |
599 |
{ |
600 |
if (bleeps & 1) |
601 |
bleep(spk_y); |
602 |
if (bleeps & 2) |
603 |
synth_write_msg(edges[msg_id-1]); |
604 |
} |
605 |
|
606 |
static void speak_char( u_char ch) |
607 |
{ |
608 |
char *cp = characters[ch]; |
609 |
if (cp == NULL) { |
610 |
pr_info ("speak_char: cp==NULL!\n"); |
611 |
return; |
612 |
} |
613 |
synth_buffer_add(SPACE); |
614 |
if (IS_CHAR(ch, B_CAP)) { |
615 |
pitch_shift++; |
616 |
synth_write_string(str_caps_start); |
617 |
synth_write_string(cp); |
618 |
synth_write_string(str_caps_stop); |
619 |
} else { |
620 |
if (*cp == '^') { |
621 |
synth_write_string(str_ctl); |
622 |
cp++; |
623 |
} |
624 |
synth_write_string(cp); |
625 |
} |
626 |
synth_buffer_add(SPACE); |
627 |
} |
628 |
|
629 |
static void say_char(struct vc_data *vc) |
630 |
{ |
631 |
u_short ch; |
632 |
spk_old_attr = spk_attr; |
633 |
ch = get_char(vc, (u_short *) spk_pos); |
634 |
spk_attr = (ch >> 8); |
635 |
if (spk_attr != spk_old_attr) { |
636 |
if (attrib_bleep & 1) |
637 |
bleep(spk_y); |
638 |
if (attrib_bleep & 2) |
639 |
say_attributes(vc); |
640 |
} |
641 |
speak_char(ch & 0xff); |
642 |
} |
643 |
|
644 |
static void say_phonetic_char(struct vc_data *vc) |
645 |
{ |
646 |
u_short ch; |
647 |
spk_old_attr = spk_attr; |
648 |
ch = get_char(vc, (u_short *) spk_pos); |
649 |
spk_attr = ((ch & 0xff00) >> 8); |
650 |
if (IS_CHAR(ch, B_ALPHA)) { |
651 |
ch &= 0x1f; |
652 |
synth_write_msg(phonetic[--ch] ); |
653 |
} else { |
654 |
if (IS_CHAR(ch, B_NUM)) |
655 |
synth_write_string("number "); |
656 |
speak_char(ch); |
657 |
} |
658 |
} |
659 |
|
660 |
static void say_prev_char(struct vc_data *vc) |
661 |
{ |
662 |
spk_parked |= 0x01; |
663 |
if (spk_x == 0) { |
664 |
announce_edge(vc, edge_left); |
665 |
return; |
666 |
} |
667 |
spk_x--; |
668 |
spk_pos -= 2; |
669 |
say_char(vc); |
670 |
} |
671 |
|
672 |
static void say_next_char(struct vc_data *vc) |
673 |
{ |
674 |
spk_parked |= 0x01; |
675 |
if (spk_x == vc->vc_cols - 1) { |
676 |
announce_edge(vc, edge_right); |
677 |
return; |
678 |
} |
679 |
spk_x++; |
680 |
spk_pos += 2; |
681 |
say_char(vc); |
682 |
} |
683 |
|
684 |
/* get_word - will first check to see if the character under the |
685 |
reading cursor is a space and if say_word_ctl is true it will |
686 |
return the word space. If say_word_ctl is not set it will check to |
687 |
see if there is a word starting on the next position to the right |
688 |
and return that word if it exists. If it does not exist it will |
689 |
move left to the beginning of any previous word on the line or the |
690 |
beginning off the line whichever comes first.. */ |
691 |
|
692 |
static u_long get_word(struct vc_data *vc) |
693 |
{ |
694 |
u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos; |
695 |
char ch; |
696 |
u_short attr_ch; |
697 |
spk_old_attr = spk_attr; |
698 |
ch = (char) get_char(vc, (u_short *) tmp_pos); |
699 |
|
700 |
/* decided to take out the sayword if on a space (mis-information */ |
701 |
if (say_word_ctl && ch == SPACE) { |
702 |
*buf = '\0'; |
703 |
synth_write_msg("space"); |
704 |
return 0; |
705 |
} else if ((tmpx < vc->vc_cols - 2) |
706 |
&& (ch == SPACE || IS_WDLM(ch )) |
707 |
&& ((char) get_char (vc, (u_short * ) tmp_pos+1 ) > SPACE)) { |
708 |
tmp_pos += 2; |
709 |
tmpx++; |
710 |
} else |
711 |
while (tmpx > 0 ) { |
712 |
ch = (char) get_char(vc, (u_short *) tmp_pos - 1); |
713 |
if ((ch == SPACE || IS_WDLM(ch)) |
714 |
&& ((char) get_char(vc, (u_short *) tmp_pos) > SPACE)) |
715 |
break; |
716 |
tmp_pos -= 2; |
717 |
tmpx--; |
718 |
} |
719 |
attr_ch = get_char(vc, (u_short *) tmp_pos); |
720 |
spk_attr = attr_ch >> 8; |
721 |
buf[cnt++] = attr_ch & 0xff; |
722 |
while (tmpx < vc->vc_cols - 1) { |
723 |
tmp_pos += 2; |
724 |
tmpx++; |
725 |
ch = (char) get_char(vc, (u_short *) tmp_pos); |
726 |
if ((ch == SPACE) || (IS_WDLM(buf[cnt-1]) && (ch > SPACE))) |
727 |
break; |
728 |
buf[cnt++] = ch; |
729 |
} |
730 |
buf[cnt] = '\0'; |
731 |
return cnt; |
732 |
} |
733 |
|
734 |
static void say_word(struct vc_data *vc) |
735 |
{ |
736 |
u_long cnt = get_word(vc ); |
737 |
u_short saved_punc_mask = punc_mask; |
738 |
if (cnt == 0) |
739 |
return; |
740 |
punc_mask = PUNC; |
741 |
buf[cnt++] = SPACE; |
742 |
spkup_write(buf, cnt); |
743 |
punc_mask = saved_punc_mask; |
744 |
} |
745 |
|
746 |
static void say_prev_word(struct vc_data *vc) |
747 |
{ |
748 |
char ch; |
749 |
u_short edge_said = 0, last_state = 0, state = 0; |
750 |
spk_parked |= 0x01; |
751 |
if (spk_x == 0) { |
752 |
if (spk_y == 0) { |
753 |
announce_edge(vc, edge_top); |
754 |
return; |
755 |
} |
756 |
spk_y--; |
757 |
spk_x = vc->vc_cols; |
758 |
edge_said = edge_quiet; |
759 |
} |
760 |
while (1) { |
761 |
if (spk_x == 0) { |
762 |
if (spk_y == 0) { |
763 |
edge_said = edge_top; |
764 |
break; |
765 |
} |
766 |
if (edge_said != edge_quiet) |
767 |
edge_said = edge_left; |
768 |
if (state > 0) |
769 |
break; |
770 |
spk_y--; |
771 |
spk_x = vc->vc_cols - 1; |
772 |
} else spk_x--; |
773 |
spk_pos -= 2; |
774 |
ch = (char) get_char(vc, (u_short *) spk_pos); |
775 |
if (ch == SPACE) |
776 |
state = 0; |
777 |
else if (IS_WDLM(ch)) |
778 |
state = 1; |
779 |
else state = 2; |
780 |
if (state < last_state) { |
781 |
spk_pos += 2; |
782 |
spk_x++; |
783 |
break; |
784 |
} |
785 |
last_state = state; |
786 |
} |
787 |
if (spk_x == 0 && edge_said == edge_quiet) |
788 |
edge_said = edge_left; |
789 |
if (edge_said > 0 && edge_said < edge_quiet) |
790 |
announce_edge(vc, edge_said); |
791 |
say_word(vc); |
792 |
} |
793 |
|
794 |
static void say_next_word(struct vc_data *vc) |
795 |
{ |
796 |
char ch; |
797 |
u_short edge_said = 0, last_state = 2, state = 0; |
798 |
spk_parked |= 0x01; |
799 |
if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) { |
800 |
announce_edge(vc, edge_bottom); |
801 |
return; |
802 |
} |
803 |
while (1) { |
804 |
ch = (char) get_char(vc, (u_short *) spk_pos ); |
805 |
if (ch == SPACE) |
806 |
state = 0; |
807 |
else if (IS_WDLM(ch)) |
808 |
state = 1; |
809 |
else state = 2; |
810 |
if (state > last_state) break; |
811 |
if (spk_x >= vc->vc_cols - 1) { |
812 |
if (spk_y == vc->vc_rows - 1) { |
813 |
edge_said = edge_bottom; |
814 |
break; |
815 |
} |
816 |
state = 0; |
817 |
spk_y++; |
818 |
spk_x = 0; |
819 |
edge_said = edge_right; |
820 |
} else spk_x++; |
821 |
spk_pos += 2; |
822 |
last_state = state; |
823 |
} |
824 |
if (edge_said > 0) |
825 |
announce_edge(vc, edge_said); |
826 |
say_word(vc); |
827 |
} |
828 |
|
829 |
static void spell_word(struct vc_data *vc) |
830 |
{ |
831 |
static char *delay_str[] = { " ", ", ", ". ", ". . ", ". . . " }; |
832 |
char *cp = buf, *str_cap = str_caps_stop; |
833 |
char *cp1, *last_cap = str_caps_stop; |
834 |
u_char ch; |
835 |
if (!get_word(vc)) |
836 |
return; |
837 |
while ((ch = (u_char) *cp)) { |
838 |
if (cp != buf) |
839 |
synth_write_string(delay_str[spell_delay]); |
840 |
if (IS_CHAR(ch, B_CAP)) { |
841 |
str_cap = str_caps_start; |
842 |
if (*str_caps_stop) |
843 |
pitch_shift++; |
844 |
else /* synth has no pitch */ |
845 |
last_cap = str_caps_stop; |
846 |
} else |
847 |
str_cap = str_caps_stop; |
848 |
if (str_cap != last_cap) { |
849 |
synth_write_string(str_cap); |
850 |
last_cap = str_cap; |
851 |
} |
852 |
if (this_speakup_key == SPELL_PHONETIC |
853 |
&& (IS_CHAR(ch, B_ALPHA))) { |
854 |
ch &= 31; |
855 |
cp1 = phonetic[--ch]; |
856 |
} else { |
857 |
cp1 = characters[ch]; |
858 |
if (*cp1 == '^') { |
859 |
synth_write_string(str_ctl); |
860 |
cp1++; |
861 |
} |
862 |
} |
863 |
synth_write_string(cp1); |
864 |
cp++; |
865 |
} |
866 |
if (str_cap != str_caps_stop) |
867 |
synth_write_string(str_caps_stop); |
868 |
} |
869 |
|
870 |
static int get_line(struct vc_data *vc) |
871 |
{ |
872 |
u_long tmp = spk_pos - (spk_x * 2); |
873 |
int i = 0; |
874 |
spk_old_attr = spk_attr; |
875 |
spk_attr = get_attributes((u_short *) spk_pos); |
876 |
for (i = 0; i < vc->vc_cols; i++) { |
877 |
buf[i] = (u_char) get_char(vc, (u_short *) tmp); |
878 |
tmp += 2; |
879 |
} |
880 |
for (--i; i >= 0; i--) |
881 |
if (buf[i] != SPACE) |
882 |
break; |
883 |
return ++i; |
884 |
} |
885 |
|
886 |
static void say_line(struct vc_data *vc) |
887 |
{ |
888 |
int i = get_line(vc); |
889 |
char *cp; |
890 |
char num_buf[8]; |
891 |
u_short saved_punc_mask = punc_mask; |
892 |
if (i == 0) { |
893 |
synth_write_msg(blank_msg); |
894 |
return; |
895 |
} |
896 |
buf[i++] = '\n'; |
897 |
if (this_speakup_key == SAY_LINE_INDENT) { |
898 |
for (cp = buf; *cp == SPACE; cp++) |
899 |
; |
900 |
sprintf(num_buf, "%d, ", (cp - buf) + 1); |
901 |
synth_write_string(num_buf); |
902 |
} |
903 |
punc_mask = punc_masks[reading_punc]; |
904 |
spkup_write(buf, i); |
905 |
punc_mask = saved_punc_mask; |
906 |
} |
907 |
|
908 |
static void say_prev_line(struct vc_data *vc) |
909 |
{ |
910 |
spk_parked |= 0x01; |
911 |
if (spk_y == 0) { |
912 |
announce_edge(vc, edge_top); |
913 |
return; |
914 |
} |
915 |
spk_y--; |
916 |
spk_pos -= vc->vc_size_row; |
917 |
say_line(vc); |
918 |
} |
919 |
|
920 |
static void say_next_line(struct vc_data *vc) |
921 |
{ |
922 |
spk_parked |= 0x01; |
923 |
if (spk_y == vc->vc_rows - 1) { |
924 |
announce_edge(vc, edge_bottom); |
925 |
return; |
926 |
} |
927 |
spk_y++; |
928 |
spk_pos += vc->vc_size_row; |
929 |
say_line(vc); |
930 |
} |
931 |
|
932 |
static int say_from_to(struct vc_data *vc, u_long from, u_long to, |
933 |
int read_punc) |
934 |
{ |
935 |
int i = 0; |
936 |
u_short saved_punc_mask = punc_mask; |
937 |
spk_old_attr = spk_attr; |
938 |
spk_attr = get_attributes((u_short *) from); |
939 |
while (from < to) { |
940 |
buf[i++] = (char) get_char(vc, (u_short *) from); |
941 |
from += 2; |
942 |
if (i >= vc->vc_size_row) |
943 |
break; |
944 |
} |
945 |
for (--i; i >= 0; i--) |
946 |
if (buf[i] != SPACE) |
947 |
break; |
948 |
buf[++i] = SPACE; |
949 |
buf[++i] = '\0'; |
950 |
if (i < 1) |
951 |
return i; |
952 |
if (read_punc) |
953 |
punc_mask = punc_info[reading_punc].mask; |
954 |
spkup_write(buf, i); |
955 |
if (read_punc) |
956 |
punc_mask = saved_punc_mask; |
957 |
return i - 1; |
958 |
} |
959 |
|
960 |
static void say_line_from_to(struct vc_data *vc, u_long from, u_long to, |
961 |
int read_punc) |
962 |
{ |
963 |
u_long start = vc->vc_origin + (spk_y * vc->vc_size_row); |
964 |
u_long end = start + (to * 2); |
965 |
start += from * 2; |
966 |
if (say_from_to(vc, start, end, read_punc) <= 0) |
967 |
if (cursor_track != read_all_mode) |
968 |
synth_write_msg(blank_msg); |
969 |
} |
970 |
|
971 |
// Sentence Reading Commands |
972 |
|
973 |
void synth_insert_next_index(int); |
974 |
|
975 |
static int currsentence; |
976 |
static int numsentences[2]; |
977 |
static char *sentbufend[2]; |
978 |
static char *sentmarks[2][10]; |
979 |
static int currbuf=0; |
980 |
static int bn; |
981 |
static char sentbuf[2][256]; |
982 |
|
983 |
static int say_sentence_num(int num , int prev) |
984 |
{ |
985 |
bn = currbuf; |
986 |
currsentence = num + 1; |
987 |
if (prev && --bn == -1) |
988 |
bn = 1; |
989 |
|
990 |
if (num > numsentences[bn]) |
991 |
return 0; |
992 |
|
993 |
spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]); |
994 |
return 1; |
995 |
} |
996 |
|
997 |
static int get_sentence_buf(struct vc_data *vc, int read_punc) |
998 |
{ |
999 |
u_long start, end; |
1000 |
int i, bn; |
1001 |
currbuf++; |
1002 |
if (currbuf == 2) |
1003 |
currbuf = 0; |
1004 |
bn = currbuf; |
1005 |
start = vc->vc_origin + ((spk_y) *vc->vc_size_row); |
1006 |
end = vc->vc_origin+((spk_y) *vc->vc_size_row) + vc->vc_cols * 2; |
1007 |
|
1008 |
numsentences[bn] = 0; |
1009 |
sentmarks[bn][0] = &sentbuf[bn][0]; |
1010 |
i = 0; |
1011 |
spk_old_attr = spk_attr; |
1012 |
spk_attr = get_attributes((u_short *) start); |
1013 |
|
1014 |
while (start < end) { |
1015 |
sentbuf[bn][i] = (char) get_char(vc, (u_short *) start); |
1016 |
if (i > 0) { |
1017 |
if (sentbuf[bn][i] == SPACE && sentbuf[bn][i-1] == '.' |
1018 |
&& numsentences[bn] < 9) { |
1019 |
// Sentence Marker |
1020 |
numsentences[bn]++; |
1021 |
sentmarks[bn][numsentences[bn]] = |
1022 |
&sentbuf[bn][i]; |
1023 |
} |
1024 |
} |
1025 |
i++; |
1026 |
start += 2; |
1027 |
if (i >= vc->vc_size_row) |
1028 |
break; |
1029 |
} |
1030 |
|
1031 |
for (--i; i >= 0; i--) |
1032 |
if (sentbuf[bn][i] != SPACE) |
1033 |
break; |
1034 |
|
1035 |
if (i < 1) |
1036 |
return -1; |
1037 |
|
1038 |
sentbuf[bn][++i] = SPACE; |
1039 |
sentbuf[bn][++i] = '\0'; |
1040 |
|
1041 |
sentbufend[bn] = &sentbuf[bn][i]; |
1042 |
return numsentences[bn]; |
1043 |
} |
1044 |
|
1045 |
static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to) |
1046 |
{ |
1047 |
u_long start = vc->vc_origin, end; |
1048 |
if (from > 0) |
1049 |
start += from * vc->vc_size_row; |
1050 |
if (to > vc->vc_rows) |
1051 |
to = vc->vc_rows; |
1052 |
end = vc->vc_origin + (to * vc->vc_size_row); |
1053 |
for (from = start; from < end; from = to) { |
1054 |
to = from + vc->vc_size_row; |
1055 |
say_from_to(vc, from, to, 1); |
1056 |
} |
1057 |
} |
1058 |
|
1059 |
static void say_screen(struct vc_data *vc) |
1060 |
{ |
1061 |
say_screen_from_to(vc, 0, vc->vc_rows); |
1062 |
} |
1063 |
|
1064 |
static void speakup_win_say(struct vc_data *vc) |
1065 |
{ |
1066 |
u_long start, end, from, to; |
1067 |
if (win_start < 2) { |
1068 |
synth_write_msg("no window"); |
1069 |
return; |
1070 |
} |
1071 |
start = vc->vc_origin + (win_top * vc->vc_size_row); |
1072 |
end = vc->vc_origin + (win_bottom * vc->vc_size_row); |
1073 |
while (start <= end) { |
1074 |
from = start + (win_left * 2); |
1075 |
to = start + (win_right * 2); |
1076 |
say_from_to(vc, from, to, 1); |
1077 |
start += vc->vc_size_row; |
1078 |
} |
1079 |
} |
1080 |
|
1081 |
static void top_edge (struct vc_data *vc) |
1082 |
{ |
1083 |
spk_parked |= 0x01; |
1084 |
spk_pos = vc->vc_origin + 2 * spk_x; |
1085 |
spk_y = 0; |
1086 |
say_line(vc); |
1087 |
} |
1088 |
|
1089 |
static void bottom_edge(struct vc_data *vc) |
1090 |
{ |
1091 |
spk_parked |= 0x01; |
1092 |
spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row; |
1093 |
spk_y = vc->vc_rows - 1; |
1094 |
say_line(vc); |
1095 |
} |
1096 |
|
1097 |
static void left_edge(struct vc_data *vc) |
1098 |
{ |
1099 |
spk_parked |= 0x01; |
1100 |
spk_pos -= spk_x * 2; |
1101 |
spk_x = 0; |
1102 |
say_char (vc ); |
1103 |
} |
1104 |
|
1105 |
static void right_edge(struct vc_data *vc) |
1106 |
{ |
1107 |
spk_parked |= 0x01; |
1108 |
spk_pos += (vc->vc_cols - spk_x - 1) * 2; |
1109 |
spk_x = vc->vc_cols - 1; |
1110 |
say_char(vc); |
1111 |
} |
1112 |
|
1113 |
static void say_first_char(struct vc_data *vc) |
1114 |
{ |
1115 |
int i, len = get_line(vc); |
1116 |
u_char ch; |
1117 |
spk_parked |= 0x01; |
1118 |
if (len == 0) { |
1119 |
synth_write_msg(blank_msg); |
1120 |
return; |
1121 |
} |
1122 |
for (i = 0; i < len; i++) |
1123 |
if (buf[i] != SPACE) |
1124 |
break; |
1125 |
ch = buf[i]; |
1126 |
spk_pos -= (spk_x - i) * 2; |
1127 |
spk_x = i; |
1128 |
sprintf(buf, "%d, ", ++i); |
1129 |
synth_write_string(buf); |
1130 |
speak_char(ch); |
1131 |
} |
1132 |
|
1133 |
static void say_last_char(struct vc_data *vc) |
1134 |
{ |
1135 |
int len = get_line(vc); |
1136 |
u_char ch; |
1137 |
spk_parked |= 0x01; |
1138 |
if (len == 0) { |
1139 |
synth_write_msg(blank_msg); |
1140 |
return; |
1141 |
} |
1142 |
ch = buf[--len]; |
1143 |
spk_pos -= (spk_x - len) * 2; |
1144 |
spk_x = len; |
1145 |
sprintf (buf, "%d, ", ++len); |
1146 |
synth_write_string(buf); |
1147 |
speak_char(ch); |
1148 |
} |
1149 |
|
1150 |
static void say_position(struct vc_data *vc) |
1151 |
{ |
1152 |
sprintf(buf, "line %ld, col %ld, t t y %d\n", spk_y + 1, spk_x + 1, |
1153 |
vc->vc_num + 1); |
1154 |
synth_write_string(buf); |
1155 |
} |
1156 |
|
1157 |
// Added by brianb |
1158 |
static void say_char_num(struct vc_data *vc) |
1159 |
{ |
1160 |
u_short ch = get_char(vc, (u_short *) spk_pos); |
1161 |
ch &= 0xff; |
1162 |
sprintf(buf, "hex %02x, decimal %d", ch, ch); |
1163 |
synth_write_msg(buf); |
1164 |
} |
1165 |
|
1166 |
/* these are stub functions to keep keyboard.c happy. */ |
1167 |
|
1168 |
static void say_from_top(struct vc_data *vc) |
1169 |
{ |
1170 |
say_screen_from_to(vc, 0, spk_y); |
1171 |
} |
1172 |
|
1173 |
static void say_to_bottom(struct vc_data *vc) |
1174 |
{ |
1175 |
say_screen_from_to(vc, spk_y, vc->vc_rows); |
1176 |
} |
1177 |
|
1178 |
static void say_from_left(struct vc_data *vc) |
1179 |
{ |
1180 |
say_line_from_to(vc, 0, spk_x, 1); |
1181 |
} |
1182 |
|
1183 |
static void say_to_right(struct vc_data *vc) |
1184 |
{ |
1185 |
say_line_from_to(vc, spk_x, vc->vc_cols, 1); |
1186 |
} |
1187 |
|
1188 |
/* end of stub functions. */ |
1189 |
|
1190 |
static void spkup_write(const char *in_buf, int count) |
1191 |
{ |
1192 |
static int rep_count = 0; |
1193 |
static u_char ch = '\0', old_ch = '\0'; |
1194 |
static u_short char_type = 0, last_type = 0; |
1195 |
static u_char *exn_ptr = NULL; |
1196 |
int in_count = count; |
1197 |
char rpt_buf[32]; |
1198 |
spk_keydown = 0; |
1199 |
while ( count-- ) { |
1200 |
if ( cursor_track == read_all_mode ) { |
1201 |
// Insert Sentence Index |
1202 |
if (( in_buf == sentmarks[bn][currsentence] ) && |
1203 |
( currsentence <= numsentences[bn] )) |
1204 |
synth_insert_next_index(currsentence++); |
1205 |
} |
1206 |
ch = (u_char )*in_buf++; |
1207 |
char_type = spk_chartab[ch]; |
1208 |
if (ch == old_ch && !(char_type&B_NUM ) ) { |
1209 |
if (++rep_count > 2 ) continue; |
1210 |
} else { |
1211 |
if ( (last_type&CH_RPT) && rep_count > 2 ) { |
1212 |
sprintf (rpt_buf, " times %d . ", ++rep_count ); |
1213 |
synth_write_string (rpt_buf ); |
1214 |
} |
1215 |
rep_count = 0; |
1216 |
} |
1217 |
if ( !( char_type&B_NUM ) ) |
1218 |
exn_ptr = NULL; |
1219 |
if (ch == spk_lastkey ) { |
1220 |
rep_count = 0; |
1221 |
if ( key_echo == 1 && ch >= MINECHOCHAR ) |
1222 |
speak_char( ch ); |
1223 |
} else if ( ( char_type&B_ALPHA ) ) { |
1224 |
if ( (synth_flags&SF_DEC) && (last_type&PUNC) ) |
1225 |
synth_buffer_add ( SPACE ); |
1226 |
synth_write( &ch, 1 ); |
1227 |
} else if ( ( char_type&B_NUM ) ) { |
1228 |
rep_count = 0; |
1229 |
if ( (last_type&B_EXNUM) && synth_buff_in == exn_ptr+1 ) { |
1230 |
synth_buff_in--; |
1231 |
synth_buffer_add( old_ch ); |
1232 |
exn_ptr = NULL; |
1233 |
} |
1234 |
synth_write( &ch, 1 ); |
1235 |
} else if ( (char_type&punc_mask) ) { |
1236 |
speak_char( ch ); |
1237 |
char_type &= ~PUNC; /* for dec nospell processing */ |
1238 |
} else if ( ( char_type&SYNTH_OK ) ) { |
1239 |
/* these are usually puncts like . and , which synth needs for expression. |
1240 |
* suppress multiple to get rid of long pausesand clear repeat count so if |
1241 |
*someone has repeats on you don't get nothing repeated count */ |
1242 |
if ( ch != old_ch ) |
1243 |
synth_write( &ch, 1 ); |
1244 |
else rep_count = 0; |
1245 |
} else { |
1246 |
if ( ( char_type&B_EXNUM ) ) |
1247 |
exn_ptr = (u_char *)synth_buff_in; |
1248 |
/* send space and record position, if next is num overwrite space */ |
1249 |
if ( old_ch != ch ) synth_buffer_add ( SPACE ); |
1250 |
else rep_count = 0; |
1251 |
} |
1252 |
old_ch = ch; |
1253 |
last_type = char_type; |
1254 |
} |
1255 |
spk_lastkey = 0; |
1256 |
if (in_count > 2 && rep_count > 2 ) { |
1257 |
if ( (last_type&CH_RPT) ) { |
1258 |
sprintf (rpt_buf, " repeated %d . ", ++rep_count ); |
1259 |
synth_write_string (rpt_buf ); |
1260 |
} |
1261 |
rep_count = 0; |
1262 |
} |
1263 |
} |
1264 |
|
1265 |
static char *ctl_key_ids[] = { |
1266 |
"shift", "altgr", "control", "ault", "l shift", "speakup", |
1267 |
"l control", "r control" |
1268 |
}; |
1269 |
#define NUM_CTL_LABELS 8 |
1270 |
|
1271 |
static void read_all_doc(struct vc_data *vc); |
1272 |
static void cursor_stop_timer(void); |
1273 |
|
1274 |
static void handle_shift(struct vc_data *vc, u_char value, char up_flag) |
1275 |
{ |
1276 |
(*do_shift)(vc, value, up_flag); |
1277 |
if (synth == NULL || up_flag || spk_killed) |
1278 |
return; |
1279 |
if (cursor_track == read_all_mode) { |
1280 |
switch (value) { |
1281 |
case KVAL(K_SHIFT): |
1282 |
cursor_stop_timer(); |
1283 |
spk_shut_up &= 0xfe; |
1284 |
do_flush(); |
1285 |
read_all_doc(vc); |
1286 |
break; |
1287 |
case KVAL(K_CTRL): |
1288 |
cursor_stop_timer(); |
1289 |
cursor_track=prev_cursor_track; |
1290 |
spk_shut_up &= 0xfe; |
1291 |
do_flush(); |
1292 |
break; |
1293 |
} |
1294 |
} else { |
1295 |
spk_shut_up &= 0xfe; |
1296 |
do_flush(); |
1297 |
} |
1298 |
if (say_ctrl && value < NUM_CTL_LABELS) |
1299 |
synth_write_string(ctl_key_ids[value]); |
1300 |
} |
1301 |
|
1302 |
static void handle_latin(struct vc_data *vc, u_char value, char up_flag) |
1303 |
{ |
1304 |
(*do_latin)(vc, value, up_flag); |
1305 |
if (up_flag) { |
1306 |
spk_lastkey = spk_keydown = 0; |
1307 |
return; |
1308 |
} |
1309 |
if (synth == NULL || spk_killed) |
1310 |
return; |
1311 |
spk_shut_up &= 0xfe; |
1312 |
spk_lastkey = value; |
1313 |
spk_keydown++; |
1314 |
spk_parked &= 0xfe; |
1315 |
if (key_echo == 2 && value >= MINECHOCHAR) |
1316 |
speak_char( value ); |
1317 |
} |
1318 |
|
1319 |
static int set_key_info(const u_char *key_info, u_char *k_buffer) |
1320 |
{ |
1321 |
int i = 0, states, key_data_len; |
1322 |
const u_char *cp = key_info; |
1323 |
u_char *cp1 = k_buffer; |
1324 |
u_char ch, version, num_keys; |
1325 |
version = *cp++; |
1326 |
if (version != KEY_MAP_VER) |
1327 |
return -1; |
1328 |
num_keys = *cp; |
1329 |
states = (int) cp[1]; |
1330 |
key_data_len = (states + 1) * (num_keys + 1); |
1331 |
if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(key_buf)) |
1332 |
return -2; |
1333 |
memset(k_buffer, 0, SHIFT_TBL_SIZE); |
1334 |
memset(our_keys, 0, sizeof(our_keys)); |
1335 |
shift_table = k_buffer; |
1336 |
our_keys[0] = shift_table; |
1337 |
cp1 += SHIFT_TBL_SIZE; |
1338 |
memcpy(cp1, cp, key_data_len + 3); |
1339 |
/* get num_keys, states and data*/ |
1340 |
cp1 += 2; /* now pointing at shift states */ |
1341 |
for (i = 1; i <= states; i++) { |
1342 |
ch = *cp1++; |
1343 |
if (ch >= SHIFT_TBL_SIZE) |
1344 |
return -3; |
1345 |
shift_table[ch] = i; |
1346 |
} |
1347 |
keymap_flags = *cp1++; |
1348 |
while ((ch = *cp1)) { |
1349 |
if (ch >= MAX_KEY) |
1350 |
return -4; |
1351 |
our_keys[ch] = cp1; |
1352 |
cp1 += states + 1; |
1353 |
} |
1354 |
return 0; |
1355 |
} |
1356 |
|
1357 |
static struct st_num_var spk_num_vars[] = { /* bell must be first to set high limit */ |
1358 |
{ BELL_POS, 0, 0, 0, 0, 0, 0, 0 }, |
1359 |
{ SPELL_DELAY, 0, 0, 0, 5, 0, 0, 0 }, |
1360 |
{ ATTRIB_BLEEP, 0, 1, 0, 3, 0, 0, 0 }, |
1361 |
{ BLEEPS, 0, 3, 0, 3, 0, 0, 0 }, |
1362 |
{ BLEEP_TIME, 0, 30, 1, 200, 0, 0, 0 }, |
1363 |
{ PUNC_LEVEL, 0, 1, 0, 4, 0, 0, 0 }, |
1364 |
{ READING_PUNC, 0, 1, 0, 4, 0, 0, 0 }, |
1365 |
{ CURSOR_TIME, 0, 120, 50, 600, 0, 0, 0 }, |
1366 |
{ SAY_CONTROL, TOGGLE_0 }, |
1367 |
{ SAY_WORD_CTL, TOGGLE_0 }, |
1368 |
{ NO_INTERRUPT, TOGGLE_0 }, |
1369 |
{ KEY_ECHO, 0, 1, 0, 2, 0, 0, 0 }, |
1370 |
V_LAST_NUM |
1371 |
}; |
1372 |
|
1373 |
static char *cursor_msgs[] = { "cursoring off", "cursoring on", |
1374 |
"highlight tracking", "read windo", |
1375 |
"read all" }; |
1376 |
|
1377 |
static void toggle_cursoring(struct vc_data *vc) |
1378 |
{ |
1379 |
if (cursor_track == read_all_mode) |
1380 |
cursor_track = prev_cursor_track; |
1381 |
if (++cursor_track >= CT_Max) |
1382 |
cursor_track = 0; |
1383 |
synth_write_msg(cursor_msgs[cursor_track]); |
1384 |
} |
1385 |
|
1386 |
static void reset_default_chars(void) |
1387 |
{ |
1388 |
int i; |
1389 |
if (default_chars[(int )'a'] == NULL) /* lowers are null first time */ |
1390 |
for (i = (int )'a'; default_chars[i] == NULL; i++) |
1391 |
default_chars[i] = default_chars[i - 32]; |
1392 |
else /* free any non-default */ |
1393 |
for (i = 0; i < 256; i++) { |
1394 |
if (characters[i] != default_chars[i]) |
1395 |
kfree(characters[i]); |
1396 |
} |
1397 |
memcpy(characters, default_chars, sizeof(default_chars)); |
1398 |
} |
1399 |
|
1400 |
static void reset_default_chartab(void) |
1401 |
{ |
1402 |
memcpy(spk_chartab, default_chartab, sizeof(default_chartab)); |
1403 |
} |
1404 |
|
1405 |
static void handle_cursor(struct vc_data *vc, u_char value, char up_flag); |
1406 |
static void handle_spec(struct vc_data *vc, u_char value, char up_flag); |
1407 |
static void cursor_done(u_long data ); |
1408 |
|
1409 |
static declare_timer(cursor_timer); |
1410 |
|
1411 |
static void __init speakup_open(struct vc_data *vc, |
1412 |
struct st_spk_t *first_console) |
1413 |
{ |
1414 |
int i; |
1415 |
struct st_num_var *n_var; |
1416 |
|
1417 |
reset_default_chars(); |
1418 |
reset_default_chartab(); |
1419 |
memset(speakup_console, 0, sizeof(speakup_console)); |
1420 |
if (first_console == NULL) |
1421 |
return; |
1422 |
speakup_console[vc->vc_num] = first_console; |
1423 |
speakup_date(vc); |
1424 |
pr_info("%s: initialized\n", SPEAKUP_VERSION); |
1425 |
init_timer(&cursor_timer); |
1426 |
cursor_timer.entry.prev = NULL; |
1427 |
cursor_timer.function = cursor_done; |
1428 |
init_sleeper(synth_sleeping_list); |
1429 |
strlwr(synth_name); |
1430 |
spk_num_vars[0].high = vc->vc_cols; |
1431 |
for (n_var = spk_num_vars; n_var->var_id >= 0; n_var++) |
1432 |
speakup_register_var(n_var); |
1433 |
for (i = 1; punc_info[i].mask != 0; i++) |
1434 |
set_mask_bits(0, i, 2); |
1435 |
do_latin = key_handler[KT_LATIN]; |
1436 |
key_handler[KT_LATIN] = handle_latin; |
1437 |
do_spec = key_handler[KT_SPEC]; |
1438 |
key_handler[KT_SPEC] = handle_spec; |
1439 |
do_cursor = key_handler[KT_CUR]; |
1440 |
key_handler[KT_CUR] = handle_cursor; |
1441 |
do_shift = key_handler[KT_SHIFT]; |
1442 |
key_handler[KT_SHIFT] = handle_shift; |
1443 |
set_key_info(key_defaults, key_buf); |
1444 |
if (quiet_boot) spk_shut_up |= 0x01; |
1445 |
} |
1446 |
|
1447 |
#ifdef CONFIG_PROC_FS |
1448 |
|
1449 |
// speakup /proc interface code |
1450 |
|
1451 |
/* Usage: |
1452 |
cat /proc/speakup/version |
1453 |
|
1454 |
cat /proc/speakup/characters > foo |
1455 |
less /proc/speakup/characters |
1456 |
vi /proc/speakup/characters |
1457 |
|
1458 |
cat foo > /proc/speakup/characters |
1459 |
cat > /proc/speakup/characters |
1460 |
echo 39 apostrophe > /proc/speakup/characters |
1461 |
echo 87 w > /proc/speakup/characters |
1462 |
echo 119 w > /proc/speakup/characters |
1463 |
echo defaults > /proc/speakup/characters |
1464 |
echo reset > /proc/speakup/characters |
1465 |
|
1466 |
|
1467 |
cat /proc/speakup/chartab > foo |
1468 |
less /proc/speakup/chartab |
1469 |
vi /proc/speakup/chartab |
1470 |
|
1471 |
cat foo > /proc/speakup/chartab |
1472 |
cat > /proc/speakup/chartab |
1473 |
echo 233 ALPHA > /proc/speakup/chartab |
1474 |
echo 46 A_PUNC > /proc/speakup/chartab |
1475 |
echo defaults > /proc/speakup/chartab |
1476 |
echo reset > /proc/speakup/chartab |
1477 |
*/ |
1478 |
|
1479 |
// keymap handlers |
1480 |
|
1481 |
static int keys_read_proc(char *page, char **start, off_t off, int count, |
1482 |
int *eof, void *data) |
1483 |
{ |
1484 |
char *cp = page; |
1485 |
int i, n, num_keys, nstates; |
1486 |
u_char *cp1 = key_buf + SHIFT_TBL_SIZE, ch; |
1487 |
num_keys = (int)(*cp1); |
1488 |
nstates = (int)cp1[1]; |
1489 |
cp += sprintf( cp, "%d, %d, %d,\n", KEY_MAP_VER, num_keys, nstates ); |
1490 |
cp1 += 2; /* now pointing at shift states */ |
1491 |
/* dump num_keys+1 as first row is shift states + flags, |
1492 |
each subsequent row is key + states */ |
1493 |
for ( n = 0; n <= num_keys; n++ ) { |
1494 |
for ( i = 0; i <= nstates; i++ ) { |
1495 |
ch = *cp1++; |
1496 |
cp += sprintf( cp, "%d,", (int)ch ); |
1497 |
*cp++ = ( i < nstates ) ? SPACE : '\n'; |
1498 |
} |
1499 |
} |
1500 |
cp += sprintf( cp, "0, %d\n", KEY_MAP_VER ); |
1501 |
*start = 0; |
1502 |
*eof = 1; |
1503 |
return (int)(cp-page); |
1504 |
} |
1505 |
|
1506 |
static char * |
1507 |
s2uchar ( char *start, char *dest ) |
1508 |
{ |
1509 |
int val = 0; |
1510 |
while ( *start && *start <= SPACE ) start++; |
1511 |
while ( *start >= '0' && *start <= '9' ) { |
1512 |
val *= 10; |
1513 |
val += ( *start ) - '0'; |
1514 |
start++; |
1515 |
} |
1516 |
if ( *start == ',' ) start++; |
1517 |
*dest = (u_char)val; |
1518 |
return start; |
1519 |
} |
1520 |
|
1521 |
static int keys_write_proc(struct file *file, const char *buffer, u_long count, |
1522 |
void *data) |
1523 |
{ |
1524 |
int i, ret = count; |
1525 |
char *in_buff, *cp; |
1526 |
u_char *cp1; |
1527 |
if (count < 1 || count > 1800 ) |
1528 |
return -EINVAL; |
1529 |
in_buff = ( char * ) __get_free_page ( GFP_KERNEL ); |
1530 |
if ( !in_buff ) return -ENOMEM; |
1531 |
if (copy_from_user (in_buff, buffer, count ) ) { |
1532 |
free_page ( ( unsigned long ) in_buff ); |
1533 |
return -EFAULT; |
1534 |
} |
1535 |
if (in_buff[count - 1] == '\n' ) count--; |
1536 |
in_buff[count] = '\0'; |
1537 |
if ( count == 1 && *in_buff == 'd' ) { |
1538 |
free_page ( ( unsigned long ) in_buff ); |
1539 |
set_key_info( key_defaults, key_buf ); |
1540 |
return ret; |
1541 |
} |
1542 |
cp = in_buff; |
1543 |
cp1 = (u_char *)in_buff; |
1544 |
for ( i = 0; i < 3; i++ ) { |
1545 |
cp = s2uchar( cp, cp1 ); |
1546 |
cp1++; |
1547 |
} |
1548 |
i = (int)cp1[-2]+1; |
1549 |
i *= (int)cp1[-1]+1; |
1550 |
i+= 2; /* 0 and last map ver */ |
1551 |
if ( cp1[-3] != KEY_MAP_VER || cp1[-1] > 10 || |
1552 |
i+SHIFT_TBL_SIZE+4 >= sizeof(key_buf ) ) { |
1553 |
pr_warn( "i %d %d %d %d\n", i, (int)cp1[-3], (int)cp1[-2], (int)cp1[-1] ); |
1554 |
free_page ( ( unsigned long ) in_buff ); |
1555 |
return -EINVAL; |
1556 |
} |
1557 |
while ( --i >= 0 ) { |
1558 |
cp = s2uchar( cp, cp1 ); |
1559 |
cp1++; |
1560 |
if ( !(*cp) ) break; |
1561 |
} |
1562 |
if ( i != 0 || cp1[-1] != KEY_MAP_VER || cp1[-2] != 0 ) { |
1563 |
ret = -EINVAL; |
1564 |
pr_warn( "end %d %d %d %d\n", i, (int)cp1[-3], (int)cp1[-2], (int)cp1[-1] ); |
1565 |
} else { |
1566 |
if ( set_key_info( in_buff, key_buf ) ) { |
1567 |
set_key_info( key_defaults, key_buf ); |
1568 |
ret = -EINVAL; |
1569 |
pr_warn( "set key failed\n" ); |
1570 |
} |
1571 |
} |
1572 |
free_page ( ( unsigned long ) in_buff ); |
1573 |
return ret; |
1574 |
} |
1575 |
|
1576 |
// this is the handler for /proc/speakup/version |
1577 |
static int version_read_proc(char *page, char **start, off_t off, int count, |
1578 |
int *eof, void *data) |
1579 |
{ |
1580 |
int len = sprintf (page, "%s\n", SPEAKUP_VERSION ); |
1581 |
if (synth != NULL) |
1582 |
len += sprintf(page+len, "synth %s version %s\n", synth->name, |
1583 |
synth->version); |
1584 |
*start = 0; |
1585 |
*eof = 1; |
1586 |
return len; |
1587 |
} |
1588 |
|
1589 |
// this is the read handler for /proc/speakup/characters |
1590 |
static int chars_read_proc(char *page, char **start, off_t off, int count, |
1591 |
int *eof, void *data) |
1592 |
{ |
1593 |
int i, len = 0; |
1594 |
off_t begin = 0; |
1595 |
char *cp; |
1596 |
for (i = 0; i < 256; i++) { |
1597 |
cp = (characters[i]) ? characters[i] : "NULL"; |
1598 |
len += sprintf(page + len, "%d\t%s\n", i, cp); |
1599 |
if (len + begin > off + count) |
1600 |
break; |
1601 |
if (len + begin < off) { |
1602 |
begin += len; |
1603 |
len = 0; |
1604 |
} |
1605 |
} |
1606 |
if (i >= 256) |
1607 |
*eof = 1; |
1608 |
if (off >= len + begin) |
1609 |
return 0; |
1610 |
*start = page + (off - begin); |
1611 |
return ((count < begin + len - off) ? count : begin + len - off); |
1612 |
} |
1613 |
|
1614 |
static volatile int chars_timer_active = 0; // indicates when timer is set |
1615 |
static declare_timer(chars_timer); |
1616 |
|
1617 |
static void chars_stop_timer(void) |
1618 |
{ |
1619 |
if (chars_timer_active) |
1620 |
stop_timer(chars_timer); |
1621 |
} |
1622 |
|
1623 |
static int strings, rejects, updates; |
1624 |
|
1625 |
static void show_char_results (u_long data) |
1626 |
{ |
1627 |
int len; |
1628 |
char buf[80]; |
1629 |
chars_stop_timer(); |
1630 |
len = sprintf(buf, " updated %d of %d character descriptions\n", |
1631 |
updates, strings); |
1632 |
if (rejects) |
1633 |
sprintf(buf + (len - 1), " with %d reject%s\n", |
1634 |
rejects, rejects > 1 ? "s" : ""); |
1635 |
printk(buf); |
1636 |
} |
1637 |
|
1638 |
// this is the read handler for /proc/speakup/chartab |
1639 |
static int chartab_read_proc(char *page, char **start, off_t off, int count, |
1640 |
int *eof, void *data) |
1641 |
{ |
1642 |
int i, len = 0; |
1643 |
off_t begin = 0; |
1644 |
char *cp; |
1645 |
for (i = 0; i < 256; i++) { |
1646 |
cp = "0"; |
1647 |
if (IS_TYPE(i, B_CTL)) |
1648 |
cp = "B_CTL"; |
1649 |
else if (IS_TYPE(i, WDLM)) |
1650 |
cp = "WDLM"; |
1651 |
else if (IS_TYPE(i, A_PUNC)) |
1652 |
cp = "A_PUNC"; |
1653 |
else if (IS_TYPE(i, PUNC)) |
1654 |
cp = "PUNC"; |
1655 |
else if (IS_TYPE(i, NUM)) |
1656 |
cp = "NUM"; |
1657 |
else if (IS_TYPE(i, A_CAP)) |
1658 |
cp = "A_CAP"; |
1659 |
else if (IS_TYPE(i, ALPHA)) |
1660 |
cp = "ALPHA"; |
1661 |
else if (IS_TYPE(i, B_CAPSYM)) |
1662 |
cp = "B_CAPSYM"; |
1663 |
else if (IS_TYPE(i, B_SYM)) |
1664 |
cp = "B_SYM"; |
1665 |
|
1666 |
len += sprintf(page + len, "%d\t%s\n", i, cp); |
1667 |
if (len + begin > off + count) |
1668 |
break; |
1669 |
if (len + begin < off) { |
1670 |
begin += len; |
1671 |
len = 0; |
1672 |
} |
1673 |
} |
1674 |
if (i >= 256) |
1675 |
*eof = 1; |
1676 |
if (off >= len + begin) |
1677 |
return 0; |
1678 |
*start = page + (off - begin); |
1679 |
return ((count < begin + len - off) ? count : begin + len - off); |
1680 |
} |
1681 |
|
1682 |
static int chartab_get_value(char *keyword) |
1683 |
{ |
1684 |
int value = 0; |
1685 |
|
1686 |
if (!strcmp(keyword, "ALPHA")) |
1687 |
value = ALPHA; |
1688 |
else if (!strcmp(keyword, "B_CTL")) |
1689 |
value = B_CTL; |
1690 |
else if (!strcmp(keyword, "WDLM")) |
1691 |
value = WDLM; |
1692 |
else if (!strcmp(keyword, "A_PUNC")) |
1693 |
value = A_PUNC; |
1694 |
else if (!strcmp(keyword, "PUNC")) |
1695 |
value = PUNC; |
1696 |
else if (!strcmp(keyword, "NUM")) |
1697 |
value = NUM; |
1698 |
else if (!strcmp(keyword, "A_CAP")) |
1699 |
value = A_CAP; |
1700 |
else if (!strcmp(keyword, "B_CAPSYM")) |
1701 |
value = B_CAPSYM; |
1702 |
else if (!strcmp(keyword, "B_SYM")) |
1703 |
value = B_SYM; |
1704 |
return value; |
1705 |
} |
1706 |
|
1707 |
/* this is the write handler for /proc/speakup/silent */ |
1708 |
static int silent_write_proc(struct file *file, const char *buffer, |
1709 |
u_long count, void *data) |
1710 |
{ |
1711 |
struct vc_data *vc = vc_cons[fg_console].d; |
1712 |
char ch = 0, shut; |
1713 |
if (count > 0 || count < 3 ) { |
1714 |
get_user (ch, buffer ); |
1715 |
if ( ch == '\n' ) ch = '0'; |
1716 |
} |
1717 |
if ( ch < '0' || ch > '7' ) { |
1718 |
pr_warn ( "silent value not in range (0,7)\n" ); |
1719 |
return count; |
1720 |
} |
1721 |
if ( (ch&2) ) { |
1722 |
shut = 1; |
1723 |
do_flush( ); |
1724 |
} else shut = 0; |
1725 |
if ( (ch&4) ) shut |= 0x40; |
1726 |
if ( (ch&1) ) |
1727 |
spk_shut_up |= shut; |
1728 |
else spk_shut_up &= ~shut; |
1729 |
return count; |
1730 |
} |
1731 |
|
1732 |
// this is the write handler for /proc/speakup/characters |
1733 |
static int chars_write_proc(struct file *file, const char *buffer, |
1734 |
u_long count, void *data) |
1735 |
{ |
1736 |
#define max_desc_len 72 |
1737 |
static int cnt = 0, state = 0; |
1738 |
static char desc[max_desc_len + 1]; |
1739 |
static u_long jiff_last = 0; |
1740 |
short i = 0, num; |
1741 |
int len; |
1742 |
char ch, *cp, *p_new; |
1743 |
// reset certain vars if enough time has elapsed since last called |
1744 |
if (jiffies - jiff_last > 10 ) { |
1745 |
cnt = state = strings = rejects = updates = 0; |
1746 |
} |
1747 |
jiff_last = jiffies; |
1748 |
get_more: |
1749 |
desc[cnt] = '\0'; |
1750 |
state = 0; |
1751 |
for (; i < count && state < 2; i++ ) { |
1752 |
get_user (ch, buffer + i ); |
1753 |
if ( ch == '\n' ) { |
1754 |
desc[cnt] = '\0'; |
1755 |
state = 2; |
1756 |
} else if (cnt < max_desc_len ) |
1757 |
desc[cnt++] = ch; |
1758 |
} |
1759 |
if (state < 2 ) return count; |
1760 |
cp = desc; |
1761 |
while ( *cp && (unsigned char)(*cp) <= SPACE ) cp++; |
1762 |
if ((!cnt ) || strchr ("dDrR", *cp ) ) { |
1763 |
reset_default_chars ( ); |
1764 |
pr_info( "character descriptions reset to defaults\n" ); |
1765 |
cnt = 0; |
1766 |
return count; |
1767 |
} |
1768 |
cnt = 0; |
1769 |
if (*cp == '#' ) goto get_more; |
1770 |
num = -1; |
1771 |
cp = speakup_s2i(cp, &num ); |
1772 |
while ( *cp && (unsigned char)(*cp) <= SPACE ) cp++; |
1773 |
if (num < 0 || num > 255 ) { // not in range |
1774 |
rejects++; |
1775 |
strings++; |
1776 |
goto get_more; |
1777 |
} |
1778 |
if (num >= 27 && num <= 31 ) goto get_more; |
1779 |
if (!strcmp(cp, characters[num] ) ) { |
1780 |
strings++; |
1781 |
goto get_more; |
1782 |
} |
1783 |
len = strlen(cp ); |
1784 |
if (characters[num] == default_chars[num] ) |
1785 |
p_new = kmalloc(sizeof (char) * len+1, GFP_KERNEL ); |
1786 |
else if ( strlen(characters[num] ) >= len ) |
1787 |
p_new = characters[num]; |
1788 |
else { |
1789 |
kfree(characters[num] ); |
1790 |
characters[num] = default_chars[num]; |
1791 |
p_new = kmalloc(sizeof (char) * len+1, GFP_KERNEL ); |
1792 |
} |
1793 |
if (!p_new ) return -ENOMEM; |
1794 |
strcpy ( p_new, cp ); |
1795 |
characters[num] = p_new; |
1796 |
updates++; |
1797 |
strings++; |
1798 |
if (i < count ) goto get_more; |
1799 |
chars_stop_timer ( ); |
1800 |
init_timer (&chars_timer ); |
1801 |
chars_timer.function = show_char_results; |
1802 |
chars_timer.expires = jiffies + 5; |
1803 |
start_timer (chars_timer ); |
1804 |
chars_timer_active++; |
1805 |
return count; |
1806 |
} |
1807 |
|
1808 |
// this is the write handler for /proc/speakup/chartab |
1809 |
static int chartab_write_proc(struct file *file, const char *buffer, |
1810 |
u_long count, void *data) |
1811 |
{ |
1812 |
#define max_desc_len 72 |
1813 |
static int cnt = 0, state = 0; |
1814 |
static char desc[max_desc_len + 1]; |
1815 |
static u_long jiff_last = 0; |
1816 |
short i = 0, num; |
1817 |
char ch, *cp; |
1818 |
int value=0; |
1819 |
// reset certain vars if enough time has elapsed since last called |
1820 |
if (jiffies - jiff_last > 10 ) { |
1821 |
cnt = state = strings = rejects = updates = 0; |
1822 |
} |
1823 |
jiff_last = jiffies; |
1824 |
get_more: |
1825 |
desc[cnt] = '\0'; |
1826 |
state = 0; |
1827 |
for (; i < count && state < 2; i++ ) { |
1828 |
get_user (ch, buffer + i ); |
1829 |
if ( ch == '\n' ) { |
1830 |
desc[cnt] = '\0'; |
1831 |
state = 2; |
1832 |
} else if (cnt < max_desc_len ) |
1833 |
desc[cnt++] = ch; |
1834 |
} |
1835 |
if (state < 2 ) return count; |
1836 |
cp = desc; |
1837 |
while ( *cp && (unsigned char)(*cp) <= SPACE ) cp++; |
1838 |
if ((!cnt ) || strchr ("dDrR", *cp ) ) { |
1839 |
reset_default_chartab ( ); |
1840 |
pr_info( "character descriptions reset to defaults\n" ); |
1841 |
cnt = 0; |
1842 |
return count; |
1843 |
} |
1844 |
cnt = 0; |
1845 |
if (*cp == '#' ) goto get_more; |
1846 |
num = -1; |
1847 |
cp = speakup_s2i(cp, &num ); |
1848 |
while ( *cp && (unsigned char)(*cp) <= SPACE ) cp++; |
1849 |
if (num < 0 || num > 255 ) { // not in range |
1850 |
rejects++; |
1851 |
strings++; |
1852 |
goto get_more; |
1853 |
} |
1854 |
/* if (num >= 27 && num <= 31 ) goto get_more; */ |
1855 |
|
1856 |
value = chartab_get_value (cp); |
1857 |
if (!value) { // not in range |
1858 |
rejects++; |
1859 |
strings++; |
1860 |
goto get_more; |
1861 |
} |
1862 |
|
1863 |
if (value==spk_chartab[num]) { |
1864 |
strings++; |
1865 |
goto get_more; |
1866 |
} |
1867 |
|
1868 |
spk_chartab[num] = value; |
1869 |
updates++; |
1870 |
strings++; |
1871 |
if (i < count ) goto get_more; |
1872 |
chars_stop_timer ( ); |
1873 |
init_timer (&chars_timer ); |
1874 |
chars_timer.function = show_char_results; |
1875 |
chars_timer.expires = jiffies + 5; |
1876 |
start_timer (chars_timer ); |
1877 |
chars_timer_active++; |
1878 |
return count; |
1879 |
} |
1880 |
|
1881 |
static int bits_read_proc(char *page, char **start, off_t off, int count, |
1882 |
int *eof, void *data) |
1883 |
{ |
1884 |
int i; |
1885 |
struct st_var_header *p_header = data; |
1886 |
struct st_proc_var *var = p_header->data; |
1887 |
const struct st_bits_data *pb = &punc_info[var->value]; |
1888 |
short mask = pb->mask; |
1889 |
char *cp = page; |
1890 |
*start = 0; |
1891 |
*eof = 1; |
1892 |
for ( i = 33; i < 128; i++ ) { |
1893 |
if ( !(spk_chartab[i]&mask ) ) continue; |
1894 |
*cp++ = (char )i; |
1895 |
} |
1896 |
*cp++ = '\n'; |
1897 |
return cp-page; |
1898 |
} |
1899 |
|
1900 |
/* set_mask_bits sets or clears the punc/delim/repeat bits, |
1901 |
* if input is null uses the defaults. |
1902 |
* values for how: 0 clears bits of chars supplied, |
1903 |
* 1 clears allk, 2 sets bits for chars */ |
1904 |
|
1905 |
static int set_mask_bits(const char *input, const int which, const int how) |
1906 |
{ |
1907 |
u_char *cp; |
1908 |
short mask = punc_info[which].mask; |
1909 |
if ( how&1 ) { |
1910 |
for ( cp = (u_char * )punc_info[3].value; *cp; cp++ ) |
1911 |
spk_chartab[*cp] &= ~mask; |
1912 |
} |
1913 |
cp = (u_char * )input; |
1914 |
if ( cp == 0 ) cp = punc_info[which].value; |
1915 |
else { |
1916 |
for ( ; *cp; cp++ ) { |
1917 |
if ( *cp < SPACE ) break; |
1918 |
if ( mask < PUNC ) { |
1919 |
if ( !(spk_chartab[*cp]&PUNC) ) break; |
1920 |
} else if ( (spk_chartab[*cp]&B_NUM) ) break; |
1921 |
} |
1922 |
if ( *cp ) return -EINVAL; |
1923 |
cp = (u_char * )input; |
1924 |
} |
1925 |
if ( how&2 ) { |
1926 |
for ( ; *cp; cp++ ) |
1927 |
if ( *cp > SPACE ) spk_chartab[*cp] |= mask; |
1928 |
} else { |
1929 |
for ( ; *cp; cp++ ) |
1930 |
if ( *cp > SPACE ) spk_chartab[*cp] &= ~mask; |
1931 |
} |
1932 |
return 0; |
1933 |
} |
1934 |
|
1935 |
static const struct st_bits_data *pb_edit = NULL; |
1936 |
|
1937 |
static int edit_bits (struct vc_data *vc, u_char type, u_char ch, u_short key ) |
1938 |
{ |
1939 |
short mask = pb_edit->mask, ch_type = spk_chartab[ch]; |
1940 |
if ( type != KT_LATIN || (ch_type&B_NUM ) || ch < SPACE ) return -1; |
1941 |
if ( ch == SPACE ) { |
1942 |
synth_write_msg( "edit done" ); |
1943 |
special_handler = NULL; |
1944 |
return 1; |
1945 |
} |
1946 |
if ( mask < PUNC && !(ch_type&PUNC) ) return -1; |
1947 |
spk_chartab[ch] ^= mask; |
1948 |
speak_char( ch ); |
1949 |
synth_write_msg( (spk_chartab[ch]&mask ) ? " on" : " off" ); |
1950 |
return 1; |
1951 |
} |
1952 |
|
1953 |
static int bits_write_proc(struct file *file, const char *buffer, u_long count, |
1954 |
void *data) |
1955 |
{ |
1956 |
struct st_var_header *p_header = data; |
1957 |
struct st_proc_var *var = p_header->data; |
1958 |
int ret = count; |
1959 |
char punc_buf[100]; |
1960 |
if (count < 1 || count > 99 ) |
1961 |
return -EINVAL; |
1962 |
if (copy_from_user (punc_buf, buffer, count ) ) |
1963 |
return -EFAULT; |
1964 |
if (punc_buf[count - 1] == '\n' ) |
1965 |
count--; |
1966 |
punc_buf[count] = '\0'; |
1967 |
if ( *punc_buf == 'd' || *punc_buf == 'r' ) |
1968 |
count = set_mask_bits( 0, var->value, 3 ); |
1969 |
else |
1970 |
count = set_mask_bits( punc_buf, var->value, 3 ); |
1971 |
if ( count < 0 ) return count; |
1972 |
return ret; |
1973 |
} |
1974 |
|
1975 |
// this is the read handler for /proc/speakup/synth |
1976 |
static int synth_read_proc(char *page, char **start, off_t off, int count, |
1977 |
int *eof, void *data) |
1978 |
{ |
1979 |
int len; |
1980 |
if ( synth == NULL ) strcpy( synth_name, "none" ); |
1981 |
else strcpy( synth_name, synth->name ); |
1982 |
len = sprintf (page, "%s\n", synth_name ); |
1983 |
*start = 0; |
1984 |
*eof = 1; |
1985 |
return len; |
1986 |
} |
1987 |
|
1988 |
// this is the write handler for /proc/speakup/synth |
1989 |
static int synth_write_proc(struct file *file, const char *buffer, |
1990 |
u_long count, void *data) |
1991 |
{ |
1992 |
int ret = count; |
1993 |
char new_synth_name[10]; |
1994 |
const char *old_name = ( synth != NULL ) ? synth->name : "none"; |
1995 |
if (count < 2 || count > 9 ) |
1996 |
return -EINVAL; |
1997 |
if (copy_from_user (new_synth_name, buffer, count ) ) |
1998 |
return -EFAULT; |
1999 |
if (new_synth_name[count - 1] == '\n' ) |
2000 |
count--; |
2001 |
new_synth_name[count] = '\0'; |
2002 |
strlwr (new_synth_name ); |
2003 |
if (!strcmp (new_synth_name, old_name ) ) { |
2004 |
pr_warn ( "%s already in use\n", new_synth_name ); |
2005 |
return ret; |
2006 |
} |
2007 |
if ( synth_init( new_synth_name ) == 0 ) return ret; |
2008 |
pr_warn( "failed to init synth %s\n", new_synth_name ); |
2009 |
return -ENODEV; |
2010 |
} |
2011 |
|
2012 |
struct st_proc_var spk_proc_vars[] = { |
2013 |
{ VERSION, version_read_proc, 0, 0 }, |
2014 |
{ SILENT, 0, silent_write_proc, 0 }, |
2015 |
{ CHARS, chars_read_proc, chars_write_proc, 0 }, |
2016 |
{ SYNTH, synth_read_proc, synth_write_proc, 0 }, |
2017 |
{ KEYMAP, keys_read_proc, keys_write_proc, 0 }, |
2018 |
{ PUNC_SOME, bits_read_proc, bits_write_proc, 1 }, |
2019 |
{ PUNC_MOST, bits_read_proc, bits_write_proc, 2 }, |
2020 |
{ PUNC_ALL, bits_read_proc, 0, 3 }, |
2021 |
{ DELIM, bits_read_proc, bits_write_proc, 4 }, |
2022 |
{ REPEATS, bits_read_proc, bits_write_proc, 5 }, |
2023 |
{ EXNUMBER, bits_read_proc, bits_write_proc, 6 }, |
2024 |
{ CHARTAB, chartab_read_proc, chartab_write_proc, 0 }, |
2025 |
{ -1, 0, 0, 0 } |
2026 |
}; |
2027 |
|
2028 |
#endif // CONFIG_PROC_FS |
2029 |
|
2030 |
void __init speakup_init(struct vc_data *vc) |
2031 |
{ |
2032 |
struct st_spk_t *first_console = |
2033 |
alloc_bootmem(sizeof(struct st_spk_t) + 1); |
2034 |
memset( first_console, 0, sizeof(struct st_spk_t)); |
2035 |
speakup_open(vc, first_console); |
2036 |
} |
2037 |
|
2038 |
void speakup_allocate(struct vc_data *vc) |
2039 |
{ |
2040 |
int vc_num; |
2041 |
|
2042 |
vc_num = vc->vc_num; |
2043 |
if ( speakup_console[vc_num] == NULL ) { |
2044 |
speakup_console[vc_num] = kzalloc(sizeof(struct st_spk_t) + 1, |
2045 |
GFP_KERNEL); |
2046 |
if (speakup_console[vc_num] == NULL) |
2047 |
return; |
2048 |
speakup_date( vc); |
2049 |
} else if ( !spk_parked ) speakup_date( vc); |
2050 |
} |
2051 |
|
2052 |
static u_char is_cursor = 0; |
2053 |
static u_long old_cursor_pos, old_cursor_x, old_cursor_y; |
2054 |
static int cursor_con; |
2055 |
static int cursor_timer_active = 0; |
2056 |
|
2057 |
static void cursor_stop_timer(void) |
2058 |
{ |
2059 |
if (!cursor_timer_active ) return; |
2060 |
stop_timer ( cursor_timer ); |
2061 |
cursor_timer_active = 0; |
2062 |
} |
2063 |
|
2064 |
static void reset_highlight_buffers( struct vc_data * ); |
2065 |
|
2066 |
//extern void kbd_fakekey(unsigned int); |
2067 |
extern struct input_dev *fakekeydev; |
2068 |
|
2069 |
static int read_all_key; |
2070 |
|
2071 |
void reset_index_count(int); |
2072 |
void get_index_count(int *, int *); |
2073 |
//int synth_supports_indexing(void); |
2074 |
static void start_read_all_timer( struct vc_data *vc, int command ); |
2075 |
|
2076 |
enum {RA_NOTHING,RA_NEXT_SENT,RA_PREV_LINE,RA_NEXT_LINE,RA_PREV_SENT,RA_DOWN_ARROW,RA_TIMER,RA_FIND_NEXT_SENT,RA_FIND_PREV_SENT}; |
2077 |
|
2078 |
static void |
2079 |
kbd_fakekey2(struct vc_data *vc,int v,int command) |
2080 |
{ |
2081 |
cursor_stop_timer(); |
2082 |
(*do_cursor)( vc,v,0); |
2083 |
(*do_cursor)( vc,v,1); |
2084 |
start_read_all_timer(vc,command); |
2085 |
} |
2086 |
|
2087 |
static void |
2088 |
read_all_doc( struct vc_data *vc) |
2089 |
{ |
2090 |
if ( synth == NULL || spk_shut_up || (vc->vc_num != fg_console ) ) |
2091 |
return; |
2092 |
if (!synth_supports_indexing()) |
2093 |
return; |
2094 |
if (cursor_track!=read_all_mode) |
2095 |
prev_cursor_track=cursor_track; |
2096 |
cursor_track=read_all_mode; |
2097 |
reset_index_count(0); |
2098 |
if (get_sentence_buf(vc,0)==-1) |
2099 |
kbd_fakekey2(vc,0,RA_DOWN_ARROW); |
2100 |
else { |
2101 |
say_sentence_num(0,0); |
2102 |
synth_insert_next_index(0); |
2103 |
start_read_all_timer(vc,RA_TIMER); |
2104 |
} |
2105 |
} |
2106 |
|
2107 |
static void |
2108 |
stop_read_all( struct vc_data *vc) |
2109 |
{ |
2110 |
cursor_stop_timer( ); |
2111 |
cursor_track=prev_cursor_track; |
2112 |
spk_shut_up &= 0xfe; |
2113 |
do_flush(); |
2114 |
} |
2115 |
|
2116 |
static void |
2117 |
start_read_all_timer( struct vc_data *vc, int command ) |
2118 |
{ |
2119 |
cursor_con = vc->vc_num; |
2120 |
cursor_timer.expires = jiffies + cursor_timeout; |
2121 |
read_all_key=command; |
2122 |
start_timer (cursor_timer ); |
2123 |
cursor_timer_active++; |
2124 |
} |
2125 |
|
2126 |
static void |
2127 |
handle_cursor_read_all( struct vc_data *vc,int command ) |
2128 |
{ |
2129 |
int indcount,sentcount,rv,sn; |
2130 |
|
2131 |
switch (command) |
2132 |
{ |
2133 |
case RA_NEXT_SENT: |
2134 |
// Get Current Sentence |
2135 |
get_index_count(&indcount,&sentcount); |
2136 |
//printk("%d %d ",indcount,sentcount); |
2137 |
reset_index_count(sentcount+1); |
2138 |
if (indcount==1) |
2139 |
{ |
2140 |
if (!say_sentence_num(sentcount+1,0)) |
2141 |
{ |
2142 |
kbd_fakekey2(vc,0,RA_FIND_NEXT_SENT); |
2143 |
return; |
2144 |
} |
2145 |
synth_insert_next_index(0); |
2146 |
} |
2147 |
else |
2148 |
{ |
2149 |
sn=0; |
2150 |
if (!say_sentence_num(sentcount+1,1)) |
2151 |
{ |
2152 |
sn=1; |
2153 |
reset_index_count(sn); |
2154 |
} |
2155 |
else |
2156 |
synth_insert_next_index(0); |
2157 |
if (!say_sentence_num(sn,0)) |
2158 |
{ |
2159 |
kbd_fakekey2(vc,0,RA_FIND_NEXT_SENT); |
2160 |
return; |
2161 |
} |
2162 |
synth_insert_next_index(0); |
2163 |
} |
2164 |
start_read_all_timer(vc,RA_TIMER); |
2165 |
break; |
2166 |
case RA_PREV_SENT: |
2167 |
break; |
2168 |
case RA_NEXT_LINE: |
2169 |
read_all_doc(vc); |
2170 |
break; |
2171 |
case RA_PREV_LINE: |
2172 |
break; |
2173 |
case RA_DOWN_ARROW: |
2174 |
if (get_sentence_buf(vc,0)==-1) |
2175 |
{ |
2176 |
kbd_fakekey2(vc,0,RA_DOWN_ARROW); |
2177 |
} |
2178 |
else |
2179 |
{ |
2180 |
say_sentence_num(0,0); |
2181 |
synth_insert_next_index(0); |
2182 |
start_read_all_timer(vc,RA_TIMER); |
2183 |
} |
2184 |
break; |
2185 |
case RA_FIND_NEXT_SENT: |
2186 |
rv=get_sentence_buf(vc,0); |
2187 |
if (rv==-1) |
2188 |
{ |
2189 |
read_all_doc(vc); |
2190 |
} |
2191 |
if (rv==0) |
2192 |
{ |
2193 |
kbd_fakekey2(vc,0,RA_FIND_NEXT_SENT); |
2194 |
} |
2195 |
else |
2196 |
{ |
2197 |
say_sentence_num(1,0); |
2198 |
synth_insert_next_index(0); |
2199 |
start_read_all_timer(vc,RA_TIMER); |
2200 |
} |
2201 |
break; |
2202 |
case RA_FIND_PREV_SENT: |
2203 |
break; |
2204 |
case RA_TIMER: |
2205 |
get_index_count(&indcount,&sentcount); |
2206 |
if (indcount<2) |
2207 |
{ |
2208 |
kbd_fakekey2(vc,0,RA_DOWN_ARROW); |
2209 |
} |
2210 |
else |
2211 |
{ |
2212 |
start_read_all_timer(vc,RA_TIMER); |
2213 |
} |
2214 |
break; |
2215 |
} |
2216 |
} |
2217 |
|
2218 |
static void handle_cursor(struct vc_data *vc, u_char value, char up_flag) |
2219 |
{ |
2220 |
if (cursor_track == read_all_mode) |
2221 |
{ |
2222 |
spk_parked &= 0xfe; |
2223 |
if ( synth == NULL || up_flag || spk_shut_up ) |
2224 |
return; |
2225 |
cursor_stop_timer(); |
2226 |
spk_shut_up &= 0xfe; |
2227 |
do_flush(); |
2228 |
start_read_all_timer(vc,value+1); |
2229 |
return; |
2230 |
} |
2231 |
(*do_cursor)(vc, value, up_flag); |
2232 |
spk_parked &= 0xfe; |
2233 |
if ( synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off ) |
2234 |
return; |
2235 |
spk_shut_up &= 0xfe; |
2236 |
if ( no_intr ) do_flush( ); |
2237 |
/* the key press flushes if !no_inter but we want to flush on cursor |
2238 |
* moves regardless of no_inter state */ |
2239 |
is_cursor = value+1; |
2240 |
old_cursor_pos = vc->vc_pos; |
2241 |
old_cursor_x = vc->vc_x; |
2242 |
old_cursor_y = vc->vc_y; |
2243 |
speakup_console[vc->vc_num]->ht.cy=vc->vc_y; |
2244 |
cursor_con = vc->vc_num; |
2245 |
cursor_stop_timer( ); |
2246 |
cursor_timer.expires = jiffies + cursor_timeout; |
2247 |
if ( cursor_track == CT_Highlight) |
2248 |
reset_highlight_buffers( vc ); |
2249 |
read_all_key=value+1; |
2250 |
start_timer (cursor_timer ); |
2251 |
cursor_timer_active++; |
2252 |
} |
2253 |
|
2254 |
static void |
2255 |
update_color_buffer( struct vc_data *vc , const char *ic , int len ) |
2256 |
{ |
2257 |
int i,bi,hi; |
2258 |
int vc_num=vc->vc_num; |
2259 |
|
2260 |
bi = ( (vc->vc_attr & 0x70) >> 4 ) ; |
2261 |
hi=speakup_console[vc_num]->ht.highsize[bi]; |
2262 |
|
2263 |
i=0; |
2264 |
if (speakup_console[vc_num]->ht.highsize[bi]==0) |
2265 |
{ |
2266 |
speakup_console[vc_num]->ht.rpos[bi]=vc->vc_pos; |
2267 |
speakup_console[vc_num]->ht.rx[bi]=vc->vc_x; |
2268 |
speakup_console[vc_num]->ht.ry[bi]=vc->vc_y; |
2269 |
} |
2270 |
while (( hi<COLOR_BUFFER_SIZE ) && ( i < len )) |
2271 |
{ |
2272 |
if (( ic[i]>32 ) && ( ic[i]<127 )) |
2273 |
{ |
2274 |
speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i]; |
2275 |
hi++; |
2276 |
} |
2277 |
else if (( ic[i] == 32 ) && ( hi != 0 )) |
2278 |
{ |
2279 |
if (speakup_console[vc_num]->ht.highbuf[bi][hi-1]!=32) |
2280 |
{ |
2281 |
speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i]; |
2282 |
hi++; |
2283 |
} |
2284 |
} |
2285 |
i++; |
2286 |
} |
2287 |
speakup_console[vc_num]->ht.highsize[bi]=hi; |
2288 |
} |
2289 |
|
2290 |
static void |
2291 |
reset_highlight_buffers( struct vc_data *vc ) |
2292 |
{ |
2293 |
int i; |
2294 |
int vc_num=vc->vc_num; |
2295 |
for ( i=0 ; i<8 ; i++ ) |
2296 |
speakup_console[vc_num]->ht.highsize[i]=0; |
2297 |
} |
2298 |
|
2299 |
static int |
2300 |
count_highlight_color(struct vc_data *vc) |
2301 |
{ |
2302 |
int i,bg; |
2303 |
int cc; |
2304 |
int vc_num=vc->vc_num; |
2305 |
u16 ch; |
2306 |
u16 *start = (u16 *) vc->vc_origin; |
2307 |
|
2308 |
for ( i=0 ; i<8 ; i++ ) |
2309 |
speakup_console[vc_num]->ht.bgcount[i]=0; |
2310 |
|
2311 |
for ( i=0 ; i<vc->vc_rows; i++ ) { |
2312 |
u16 *end = start + vc->vc_cols*2; |
2313 |
u16 *ptr; |
2314 |
for ( ptr=start ; ptr<end ; ptr++) { |
2315 |
ch = get_attributes( ptr ); |
2316 |
bg = ( ch & 0x70 ) >> 4; |
2317 |
speakup_console[vc_num]->ht.bgcount[bg]++; |
2318 |
} |
2319 |
start += vc->vc_size_row; |
2320 |
} |
2321 |
|
2322 |
cc=0; |
2323 |
for ( i=0 ; i<8 ; i++ ) |
2324 |
if (speakup_console[vc_num]->ht.bgcount[i]>0) |
2325 |
cc++; |
2326 |
return cc; |
2327 |
} |
2328 |
|
2329 |
static int |
2330 |
get_highlight_color( struct vc_data *vc ) |
2331 |
{ |
2332 |
int i,j; |
2333 |
unsigned int cptr[8],tmp; |
2334 |
int vc_num=vc->vc_num; |
2335 |
|
2336 |
for ( i=0 ; i<8 ; i++ ) |
2337 |
cptr[i]=i; |
2338 |
|
2339 |
for ( i=0 ; i<7 ; i++ ) |
2340 |
for ( j=i+1 ; j<8 ; j++ ) |
2341 |
if ( speakup_console[vc_num]->ht.bgcount[cptr[i]] > speakup_console[vc_num]->ht.bgcount[cptr[j]]) { |
2342 |
tmp=cptr[i]; |
2343 |
cptr[i]=cptr[j]; |
2344 |
cptr[j]=tmp; |
2345 |
} |
2346 |
|
2347 |
for ( i=0; i<8; i++ ) |
2348 |
if ( speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0) |
2349 |
if ( speakup_console[vc_num]->ht.highsize[cptr[i]] > 0) |
2350 |
{ |
2351 |
return cptr[i]; |
2352 |
} |
2353 |
return -1; |
2354 |
} |
2355 |
|
2356 |
static int |
2357 |
speak_highlight( struct vc_data *vc ) |
2358 |
{ |
2359 |
int hc,d; |
2360 |
int vc_num=vc->vc_num; |
2361 |
if (count_highlight_color( vc )==1) |
2362 |
return 0; |
2363 |
hc=get_highlight_color( vc ); |
2364 |
if ( hc != -1 ) |
2365 |
{ |
2366 |
d=vc->vc_y-speakup_console[vc_num]->ht.cy; |
2367 |
if ((d==1)||(d==-1)) |
2368 |
{ |
2369 |
if (speakup_console[vc_num]->ht.ry[hc]!=vc->vc_y) |
2370 |
return 0; |
2371 |
} |
2372 |
spk_parked |= 0x01; |
2373 |
do_flush(); |
2374 |
spkup_write (speakup_console[vc_num]->ht.highbuf[hc] , speakup_console[vc_num]->ht.highsize[hc] ); |
2375 |
spk_pos=spk_cp=speakup_console[vc_num]->ht.rpos[hc]; |
2376 |
spk_x=spk_cx=speakup_console[vc_num]->ht.rx[hc]; |
2377 |
spk_y=spk_cy=speakup_console[vc_num]->ht.ry[hc]; |
2378 |
return 1; |
2379 |
} |
2380 |
return 0; |
2381 |
} |
2382 |
|
2383 |
static void |
2384 |
cursor_done (u_long data ) |
2385 |
{ |
2386 |
struct vc_data *vc = vc_cons[cursor_con].d; |
2387 |
cursor_stop_timer( ); |
2388 |
if (cursor_con != fg_console ) { |
2389 |
is_cursor = 0; |
2390 |
return; |
2391 |
} |
2392 |
speakup_date (vc ); |
2393 |
if ( win_enabled ) { |
2394 |
if ( vc->vc_x >= win_left && vc->vc_x <= win_right && |
2395 |
vc->vc_y >= win_top && vc->vc_y <= win_bottom ) { |
2396 |
spk_keydown = is_cursor = 0; |
2397 |
return; |
2398 |
} |
2399 |
} |
2400 |
if ( cursor_track == read_all_mode ) { |
2401 |
handle_cursor_read_all(vc,read_all_key); |
2402 |
return; |
2403 |
} |
2404 |
if ( cursor_track == CT_Highlight) { |
2405 |
if ( speak_highlight( vc )) { |
2406 |
spk_keydown = is_cursor = 0; |
2407 |
return; |
2408 |
} |
2409 |
} |
2410 |
if ( cursor_track == CT_Window) { |
2411 |
speakup_win_say (vc); |
2412 |
} else if ( is_cursor == 1 || is_cursor == 4 ) |
2413 |
say_line_from_to (vc, 0, vc->vc_cols, 0 ); |
2414 |
else |
2415 |
say_char ( vc ); |
2416 |
spk_keydown = is_cursor = 0; |
2417 |
} |
2418 |
|
2419 |
/* These functions are the interface to speakup from the actual kernel code. */ |
2420 |
|
2421 |
void |
2422 |
speakup_bs (struct vc_data *vc ) |
2423 |
{ |
2424 |
if (!spk_parked ) |
2425 |
speakup_date (vc ); |
2426 |
if ( spk_shut_up || synth == NULL ) return; |
2427 |
if ( vc->vc_num == fg_console && spk_keydown ) { |
2428 |
spk_keydown = 0; |
2429 |
if (!is_cursor ) say_char (vc ); |
2430 |
} |
2431 |
} |
2432 |
|
2433 |
void |
2434 |
speakup_con_write (struct vc_data *vc, const char *str, int len ) |
2435 |
{ |
2436 |
if (spk_shut_up || (vc->vc_num != fg_console ) ) |
2437 |
return; |
2438 |
if (bell_pos && spk_keydown && (vc->vc_x == bell_pos - 1 ) ) |
2439 |
bleep(3 ); |
2440 |
if (synth == NULL) return; |
2441 |
if ((is_cursor)||(cursor_track == read_all_mode )) { |
2442 |
if (cursor_track == CT_Highlight ) |
2443 |
update_color_buffer( vc, str, len); |
2444 |
return; |
2445 |
} |
2446 |
if ( win_enabled ) { |
2447 |
if ( vc->vc_x >= win_left && vc->vc_x <= win_right && |
2448 |
vc->vc_y >= win_top && vc->vc_y <= win_bottom ) return; |
2449 |
} |
2450 |
|
2451 |
spkup_write (str, len ); |
2452 |
} |
2453 |
|
2454 |
void |
2455 |
speakup_con_update (struct vc_data *vc ) |
2456 |
{ |
2457 |
if ( speakup_console[vc->vc_num] == NULL || spk_parked ) |
2458 |
return; |
2459 |
speakup_date (vc ); |
2460 |
} |
2461 |
|
2462 |
static void handle_spec(struct vc_data *vc, u_char value, char up_flag) |
2463 |
{ |
2464 |
int on_off = 2; |
2465 |
char *label; |
2466 |
static const char *lock_status[] = { " off", " on", "" }; |
2467 |
(*do_spec)(vc, value, up_flag); |
2468 |
if ( synth == NULL || up_flag || spk_killed ) return; |
2469 |
spk_shut_up &= 0xfe; |
2470 |
if ( no_intr ) do_flush( ); |
2471 |
switch (value ) { |
2472 |
case KVAL( K_CAPS ): |
2473 |
label = "caps lock"; |
2474 |
on_off = (vc_kbd_led(kbd , VC_CAPSLOCK ) ); |
2475 |
break; |
2476 |
case KVAL( K_NUM ): |
2477 |
label = "num lock"; |
2478 |
on_off = (vc_kbd_led(kbd , VC_NUMLOCK ) ); |
2479 |
break; |
2480 |
case KVAL( K_HOLD ): |
2481 |
label = "scroll lock"; |
2482 |
on_off = (vc_kbd_led(kbd , VC_SCROLLOCK ) ); |
2483 |
break; |
2484 |
default: |
2485 |
spk_parked &= 0xfe; |
2486 |
return; |
2487 |
} |
2488 |
synth_write_string ( label ); |
2489 |
synth_write_msg ( lock_status[on_off] ); |
2490 |
} |
2491 |
|
2492 |
static int |
2493 |
inc_dec_var( u_char value ) |
2494 |
{ |
2495 |
struct st_var_header *p_header; |
2496 |
struct st_num_var *var_data; |
2497 |
char num_buf[32]; |
2498 |
char *cp = num_buf, *pn; |
2499 |
int var_id = (int)value - VAR_START; |
2500 |
int how = (var_id&1) ? E_INC : E_DEC; |
2501 |
var_id = var_id/2+FIRST_SET_VAR; |
2502 |
p_header = get_var_header( var_id ); |
2503 |
if ( p_header == NULL ) return -1; |
2504 |
if ( p_header->var_type != VAR_NUM ) return -1; |
2505 |
var_data = p_header->data; |
2506 |
if ( set_num_var( 1, p_header, how ) != 0 ) |
2507 |
return -1; |
2508 |
if ( !spk_close_press ) { |
2509 |
for ( pn = p_header->name; *pn; pn++ ) { |
2510 |
if ( *pn == '_' ) *cp = SPACE; |
2511 |
else *cp++ = *pn; |
2512 |
} |
2513 |
} |
2514 |
sprintf( cp, " %d ", (int)var_data->value ); |
2515 |
synth_write_string( num_buf ); |
2516 |
return 0; |
2517 |
} |
2518 |
|
2519 |
static void |
2520 |
speakup_win_set (struct vc_data *vc ) |
2521 |
{ |
2522 |
char info[40]; |
2523 |
if ( win_start > 1 ) { |
2524 |
synth_write_msg( "window already set, clear then reset" ); |
2525 |
return; |
2526 |
} |
2527 |
if ( spk_x < win_left || spk_y < win_top ) { |
2528 |
synth_write_msg( "error end before start" ); |
2529 |
return; |
2530 |
} |
2531 |
if ( win_start && spk_x == win_left && spk_y == win_top ) { |
2532 |
win_left = 0; |
2533 |
win_right = vc->vc_cols-1; |
2534 |
win_bottom = spk_y; |
2535 |
sprintf( info, "window is line %d", (int)win_top+1 ); |
2536 |
} else { |
2537 |
if ( !win_start ) { |
2538 |
win_top = spk_y; |
2539 |
win_left = spk_x; |
2540 |
} else { |
2541 |
win_bottom = spk_y; |
2542 |
win_right = spk_x; |
2543 |
} |
2544 |
sprintf( info, "%s at line %d, column %d", |
2545 |
(win_start) ? "end" : "start", |
2546 |
(int)spk_y+1, (int)spk_x+1 ); |
2547 |
} |
2548 |
synth_write_msg( info ); |
2549 |
win_start++; |
2550 |
} |
2551 |
|
2552 |
static void |
2553 |
speakup_win_clear (struct vc_data *vc ) |
2554 |
{ |
2555 |
win_top = win_bottom = 0; |
2556 |
win_left = win_right = 0; |
2557 |
win_start = 0; |
2558 |
synth_write_msg( "window cleared" ); |
2559 |
} |
2560 |
|
2561 |
static void |
2562 |
speakup_win_enable (struct vc_data *vc ) |
2563 |
{ |
2564 |
if ( win_start < 2 ) { |
2565 |
synth_write_msg( "no window" ); |
2566 |
return; |
2567 |
} |
2568 |
win_enabled ^= 1; |
2569 |
if ( win_enabled ) synth_write_msg( "window silenced" ); |
2570 |
else synth_write_msg( "window silence disabled" ); |
2571 |
} |
2572 |
|
2573 |
static void |
2574 |
speakup_bits (struct vc_data *vc ) |
2575 |
{ |
2576 |
int val = this_speakup_key - ( FIRST_EDIT_BITS - 1 ); |
2577 |
if ( special_handler != NULL || val < 1 || val > 6 ) { |
2578 |
synth_write_msg( "error" ); |
2579 |
return; |
2580 |
} |
2581 |
pb_edit = &punc_info[val]; |
2582 |
sprintf( buf, "edit %s, press space when done", pb_edit->name ); |
2583 |
synth_write_msg( buf ); |
2584 |
special_handler = edit_bits; |
2585 |
} |
2586 |
|
2587 |
static int handle_goto (struct vc_data *vc, u_char type, u_char ch, u_short key ) |
2588 |
{ |
2589 |
static u_char *goto_buf = "\0\0\0\0\0\0"; |
2590 |
static int num = 0; |
2591 |
short maxlen, go_pos; |
2592 |
char *cp; |
2593 |
if ( type == KT_SPKUP && ch == SPEAKUP_GOTO ) goto do_goto; |
2594 |
if ( type == KT_LATIN && ch == '\n' ) goto do_goto; |
2595 |
if ( type != 0 ) goto oops; |
2596 |
if (ch == 8 ) { |
2597 |
if ( num == 0 ) return -1; |
2598 |
ch = goto_buf[--num]; |
2599 |
goto_buf[num] = '\0'; |
2600 |
spkup_write( &ch, 1 ); |
2601 |
return 1; |
2602 |
} |
2603 |
if ( ch < '+' || ch > 'y' ) goto oops; |
2604 |
goto_buf[num++] = ch; |
2605 |
goto_buf[num] = '\0'; |
2606 |
spkup_write( &ch, 1 ); |
2607 |
maxlen = ( *goto_buf >= '0' ) ? 3 : 4; |
2608 |
if ((ch == '+' || ch == '-' ) && num == 1 ) return 1; |
2609 |
if (ch >= '0' && ch <= '9' && num < maxlen ) return 1; |
2610 |
if ( num < maxlen-1 || num > maxlen ) goto oops; |
2611 |
if ( ch < 'x' || ch > 'y' ) { |
2612 |
oops: |
2613 |
if (!spk_killed ) |
2614 |
synth_write_msg (" goto canceled" ); |
2615 |
goto_buf[num = 0] = '\0'; |
2616 |
special_handler = NULL; |
2617 |
return 1; |
2618 |
} |
2619 |
cp = speakup_s2i (goto_buf, &go_pos ); |
2620 |
goto_pos = (u_long)go_pos; |
2621 |
if (*cp == 'x' ) { |
2622 |
if (*goto_buf < '0' ) goto_pos += spk_x; |
2623 |
else goto_pos--; |
2624 |
if (goto_pos < 0 ) goto_pos = 0; |
2625 |
if (goto_pos >= vc->vc_cols ) |
2626 |
goto_pos = vc->vc_cols-1; |
2627 |
goto_x = 1; |
2628 |
} else { |
2629 |
if (*goto_buf < '0' ) goto_pos += spk_y; |
2630 |
else goto_pos--; |
2631 |
if (goto_pos < 0 ) goto_pos = 0; |
2632 |
if (goto_pos >= vc->vc_rows ) goto_pos = vc->vc_rows-1; |
2633 |
goto_x = 0; |
2634 |
} |
2635 |
goto_buf[num = 0] = '\0'; |
2636 |
do_goto: |
2637 |
special_handler = NULL; |
2638 |
spk_parked |= 0x01; |
2639 |
if ( goto_x ) { |
2640 |
spk_pos -= spk_x * 2; |
2641 |
spk_x = goto_pos; |
2642 |
spk_pos += goto_pos * 2; |
2643 |
say_word( vc ); |
2644 |
} else { |
2645 |
spk_y = goto_pos; |
2646 |
spk_pos = vc->vc_origin + ( goto_pos * vc->vc_size_row ); |
2647 |
say_line( vc ); |
2648 |
} |
2649 |
return 1; |
2650 |
} |
2651 |
|
2652 |
static void |
2653 |
speakup_goto (struct vc_data *vc ) |
2654 |
{ |
2655 |
if ( special_handler != NULL ) { |
2656 |
synth_write_msg( "error" ); |
2657 |
return; |
2658 |
} |
2659 |
synth_write_msg( "go to?" ); |
2660 |
special_handler = handle_goto; |
2661 |
return; |
2662 |
} |
2663 |
|
2664 |
static void |
2665 |
load_help ( struct work_struct *dummy ) |
2666 |
{ |
2667 |
request_module( "speakup_keyhelp" ); |
2668 |
if ( help_handler ) { |
2669 |
(*help_handler)(0, KT_SPKUP, SPEAKUP_HELP, 0 ); |
2670 |
} else synth_write_string( "help module not found" ); |
2671 |
} |
2672 |
|
2673 |
static DECLARE_WORK(ld_help, load_help); |
2674 |
#define schedule_help schedule_work |
2675 |
|
2676 |
static void |
2677 |
speakup_help (struct vc_data *vc ) |
2678 |
{ |
2679 |
if ( help_handler == NULL ) { |
2680 |
/* we can't call request_module from this context so schedule it*/ |
2681 |
/* **** note kernel hangs and my wrath will be on you */ |
2682 |
schedule_help (&ld_help); |
2683 |
return; |
2684 |
} |
2685 |
(*help_handler)(vc, KT_SPKUP, SPEAKUP_HELP, 0 ); |
2686 |
} |
2687 |
|
2688 |
static void |
2689 |
do_nothing (struct vc_data *vc ) |
2690 |
{ |
2691 |
return; /* flush done in do_spkup */ |
2692 |
} |
2693 |
static u_char key_speakup = 0, spk_key_locked = 0; |
2694 |
|
2695 |
static void |
2696 |
speakup_lock (struct vc_data *vc ) |
2697 |
{ |
2698 |
if ( !spk_key_locked ) |
2699 |
spk_key_locked = key_speakup = 16; |
2700 |
else spk_key_locked = key_speakup = 0; |
2701 |
} |
2702 |
|
2703 |
typedef void (*spkup_hand )(struct vc_data * ); |
2704 |
spkup_hand spkup_handler[] = { /* must be ordered same as defines in speakup.h */ |
2705 |
do_nothing, speakup_goto, speech_kill, speakup_shut_up, |
2706 |
speakup_cut, speakup_paste, say_first_char, say_last_char, |
2707 |
say_char, say_prev_char, say_next_char, |
2708 |
say_word, say_prev_word, say_next_word, |
2709 |
say_line, say_prev_line, say_next_line, |
2710 |
top_edge, bottom_edge, left_edge, right_edge, |
2711 |
spell_word, spell_word, say_screen, |
2712 |
say_position, say_attributes, |
2713 |
speakup_off, speakup_parked, say_line, // this is for indent |
2714 |
say_from_top, say_to_bottom, |
2715 |
say_from_left, say_to_right, |
2716 |
say_char_num, speakup_bits, speakup_bits, say_phonetic_char, |
2717 |
speakup_bits, speakup_bits, speakup_bits, |
2718 |
speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say, |
2719 |
speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL |
2720 |
}; |
2721 |
|
2722 |
static void do_spkup( struct vc_data *vc,u_char value ) |
2723 |
{ |
2724 |
if (spk_killed && value != SPEECH_KILL ) return; |
2725 |
spk_keydown = 0; |
2726 |
spk_lastkey = 0; |
2727 |
spk_shut_up &= 0xfe; |
2728 |
this_speakup_key = value; |
2729 |
if (value < SPKUP_MAX_FUNC && spkup_handler[value] ) { |
2730 |
do_flush( ); |
2731 |
(*spkup_handler[value] )(vc ); |
2732 |
} else { |
2733 |
if ( inc_dec_var( value ) < 0 ) |
2734 |
bleep( 9 ); |
2735 |
} |
2736 |
} |
2737 |
|
2738 |
static const char *pad_chars = "0123456789+-*/\015,.?()"; |
2739 |
|
2740 |
int |
2741 |
speakup_key (struct vc_data *vc, int shift_state, int keycode, u_short keysym, int up_flag) |
2742 |
{ |
2743 |
int kh; |
2744 |
u_char *key_info; |
2745 |
u_char type = KTYP( keysym ), value = KVAL( keysym ), new_key = 0; |
2746 |
u_char shift_info, offset; |
2747 |
tty = vc->vc_tty; |
2748 |
if ( synth == NULL ) return 0; |
2749 |
if ( type >= 0xf0 ) type -= 0xf0; |
2750 |
if ( type == KT_PAD && (vc_kbd_led(kbd , VC_NUMLOCK ) ) ) { |
2751 |
if ( up_flag ) { |
2752 |
spk_keydown = 0; |
2753 |
return 0; |
2754 |
} |
2755 |
value = spk_lastkey = pad_chars[value]; |
2756 |
spk_keydown++; |
2757 |
spk_parked &= 0xfe; |
2758 |
goto no_map; |
2759 |
} |
2760 |
if ( keycode >= MAX_KEY ) goto no_map; |
2761 |
if ( ( key_info = our_keys[keycode] ) == 0 ) goto no_map; |
2762 |
// Check valid read all mode keys |
2763 |
if ( (cursor_track==read_all_mode) && ( !up_flag )) |
2764 |
{ |
2765 |
switch (value) |
2766 |
{ |
2767 |
case KVAL(K_DOWN): |
2768 |
case KVAL(K_UP): |
2769 |
case KVAL(K_LEFT): |
2770 |
case KVAL(K_RIGHT): |
2771 |
case KVAL(K_PGUP): |
2772 |
case KVAL(K_PGDN): |
2773 |
break; |
2774 |
default: |
2775 |
stop_read_all(vc); |
2776 |
break; |
2777 |
} |
2778 |
} |
2779 |
shift_info = ( shift_state&0x0f ) + key_speakup; |
2780 |
offset = shift_table[shift_info]; |
2781 |
if ( offset && ( new_key = key_info[offset] ) ) { |
2782 |
if ( new_key == SPK_KEY ) { |
2783 |
if ( !spk_key_locked ) |
2784 |
key_speakup = ( up_flag ) ? 0 : 16; |
2785 |
if ( up_flag || spk_killed ) return 1; |
2786 |
spk_shut_up &= 0xfe; |
2787 |
do_flush( ); |
2788 |
return 1; |
2789 |
} |
2790 |
if ( up_flag ) return 1; |
2791 |
if ( last_keycode == keycode && last_spk_jiffy+MAX_DELAY > jiffies ) { |
2792 |
spk_close_press = 1; |
2793 |
offset = shift_table[shift_info+32]; |
2794 |
/* double press? */ |
2795 |
if ( offset && key_info[offset] ) |
2796 |
new_key = key_info[offset]; |
2797 |
} |
2798 |
last_keycode = keycode; |
2799 |
last_spk_jiffy = jiffies; |
2800 |
type = KT_SPKUP; |
2801 |
value = new_key; |
2802 |
} |
2803 |
no_map: |
2804 |
if ( type == KT_SPKUP && special_handler == NULL ) { |
2805 |
do_spkup( vc, new_key ); |
2806 |
spk_close_press = 0; |
2807 |
return 1; |
2808 |
} |
2809 |
if ( up_flag || spk_killed || type == KT_SHIFT ) return 0; |
2810 |
spk_shut_up &= 0xfe; |
2811 |
kh=(value==KVAL(K_DOWN))||(value==KVAL(K_UP))||(value==KVAL(K_LEFT))||(value==KVAL(K_RIGHT)); |
2812 |
if ((cursor_track != read_all_mode) || !kh) |
2813 |
if (!no_intr ) do_flush( ); |
2814 |
if ( special_handler ) { |
2815 |
int status; |
2816 |
if ( type == KT_SPEC && value == 1 ) { |
2817 |
value = '\n'; |
2818 |
type = KT_LATIN; |
2819 |
} else if ( type == KT_LETTER ) type = KT_LATIN; |
2820 |
else if ( value == 0x7f ) value = 8; /* make del = backspace */ |
2821 |
status = (*special_handler)(vc, type, value, keycode ); |
2822 |
spk_close_press = 0; |
2823 |
if ( status < 0 ) bleep( 9 ); |
2824 |
return status; |
2825 |
} |
2826 |
last_keycode = 0; |
2827 |
return 0; |
2828 |
} |
2829 |
|
2830 |
#ifdef MODULE |
2831 |
|
2832 |
extern void speakup_remove(void); |
2833 |
extern void speakup_set_addresses ( spk_con_func, spk_con_func, spk_write_func, spk_con_func, spk_key_func); |
2834 |
|
2835 |
static void __exit mod_speakup_exit(void) |
2836 |
{ |
2837 |
int i; |
2838 |
|
2839 |
key_handler[KT_LATIN] = do_latin; |
2840 |
key_handler[KT_SPEC] = do_spec; |
2841 |
key_handler[KT_CUR] = do_cursor; |
2842 |
key_handler[KT_SHIFT] = do_shift; |
2843 |
speakup_set_addresses(NULL, NULL, NULL, NULL, NULL); |
2844 |
synth_release(); |
2845 |
speakup_remove(); |
2846 |
for(i = 0; i < 256; i++) { |
2847 |
if (characters[i] != default_chars[i]) |
2848 |
kfree(characters[i]); |
2849 |
} |
2850 |
for(i = 0; speakup_console[i]; i++) { |
2851 |
kfree(speakup_console[i]); |
2852 |
speakup_console[i] = NULL; |
2853 |
} |
2854 |
} |
2855 |
|
2856 |
static int __init mod_speakup_init( void ) |
2857 |
{ |
2858 |
int i; |
2859 |
struct st_spk_t *first_console = kzalloc(sizeof(struct st_spk_t) + 1, |
2860 |
GFP_KERNEL); |
2861 |
speakup_open( vc_cons[fg_console].d, first_console ); |
2862 |
for ( i = 0; vc_cons[i].d; i++) |
2863 |
speakup_allocate(vc_cons[i].d); |
2864 |
speakup_set_addresses( speakup_allocate, speakup_bs, |
2865 |
speakup_con_write, speakup_con_update, speakup_key ); |
2866 |
speakup_dev_init(); |
2867 |
return 0; |
2868 |
} |
2869 |
|
2870 |
module_init( mod_speakup_init ); |
2871 |
module_exit( mod_speakup_exit ); |
2872 |
|
2873 |
#endif |