Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/accessibility/speakup/main.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0+
2
/* speakup.c
3
* review functions for the speakup screen review package.
4
* originally written by: Kirk Reiser and Andy Berdan.
5
*
6
* extensively modified by David Borowski.
7
*
8
** Copyright (C) 1998 Kirk Reiser.
9
* Copyright (C) 2003 David Borowski.
10
*/
11
12
#include <linux/kernel.h>
13
#include <linux/vt.h>
14
#include <linux/tty.h>
15
#include <linux/mm.h> /* __get_free_page() and friends */
16
#include <linux/vt_kern.h>
17
#include <linux/ctype.h>
18
#include <linux/selection.h>
19
#include <linux/unistd.h>
20
#include <linux/jiffies.h>
21
#include <linux/kthread.h>
22
#include <linux/keyboard.h> /* for KT_SHIFT */
23
#include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
24
#include <linux/input.h>
25
#include <linux/kmod.h>
26
27
/* speakup_*_selection */
28
#include <linux/module.h>
29
#include <linux/sched.h>
30
#include <linux/slab.h>
31
#include <linux/types.h>
32
#include <linux/consolemap.h>
33
34
#include <linux/spinlock.h>
35
#include <linux/notifier.h>
36
37
#include <linux/uaccess.h> /* copy_from|to|user() and others */
38
39
#include "spk_priv.h"
40
#include "speakup.h"
41
42
#define MAX_DELAY msecs_to_jiffies(500)
43
#define MINECHOCHAR SPACE
44
45
MODULE_AUTHOR("Kirk Reiser <[email protected]>");
46
MODULE_AUTHOR("Daniel Drake <[email protected]>");
47
MODULE_DESCRIPTION("Speakup console speech");
48
MODULE_LICENSE("GPL");
49
MODULE_VERSION(SPEAKUP_VERSION);
50
51
char *synth_name;
52
module_param_named(synth, synth_name, charp, 0444);
53
module_param_named(quiet, spk_quiet_boot, bool, 0444);
54
55
MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
56
MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
57
58
special_func spk_special_handler;
59
60
short spk_pitch_shift, synth_flags;
61
static u16 buf[256];
62
int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
63
int spk_no_intr, spk_spell_delay;
64
int spk_key_echo, spk_say_word_ctl;
65
int spk_say_ctrl, spk_bell_pos;
66
short spk_punc_mask;
67
int spk_punc_level, spk_reading_punc;
68
int spk_cur_phonetic;
69
char spk_str_caps_start[MAXVARLEN + 1] = "\0";
70
char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
71
char spk_str_pause[MAXVARLEN + 1] = "\0";
72
bool spk_paused;
73
const struct st_bits_data spk_punc_info[] = {
74
{"none", "", 0},
75
{"some", "/$%&@", SOME},
76
{"most", "$%&#()=+*/@^<>|\\", MOST},
77
{"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
78
{"delimiters", "", B_WDLM},
79
{"repeats", "()", CH_RPT},
80
{"extended numeric", "", B_EXNUM},
81
{"symbols", "", B_SYM},
82
{NULL, NULL}
83
};
84
85
static char mark_cut_flag;
86
#define MAX_KEY 160
87
static u_char *spk_shift_table;
88
u_char *spk_our_keys[MAX_KEY];
89
u_char spk_key_buf[600];
90
const u_char spk_key_defaults[] = {
91
#include "speakupmap.h"
92
};
93
94
/* cursor track modes, must be ordered same as cursor_msgs in enum msg_index_t */
95
enum cursor_track {
96
CT_Off = 0,
97
CT_On,
98
CT_Highlight,
99
CT_Window,
100
CT_Max,
101
read_all_mode = CT_Max,
102
};
103
104
/* Speakup Cursor Track Variables */
105
static enum cursor_track cursor_track = 1, prev_cursor_track = 1;
106
107
static struct tty_struct *tty;
108
109
static void spkup_write(const u16 *in_buf, int count);
110
111
static char *phonetic[] = {
112
"alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
113
"india", "juliett", "keelo", "leema", "mike", "november", "oscar",
114
"papa",
115
"keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
116
"x ray", "yankee", "zulu"
117
};
118
119
/* array of 256 char pointers (one for each character description)
120
* initialized to default_chars and user selectable via
121
* /proc/speakup/characters
122
*/
123
char *spk_characters[256];
124
125
char *spk_default_chars[256] = {
126
/*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
127
/*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
128
/*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
129
/*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
130
"control",
131
/*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
132
"tick",
133
/*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
134
"dot",
135
"slash",
136
/*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
137
"eight", "nine",
138
/*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
139
/*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
140
/*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
141
/*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
142
/*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
143
"caret",
144
"line",
145
/*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
146
/*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
147
/*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
148
/*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
149
/*127*/ "del", "control", "control", "control", "control", "control",
150
"control", "control", "control", "control", "control",
151
/*138*/ "control", "control", "control", "control", "control",
152
"control", "control", "control", "control", "control",
153
"control", "control",
154
/*150*/ "control", "control", "control", "control", "control",
155
"control", "control", "control", "control", "control",
156
/*160*/ "nbsp", "inverted bang",
157
/*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
158
/*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
159
/*172*/ "not", "soft hyphen", "registered", "macron",
160
/*176*/ "degrees", "plus or minus", "super two", "super three",
161
/*180*/ "acute accent", "micro", "pilcrow", "middle dot",
162
/*184*/ "cedilla", "super one", "male ordinal", "double right angle",
163
/*188*/ "one quarter", "one half", "three quarters",
164
"inverted question",
165
/*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
166
"A RING",
167
/*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
168
"E OOMLAUT",
169
/*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
170
"N TILDE",
171
/*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
172
/*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
173
"U CIRCUMFLEX",
174
/*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
175
/*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
176
/*230*/ "ae", "c cidella", "e grave", "e acute",
177
/*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
178
"i circumflex",
179
/*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
180
"o circumflex",
181
/*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
182
"u acute",
183
/* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
184
};
185
186
/* array of 256 u_short (one for each character)
187
* initialized to default_chartab and user selectable via
188
* /sys/module/speakup/parameters/chartab
189
*/
190
u_short spk_chartab[256];
191
192
static u_short default_chartab[256] = {
193
B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
194
B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
195
B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
196
B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
197
WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */
198
PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */
199
NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
200
NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */
201
PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */
202
A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
203
A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
204
A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */
205
PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */
206
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
207
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
208
ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
209
B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
210
B_SYM, /* 135 */
211
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
212
B_CAPSYM, /* 143 */
213
B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
214
B_SYM, /* 151 */
215
B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
216
B_SYM, /* 159 */
217
WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
218
B_SYM, /* 167 */
219
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
220
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
221
B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
222
A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
223
A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
224
A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
225
A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
226
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
227
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
228
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
229
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */
230
};
231
232
struct task_struct *speakup_task;
233
struct bleep spk_unprocessed_sound;
234
static int spk_keydown;
235
static u16 spk_lastkey;
236
static u_char spk_close_press, keymap_flags;
237
static u_char last_keycode, this_speakup_key;
238
static u_long last_spk_jiffy;
239
240
struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
241
242
DEFINE_MUTEX(spk_mutex);
243
244
static int keyboard_notifier_call(struct notifier_block *,
245
unsigned long code, void *param);
246
247
static struct notifier_block keyboard_notifier_block = {
248
.notifier_call = keyboard_notifier_call,
249
};
250
251
static int vt_notifier_call(struct notifier_block *,
252
unsigned long code, void *param);
253
254
static struct notifier_block vt_notifier_block = {
255
.notifier_call = vt_notifier_call,
256
};
257
258
static unsigned char get_attributes(struct vc_data *vc, u16 *pos)
259
{
260
pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true);
261
return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8;
262
}
263
264
static void speakup_date(struct vc_data *vc)
265
{
266
spk_x = spk_cx = vc->state.x;
267
spk_y = spk_cy = vc->state.y;
268
spk_pos = spk_cp = vc->vc_pos;
269
spk_old_attr = spk_attr;
270
spk_attr = get_attributes(vc, (u_short *)spk_pos);
271
}
272
273
static void bleep(u_short val)
274
{
275
static const short vals[] = {
276
350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
277
};
278
short freq;
279
int time = spk_bleep_time;
280
281
freq = vals[val % 12];
282
if (val > 11)
283
freq *= (1 << (val / 12));
284
spk_unprocessed_sound.freq = freq;
285
spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
286
spk_unprocessed_sound.active = 1;
287
/* We can only have 1 active sound at a time. */
288
}
289
290
static void speakup_shut_up(struct vc_data *vc)
291
{
292
if (spk_killed)
293
return;
294
spk_shut_up |= 0x01;
295
spk_parked &= 0xfe;
296
speakup_date(vc);
297
if (synth)
298
spk_do_flush();
299
}
300
301
static void speech_kill(struct vc_data *vc)
302
{
303
char val = synth->is_alive(synth);
304
305
if (val == 0)
306
return;
307
308
/* re-enables synth, if disabled */
309
if (val == 2 || spk_killed) {
310
/* dead */
311
spk_shut_up &= ~0x40;
312
synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
313
} else {
314
synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
315
spk_shut_up |= 0x40;
316
}
317
}
318
319
static void speakup_off(struct vc_data *vc)
320
{
321
if (spk_shut_up & 0x80) {
322
spk_shut_up &= 0x7f;
323
synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
324
} else {
325
spk_shut_up |= 0x80;
326
synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
327
}
328
speakup_date(vc);
329
}
330
331
static void speakup_parked(struct vc_data *vc)
332
{
333
if (spk_parked & 0x80) {
334
spk_parked = 0;
335
synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
336
} else {
337
spk_parked |= 0x80;
338
synth_printf("%s\n", spk_msg_get(MSG_PARKED));
339
}
340
}
341
342
static void speakup_cut(struct vc_data *vc)
343
{
344
static const char err_buf[] = "set selection failed";
345
int ret;
346
347
if (!mark_cut_flag) {
348
mark_cut_flag = 1;
349
spk_xs = (u_short)spk_x;
350
spk_ys = (u_short)spk_y;
351
spk_sel_cons = vc;
352
synth_printf("%s\n", spk_msg_get(MSG_MARK));
353
return;
354
}
355
spk_xe = (u_short)spk_x;
356
spk_ye = (u_short)spk_y;
357
mark_cut_flag = 0;
358
synth_printf("%s\n", spk_msg_get(MSG_CUT));
359
360
ret = speakup_set_selection(tty);
361
362
switch (ret) {
363
case 0:
364
break; /* no error */
365
case -EFAULT:
366
pr_warn("%sEFAULT\n", err_buf);
367
break;
368
case -EINVAL:
369
pr_warn("%sEINVAL\n", err_buf);
370
break;
371
case -ENOMEM:
372
pr_warn("%sENOMEM\n", err_buf);
373
break;
374
}
375
}
376
377
static void speakup_paste(struct vc_data *vc)
378
{
379
if (mark_cut_flag) {
380
mark_cut_flag = 0;
381
synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
382
} else {
383
synth_printf("%s\n", spk_msg_get(MSG_PASTE));
384
speakup_paste_selection(tty);
385
}
386
}
387
388
static void say_attributes(struct vc_data *vc)
389
{
390
int fg = spk_attr & 0x0f;
391
int bg = spk_attr >> 4;
392
393
synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
394
if (bg > 7) {
395
synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
396
bg -= 8;
397
} else {
398
synth_printf(" %s ", spk_msg_get(MSG_ON));
399
}
400
synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
401
}
402
403
/* must be ordered same as edge_msgs in enum msg_index_t */
404
enum edge {
405
edge_none = 0,
406
edge_top,
407
edge_bottom,
408
edge_left,
409
edge_right,
410
edge_quiet
411
};
412
413
static void announce_edge(struct vc_data *vc, enum edge msg_id)
414
{
415
if (spk_bleeps & 1)
416
bleep(spk_y);
417
if ((spk_bleeps & 2) && (msg_id < edge_quiet))
418
synth_printf("%s\n",
419
spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
420
}
421
422
static void speak_char(u16 ch)
423
{
424
char *cp;
425
struct var_t *direct = spk_get_var(DIRECT);
426
427
if (ch >= 0x100 || (direct && direct->u.n.value)) {
428
if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
429
spk_pitch_shift++;
430
synth_printf("%s", spk_str_caps_start);
431
}
432
synth_putwc_s(ch);
433
if (ch < 0x100 && IS_CHAR(ch, B_CAP))
434
synth_printf("%s", spk_str_caps_stop);
435
return;
436
}
437
438
cp = spk_characters[ch];
439
if (!cp) {
440
pr_info("%s: cp == NULL!\n", __func__);
441
return;
442
}
443
if (IS_CHAR(ch, B_CAP)) {
444
spk_pitch_shift++;
445
synth_printf("%s %s %s",
446
spk_str_caps_start, cp, spk_str_caps_stop);
447
} else {
448
if (*cp == '^') {
449
cp++;
450
synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp);
451
} else {
452
synth_printf(" %s ", cp);
453
}
454
}
455
}
456
457
static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
458
{
459
u16 ch = ' ';
460
461
if (vc && pos) {
462
u16 w;
463
u16 c;
464
465
pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true);
466
w = scr_readw(pos);
467
c = w & 0xff;
468
469
if (w & vc->vc_hi_font_mask) {
470
w &= ~vc->vc_hi_font_mask;
471
c |= 0x100;
472
}
473
474
ch = inverse_translate(vc, c, true);
475
*attribs = (w & 0xff00) >> 8;
476
}
477
return ch;
478
}
479
480
static void say_char(struct vc_data *vc)
481
{
482
u16 ch;
483
484
spk_old_attr = spk_attr;
485
ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
486
if (spk_attr != spk_old_attr) {
487
if (spk_attrib_bleep & 1)
488
bleep(spk_y);
489
if (spk_attrib_bleep & 2)
490
say_attributes(vc);
491
}
492
speak_char(ch);
493
}
494
495
static void say_phonetic_char(struct vc_data *vc)
496
{
497
u16 ch;
498
499
spk_old_attr = spk_attr;
500
ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
501
if (ch <= 0x7f && isalpha(ch)) {
502
ch &= 0x1f;
503
synth_printf("%s\n", phonetic[--ch]);
504
} else {
505
if (ch < 0x100 && IS_CHAR(ch, B_NUM))
506
synth_printf("%s ", spk_msg_get(MSG_NUMBER));
507
speak_char(ch);
508
}
509
}
510
511
static void say_prev_char(struct vc_data *vc)
512
{
513
spk_parked |= 0x01;
514
if (spk_x == 0) {
515
announce_edge(vc, edge_left);
516
return;
517
}
518
spk_x--;
519
spk_pos -= 2;
520
say_char(vc);
521
}
522
523
static void say_next_char(struct vc_data *vc)
524
{
525
spk_parked |= 0x01;
526
if (spk_x == vc->vc_cols - 1) {
527
announce_edge(vc, edge_right);
528
return;
529
}
530
spk_x++;
531
spk_pos += 2;
532
say_char(vc);
533
}
534
535
/* get_word - will first check to see if the character under the
536
* reading cursor is a space and if spk_say_word_ctl is true it will
537
* return the word space. If spk_say_word_ctl is not set it will check to
538
* see if there is a word starting on the next position to the right
539
* and return that word if it exists. If it does not exist it will
540
* move left to the beginning of any previous word on the line or the
541
* beginning off the line whichever comes first..
542
*/
543
544
static u_long get_word(struct vc_data *vc)
545
{
546
u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
547
u16 ch;
548
u16 attr_ch;
549
u_char temp;
550
551
spk_old_attr = spk_attr;
552
ch = get_char(vc, (u_short *)tmp_pos, &temp);
553
554
/* decided to take out the sayword if on a space (mis-information */
555
if (spk_say_word_ctl && ch == SPACE) {
556
*buf = '\0';
557
synth_printf("%s\n", spk_msg_get(MSG_SPACE));
558
return 0;
559
} else if (tmpx < vc->vc_cols - 2 &&
560
(ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
561
get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) {
562
tmp_pos += 2;
563
tmpx++;
564
} else {
565
while (tmpx > 0) {
566
ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
567
if ((ch == SPACE || ch == 0 ||
568
(ch < 0x100 && IS_WDLM(ch))) &&
569
get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
570
break;
571
tmp_pos -= 2;
572
tmpx--;
573
}
574
}
575
attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
576
buf[cnt++] = attr_ch;
577
while (tmpx < vc->vc_cols - 1 && cnt < ARRAY_SIZE(buf) - 1) {
578
tmp_pos += 2;
579
tmpx++;
580
ch = get_char(vc, (u_short *)tmp_pos, &temp);
581
if (ch == SPACE || ch == 0 ||
582
(buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
583
ch > SPACE))
584
break;
585
buf[cnt++] = ch;
586
}
587
buf[cnt] = '\0';
588
return cnt;
589
}
590
591
static void say_word(struct vc_data *vc)
592
{
593
u_long cnt = get_word(vc);
594
u_short saved_punc_mask = spk_punc_mask;
595
596
if (cnt == 0)
597
return;
598
spk_punc_mask = PUNC;
599
buf[cnt++] = SPACE;
600
spkup_write(buf, cnt);
601
spk_punc_mask = saved_punc_mask;
602
}
603
604
static void say_prev_word(struct vc_data *vc)
605
{
606
u_char temp;
607
u16 ch;
608
enum edge edge_said = edge_none;
609
u_short last_state = 0, state = 0;
610
611
spk_parked |= 0x01;
612
613
if (spk_x == 0) {
614
if (spk_y == 0) {
615
announce_edge(vc, edge_top);
616
return;
617
}
618
spk_y--;
619
spk_x = vc->vc_cols;
620
edge_said = edge_quiet;
621
}
622
while (1) {
623
if (spk_x == 0) {
624
if (spk_y == 0) {
625
edge_said = edge_top;
626
break;
627
}
628
if (edge_said != edge_quiet)
629
edge_said = edge_left;
630
if (state > 0)
631
break;
632
spk_y--;
633
spk_x = vc->vc_cols - 1;
634
} else {
635
spk_x--;
636
}
637
spk_pos -= 2;
638
ch = get_char(vc, (u_short *)spk_pos, &temp);
639
if (ch == SPACE || ch == 0)
640
state = 0;
641
else if (ch < 0x100 && IS_WDLM(ch))
642
state = 1;
643
else
644
state = 2;
645
if (state < last_state) {
646
spk_pos += 2;
647
spk_x++;
648
break;
649
}
650
last_state = state;
651
}
652
if (spk_x == 0 && edge_said == edge_quiet)
653
edge_said = edge_left;
654
if (edge_said > edge_none && edge_said < edge_quiet)
655
announce_edge(vc, edge_said);
656
say_word(vc);
657
}
658
659
static void say_next_word(struct vc_data *vc)
660
{
661
u_char temp;
662
u16 ch;
663
enum edge edge_said = edge_none;
664
u_short last_state = 2, state = 0;
665
666
spk_parked |= 0x01;
667
if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
668
announce_edge(vc, edge_bottom);
669
return;
670
}
671
while (1) {
672
ch = get_char(vc, (u_short *)spk_pos, &temp);
673
if (ch == SPACE || ch == 0)
674
state = 0;
675
else if (ch < 0x100 && IS_WDLM(ch))
676
state = 1;
677
else
678
state = 2;
679
if (state > last_state)
680
break;
681
if (spk_x >= vc->vc_cols - 1) {
682
if (spk_y == vc->vc_rows - 1) {
683
edge_said = edge_bottom;
684
break;
685
}
686
state = 0;
687
spk_y++;
688
spk_x = 0;
689
edge_said = edge_right;
690
} else {
691
spk_x++;
692
}
693
spk_pos += 2;
694
last_state = state;
695
}
696
if (edge_said > edge_none)
697
announce_edge(vc, edge_said);
698
say_word(vc);
699
}
700
701
static void spell_word(struct vc_data *vc)
702
{
703
static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
704
u16 *cp = buf;
705
char *cp1;
706
char *str_cap = spk_str_caps_stop;
707
char *last_cap = spk_str_caps_stop;
708
struct var_t *direct = spk_get_var(DIRECT);
709
u16 ch;
710
711
if (!get_word(vc))
712
return;
713
while ((ch = *cp)) {
714
if (cp != buf)
715
synth_printf(" %s ", delay_str[spk_spell_delay]);
716
/* FIXME: Non-latin1 considered as lower case */
717
if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
718
str_cap = spk_str_caps_start;
719
if (*spk_str_caps_stop)
720
spk_pitch_shift++;
721
else /* synth has no pitch */
722
last_cap = spk_str_caps_stop;
723
} else {
724
str_cap = spk_str_caps_stop;
725
}
726
if (str_cap != last_cap) {
727
synth_printf("%s", str_cap);
728
last_cap = str_cap;
729
}
730
if (ch >= 0x100 || (direct && direct->u.n.value)) {
731
synth_putwc_s(ch);
732
} else if (this_speakup_key == SPELL_PHONETIC &&
733
ch <= 0x7f && isalpha(ch)) {
734
ch &= 0x1f;
735
cp1 = phonetic[--ch];
736
synth_printf("%s", cp1);
737
} else {
738
cp1 = spk_characters[ch];
739
if (*cp1 == '^') {
740
synth_printf("%s", spk_msg_get(MSG_CTRL));
741
cp1++;
742
}
743
synth_printf("%s", cp1);
744
}
745
cp++;
746
}
747
if (str_cap != spk_str_caps_stop)
748
synth_printf("%s", spk_str_caps_stop);
749
}
750
751
static int get_line(struct vc_data *vc)
752
{
753
u_long tmp = spk_pos - (spk_x * 2);
754
int i = 0;
755
u_char tmp2;
756
757
spk_old_attr = spk_attr;
758
spk_attr = get_attributes(vc, (u_short *)spk_pos);
759
for (i = 0; i < vc->vc_cols; i++) {
760
buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
761
tmp += 2;
762
}
763
for (--i; i >= 0; i--)
764
if (buf[i] != SPACE)
765
break;
766
return ++i;
767
}
768
769
static void say_line(struct vc_data *vc)
770
{
771
int i = get_line(vc);
772
u16 *cp;
773
u_short saved_punc_mask = spk_punc_mask;
774
775
if (i == 0) {
776
synth_printf("%s\n", spk_msg_get(MSG_BLANK));
777
return;
778
}
779
buf[i++] = '\n';
780
if (this_speakup_key == SAY_LINE_INDENT) {
781
cp = buf;
782
while (*cp == SPACE)
783
cp++;
784
synth_printf("%zd, ", (cp - buf) + 1);
785
}
786
spk_punc_mask = spk_punc_masks[spk_reading_punc];
787
spkup_write(buf, i);
788
spk_punc_mask = saved_punc_mask;
789
}
790
791
static void say_prev_line(struct vc_data *vc)
792
{
793
spk_parked |= 0x01;
794
if (spk_y == 0) {
795
announce_edge(vc, edge_top);
796
return;
797
}
798
spk_y--;
799
spk_pos -= vc->vc_size_row;
800
say_line(vc);
801
}
802
803
static void say_next_line(struct vc_data *vc)
804
{
805
spk_parked |= 0x01;
806
if (spk_y == vc->vc_rows - 1) {
807
announce_edge(vc, edge_bottom);
808
return;
809
}
810
spk_y++;
811
spk_pos += vc->vc_size_row;
812
say_line(vc);
813
}
814
815
static int say_from_to(struct vc_data *vc, u_long from, u_long to,
816
int read_punc)
817
{
818
int i = 0;
819
u_char tmp;
820
u_short saved_punc_mask = spk_punc_mask;
821
822
spk_old_attr = spk_attr;
823
spk_attr = get_attributes(vc, (u_short *)from);
824
while (from < to) {
825
buf[i++] = get_char(vc, (u_short *)from, &tmp);
826
from += 2;
827
if (i >= vc->vc_size_row)
828
break;
829
}
830
for (--i; i >= 0; i--)
831
if (buf[i] != SPACE)
832
break;
833
buf[++i] = SPACE;
834
buf[++i] = '\0';
835
if (i < 1)
836
return i;
837
if (read_punc)
838
spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
839
spkup_write(buf, i);
840
if (read_punc)
841
spk_punc_mask = saved_punc_mask;
842
return i - 1;
843
}
844
845
static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
846
int read_punc)
847
{
848
u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
849
u_long end = start + (to * 2);
850
851
start += from * 2;
852
if (say_from_to(vc, start, end, read_punc) <= 0)
853
if (cursor_track != read_all_mode)
854
synth_printf("%s\n", spk_msg_get(MSG_BLANK));
855
}
856
857
/* Sentence Reading Commands */
858
859
static int currsentence;
860
static int numsentences[2];
861
static u16 *sentbufend[2];
862
static u16 *sentmarks[2][10];
863
static int currbuf;
864
static int bn;
865
static u16 sentbuf[2][256];
866
867
static int say_sentence_num(int num, int prev)
868
{
869
bn = currbuf;
870
currsentence = num + 1;
871
if (prev && --bn == -1)
872
bn = 1;
873
874
if (num > numsentences[bn])
875
return 0;
876
877
spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
878
return 1;
879
}
880
881
static int get_sentence_buf(struct vc_data *vc, int read_punc)
882
{
883
u_long start, end;
884
int i, bn;
885
u_char tmp;
886
887
currbuf++;
888
if (currbuf == 2)
889
currbuf = 0;
890
bn = currbuf;
891
start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
892
end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
893
894
numsentences[bn] = 0;
895
sentmarks[bn][0] = &sentbuf[bn][0];
896
i = 0;
897
spk_old_attr = spk_attr;
898
spk_attr = get_attributes(vc, (u_short *)start);
899
900
while (start < end) {
901
sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
902
if (i > 0) {
903
if (sentbuf[bn][i] == SPACE &&
904
sentbuf[bn][i - 1] == '.' &&
905
numsentences[bn] < 9) {
906
/* Sentence Marker */
907
numsentences[bn]++;
908
sentmarks[bn][numsentences[bn]] =
909
&sentbuf[bn][i];
910
}
911
}
912
i++;
913
start += 2;
914
if (i >= vc->vc_size_row)
915
break;
916
}
917
918
for (--i; i >= 0; i--)
919
if (sentbuf[bn][i] != SPACE)
920
break;
921
922
if (i < 1)
923
return -1;
924
925
sentbuf[bn][++i] = SPACE;
926
sentbuf[bn][++i] = '\0';
927
928
sentbufend[bn] = &sentbuf[bn][i];
929
return numsentences[bn];
930
}
931
932
static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
933
{
934
u_long start = vc->vc_origin, end;
935
936
if (from > 0)
937
start += from * vc->vc_size_row;
938
if (to > vc->vc_rows)
939
to = vc->vc_rows;
940
end = vc->vc_origin + (to * vc->vc_size_row);
941
for (from = start; from < end; from = to) {
942
to = from + vc->vc_size_row;
943
say_from_to(vc, from, to, 1);
944
}
945
}
946
947
static void say_screen(struct vc_data *vc)
948
{
949
say_screen_from_to(vc, 0, vc->vc_rows);
950
}
951
952
static void speakup_win_say(struct vc_data *vc)
953
{
954
u_long start, end, from, to;
955
956
if (win_start < 2) {
957
synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
958
return;
959
}
960
start = vc->vc_origin + (win_top * vc->vc_size_row);
961
end = vc->vc_origin + (win_bottom * vc->vc_size_row);
962
while (start <= end) {
963
from = start + (win_left * 2);
964
to = start + (win_right * 2);
965
say_from_to(vc, from, to, 1);
966
start += vc->vc_size_row;
967
}
968
}
969
970
static void top_edge(struct vc_data *vc)
971
{
972
spk_parked |= 0x01;
973
spk_pos = vc->vc_origin + 2 * spk_x;
974
spk_y = 0;
975
say_line(vc);
976
}
977
978
static void bottom_edge(struct vc_data *vc)
979
{
980
spk_parked |= 0x01;
981
spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
982
spk_y = vc->vc_rows - 1;
983
say_line(vc);
984
}
985
986
static void left_edge(struct vc_data *vc)
987
{
988
spk_parked |= 0x01;
989
spk_pos -= spk_x * 2;
990
spk_x = 0;
991
say_char(vc);
992
}
993
994
static void right_edge(struct vc_data *vc)
995
{
996
spk_parked |= 0x01;
997
spk_pos += (vc->vc_cols - spk_x - 1) * 2;
998
spk_x = vc->vc_cols - 1;
999
say_char(vc);
1000
}
1001
1002
static void say_first_char(struct vc_data *vc)
1003
{
1004
int i, len = get_line(vc);
1005
u16 ch;
1006
1007
spk_parked |= 0x01;
1008
if (len == 0) {
1009
synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1010
return;
1011
}
1012
for (i = 0; i < len; i++)
1013
if (buf[i] != SPACE)
1014
break;
1015
ch = buf[i];
1016
spk_pos -= (spk_x - i) * 2;
1017
spk_x = i;
1018
synth_printf("%d, ", ++i);
1019
speak_char(ch);
1020
}
1021
1022
static void say_last_char(struct vc_data *vc)
1023
{
1024
int len = get_line(vc);
1025
u16 ch;
1026
1027
spk_parked |= 0x01;
1028
if (len == 0) {
1029
synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1030
return;
1031
}
1032
ch = buf[--len];
1033
spk_pos -= (spk_x - len) * 2;
1034
spk_x = len;
1035
synth_printf("%d, ", ++len);
1036
speak_char(ch);
1037
}
1038
1039
static void say_position(struct vc_data *vc)
1040
{
1041
synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1042
vc->vc_num + 1);
1043
synth_printf("\n");
1044
}
1045
1046
/* Added by brianb */
1047
static void say_char_num(struct vc_data *vc)
1048
{
1049
u_char tmp;
1050
u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);
1051
1052
synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1053
}
1054
1055
/* these are stub functions to keep keyboard.c happy. */
1056
1057
static void say_from_top(struct vc_data *vc)
1058
{
1059
say_screen_from_to(vc, 0, spk_y);
1060
}
1061
1062
static void say_to_bottom(struct vc_data *vc)
1063
{
1064
say_screen_from_to(vc, spk_y, vc->vc_rows);
1065
}
1066
1067
static void say_from_left(struct vc_data *vc)
1068
{
1069
say_line_from_to(vc, 0, spk_x, 1);
1070
}
1071
1072
static void say_to_right(struct vc_data *vc)
1073
{
1074
say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1075
}
1076
1077
/* end of stub functions. */
1078
1079
static void spkup_write(const u16 *in_buf, int count)
1080
{
1081
static int rep_count;
1082
static u16 ch = '\0', old_ch = '\0';
1083
static u_short char_type, last_type;
1084
int in_count = count;
1085
1086
spk_keydown = 0;
1087
while (count--) {
1088
if (cursor_track == read_all_mode) {
1089
/* Insert Sentence Index */
1090
if ((in_buf == sentmarks[bn][currsentence]) &&
1091
(currsentence <= numsentences[bn]))
1092
synth_insert_next_index(currsentence++);
1093
}
1094
ch = *in_buf++;
1095
if (ch < 0x100)
1096
char_type = spk_chartab[ch];
1097
else
1098
char_type = ALPHA;
1099
if (ch == old_ch && !(char_type & B_NUM)) {
1100
if (++rep_count > 2)
1101
continue;
1102
} else {
1103
if ((last_type & CH_RPT) && rep_count > 2) {
1104
synth_printf(" ");
1105
synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1106
++rep_count);
1107
synth_printf(" ");
1108
}
1109
rep_count = 0;
1110
}
1111
if (ch == spk_lastkey) {
1112
rep_count = 0;
1113
if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1114
speak_char(ch);
1115
} else if (char_type & B_ALPHA) {
1116
if ((synth_flags & SF_DEC) && (last_type & PUNC))
1117
synth_buffer_add(SPACE);
1118
synth_putwc_s(ch);
1119
} else if (char_type & B_NUM) {
1120
rep_count = 0;
1121
synth_putwc_s(ch);
1122
} else if (char_type & spk_punc_mask) {
1123
speak_char(ch);
1124
char_type &= ~PUNC; /* for dec nospell processing */
1125
} else if (char_type & SYNTH_OK) {
1126
/* these are usually puncts like . and , which synth
1127
* needs for expression.
1128
* suppress multiple to get rid of long pauses and
1129
* clear repeat count
1130
* so if someone has
1131
* repeats on you don't get nothing repeated count
1132
*/
1133
if (ch != old_ch)
1134
synth_putwc_s(ch);
1135
else
1136
rep_count = 0;
1137
} else {
1138
/* send space and record position, if next is num overwrite space */
1139
if (old_ch != ch)
1140
synth_buffer_add(SPACE);
1141
else
1142
rep_count = 0;
1143
}
1144
old_ch = ch;
1145
last_type = char_type;
1146
}
1147
spk_lastkey = 0;
1148
if (in_count > 2 && rep_count > 2) {
1149
if (last_type & CH_RPT) {
1150
synth_printf(" ");
1151
synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
1152
++rep_count);
1153
synth_printf(" ");
1154
}
1155
rep_count = 0;
1156
}
1157
}
1158
1159
static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1160
1161
static void read_all_doc(struct vc_data *vc);
1162
static void cursor_done(struct timer_list *unused);
1163
static DEFINE_TIMER(cursor_timer, cursor_done);
1164
1165
static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1166
{
1167
unsigned long flags;
1168
1169
if (!synth || up_flag || spk_killed)
1170
return;
1171
spin_lock_irqsave(&speakup_info.spinlock, flags);
1172
if (cursor_track == read_all_mode) {
1173
switch (value) {
1174
case KVAL(K_SHIFT):
1175
timer_delete(&cursor_timer);
1176
spk_shut_up &= 0xfe;
1177
spk_do_flush();
1178
read_all_doc(vc);
1179
break;
1180
case KVAL(K_CTRL):
1181
timer_delete(&cursor_timer);
1182
cursor_track = prev_cursor_track;
1183
spk_shut_up &= 0xfe;
1184
spk_do_flush();
1185
break;
1186
}
1187
} else {
1188
spk_shut_up &= 0xfe;
1189
spk_do_flush();
1190
}
1191
if (spk_say_ctrl && value < NUM_CTL_LABELS)
1192
synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1193
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1194
}
1195
1196
static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1197
{
1198
unsigned long flags;
1199
1200
spin_lock_irqsave(&speakup_info.spinlock, flags);
1201
if (up_flag) {
1202
spk_lastkey = 0;
1203
spk_keydown = 0;
1204
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1205
return;
1206
}
1207
if (!synth || spk_killed) {
1208
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1209
return;
1210
}
1211
spk_shut_up &= 0xfe;
1212
spk_lastkey = value;
1213
spk_keydown++;
1214
spk_parked &= 0xfe;
1215
if (spk_key_echo == 2 && value >= MINECHOCHAR)
1216
speak_char(value);
1217
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1218
}
1219
1220
int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1221
{
1222
int i = 0, states, key_data_len;
1223
const u_char *cp = key_info;
1224
u_char *cp1 = k_buffer;
1225
u_char ch, version, num_keys;
1226
1227
version = *cp++;
1228
if (version != KEY_MAP_VER) {
1229
pr_debug("version found %d should be %d\n",
1230
version, KEY_MAP_VER);
1231
return -EINVAL;
1232
}
1233
num_keys = *cp;
1234
states = (int)cp[1];
1235
key_data_len = (states + 1) * (num_keys + 1);
1236
if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
1237
pr_debug("too many key_infos (%d over %u)\n",
1238
key_data_len + SHIFT_TBL_SIZE + 4,
1239
(unsigned int)(sizeof(spk_key_buf)));
1240
return -EINVAL;
1241
}
1242
memset(k_buffer, 0, SHIFT_TBL_SIZE);
1243
memset(spk_our_keys, 0, sizeof(spk_our_keys));
1244
spk_shift_table = k_buffer;
1245
spk_our_keys[0] = spk_shift_table;
1246
cp1 += SHIFT_TBL_SIZE;
1247
memcpy(cp1, cp, key_data_len + 3);
1248
/* get num_keys, states and data */
1249
cp1 += 2; /* now pointing at shift states */
1250
for (i = 1; i <= states; i++) {
1251
ch = *cp1++;
1252
if (ch >= SHIFT_TBL_SIZE) {
1253
pr_debug("(%d) not valid shift state (max_allowed = %d)\n",
1254
ch, SHIFT_TBL_SIZE);
1255
return -EINVAL;
1256
}
1257
spk_shift_table[ch] = i;
1258
}
1259
keymap_flags = *cp1++;
1260
while ((ch = *cp1)) {
1261
if (ch >= MAX_KEY) {
1262
pr_debug("(%d), not valid key, (max_allowed = %d)\n",
1263
ch, MAX_KEY);
1264
return -EINVAL;
1265
}
1266
spk_our_keys[ch] = cp1;
1267
cp1 += states + 1;
1268
}
1269
return 0;
1270
}
1271
1272
enum spk_vars_id {
1273
BELL_POS_ID = 0, SPELL_DELAY_ID, ATTRIB_BLEEP_ID,
1274
BLEEPS_ID, BLEEP_TIME_ID, PUNC_LEVEL_ID,
1275
READING_PUNC_ID, CURSOR_TIME_ID, SAY_CONTROL_ID,
1276
SAY_WORD_CTL_ID, NO_INTERRUPT_ID, KEY_ECHO_ID,
1277
CUR_PHONETIC_ID, V_LAST_VAR_ID, NB_ID
1278
};
1279
1280
static struct var_t spk_vars[NB_ID] = {
1281
/* bell must be first to set high limit */
1282
[BELL_POS_ID] = { BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1283
[SPELL_DELAY_ID] = { SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1284
[ATTRIB_BLEEP_ID] = { ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1285
[BLEEPS_ID] = { BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1286
[BLEEP_TIME_ID] = { BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1287
[PUNC_LEVEL_ID] = { PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1288
[READING_PUNC_ID] = { READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1289
[CURSOR_TIME_ID] = { CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1290
[SAY_CONTROL_ID] = { SAY_CONTROL, TOGGLE_0},
1291
[SAY_WORD_CTL_ID] = {SAY_WORD_CTL, TOGGLE_0},
1292
[NO_INTERRUPT_ID] = { NO_INTERRUPT, TOGGLE_0},
1293
[KEY_ECHO_ID] = { KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1294
[CUR_PHONETIC_ID] = { CUR_PHONETIC, .u.n = {NULL, 0, 0, 1, 0, 0, NULL} },
1295
V_LAST_VAR
1296
};
1297
1298
static void toggle_cursoring(struct vc_data *vc)
1299
{
1300
if (cursor_track == read_all_mode)
1301
cursor_track = prev_cursor_track;
1302
if (++cursor_track >= CT_Max)
1303
cursor_track = 0;
1304
synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1305
}
1306
1307
void spk_reset_default_chars(void)
1308
{
1309
int i;
1310
1311
/* First, free any non-default */
1312
for (i = 0; i < 256; i++) {
1313
if (spk_characters[i] &&
1314
(spk_characters[i] != spk_default_chars[i]))
1315
kfree(spk_characters[i]);
1316
}
1317
1318
memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1319
}
1320
1321
void spk_reset_default_chartab(void)
1322
{
1323
memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1324
}
1325
1326
static const struct st_bits_data *pb_edit;
1327
1328
static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1329
{
1330
short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1331
1332
if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1333
return -1;
1334
if (ch == SPACE) {
1335
synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1336
spk_special_handler = NULL;
1337
return 1;
1338
}
1339
if (mask < PUNC && !(ch_type & PUNC))
1340
return -1;
1341
spk_chartab[ch] ^= mask;
1342
speak_char(ch);
1343
synth_printf(" %s\n",
1344
(spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1345
spk_msg_get(MSG_OFF));
1346
return 1;
1347
}
1348
1349
/* Allocation concurrency is protected by the console semaphore */
1350
static int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags)
1351
{
1352
int vc_num;
1353
1354
vc_num = vc->vc_num;
1355
if (!speakup_console[vc_num]) {
1356
speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1357
gfp_flags);
1358
if (!speakup_console[vc_num])
1359
return -ENOMEM;
1360
speakup_date(vc);
1361
} else if (!spk_parked) {
1362
speakup_date(vc);
1363
}
1364
1365
return 0;
1366
}
1367
1368
static void speakup_deallocate(struct vc_data *vc)
1369
{
1370
int vc_num;
1371
1372
vc_num = vc->vc_num;
1373
kfree(speakup_console[vc_num]);
1374
speakup_console[vc_num] = NULL;
1375
}
1376
1377
enum read_all_command {
1378
RA_NEXT_SENT = KVAL(K_DOWN)+1,
1379
RA_PREV_LINE = KVAL(K_LEFT)+1,
1380
RA_NEXT_LINE = KVAL(K_RIGHT)+1,
1381
RA_PREV_SENT = KVAL(K_UP)+1,
1382
RA_DOWN_ARROW,
1383
RA_TIMER,
1384
RA_FIND_NEXT_SENT,
1385
RA_FIND_PREV_SENT,
1386
};
1387
1388
static u_char is_cursor;
1389
static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1390
static int cursor_con;
1391
1392
static void reset_highlight_buffers(struct vc_data *);
1393
1394
static enum read_all_command read_all_key;
1395
1396
static int in_keyboard_notifier;
1397
1398
static void start_read_all_timer(struct vc_data *vc, enum read_all_command command);
1399
1400
static void kbd_fakekey2(struct vc_data *vc, enum read_all_command command)
1401
{
1402
timer_delete(&cursor_timer);
1403
speakup_fake_down_arrow();
1404
start_read_all_timer(vc, command);
1405
}
1406
1407
static void read_all_doc(struct vc_data *vc)
1408
{
1409
if ((vc->vc_num != fg_console) || !synth || spk_shut_up)
1410
return;
1411
if (!synth_supports_indexing())
1412
return;
1413
if (cursor_track != read_all_mode)
1414
prev_cursor_track = cursor_track;
1415
cursor_track = read_all_mode;
1416
spk_reset_index_count(0);
1417
if (get_sentence_buf(vc, 0) == -1) {
1418
timer_delete(&cursor_timer);
1419
if (!in_keyboard_notifier)
1420
speakup_fake_down_arrow();
1421
start_read_all_timer(vc, RA_DOWN_ARROW);
1422
} else {
1423
say_sentence_num(0, 0);
1424
synth_insert_next_index(0);
1425
start_read_all_timer(vc, RA_TIMER);
1426
}
1427
}
1428
1429
static void stop_read_all(struct vc_data *vc)
1430
{
1431
timer_delete(&cursor_timer);
1432
cursor_track = prev_cursor_track;
1433
spk_shut_up &= 0xfe;
1434
spk_do_flush();
1435
}
1436
1437
static void start_read_all_timer(struct vc_data *vc, enum read_all_command command)
1438
{
1439
struct var_t *cursor_timeout;
1440
1441
cursor_con = vc->vc_num;
1442
read_all_key = command;
1443
cursor_timeout = spk_get_var(CURSOR_TIME);
1444
mod_timer(&cursor_timer,
1445
jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1446
}
1447
1448
static void handle_cursor_read_all(struct vc_data *vc, enum read_all_command command)
1449
{
1450
int indcount, sentcount, rv, sn;
1451
1452
switch (command) {
1453
case RA_NEXT_SENT:
1454
/* Get Current Sentence */
1455
spk_get_index_count(&indcount, &sentcount);
1456
/*printk("%d %d ", indcount, sentcount); */
1457
spk_reset_index_count(sentcount + 1);
1458
if (indcount == 1) {
1459
if (!say_sentence_num(sentcount + 1, 0)) {
1460
kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1461
return;
1462
}
1463
synth_insert_next_index(0);
1464
} else {
1465
sn = 0;
1466
if (!say_sentence_num(sentcount + 1, 1)) {
1467
sn = 1;
1468
spk_reset_index_count(sn);
1469
} else {
1470
synth_insert_next_index(0);
1471
}
1472
if (!say_sentence_num(sn, 0)) {
1473
kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1474
return;
1475
}
1476
synth_insert_next_index(0);
1477
}
1478
start_read_all_timer(vc, RA_TIMER);
1479
break;
1480
case RA_PREV_SENT:
1481
break;
1482
case RA_NEXT_LINE:
1483
read_all_doc(vc);
1484
break;
1485
case RA_PREV_LINE:
1486
break;
1487
case RA_DOWN_ARROW:
1488
if (get_sentence_buf(vc, 0) == -1) {
1489
kbd_fakekey2(vc, RA_DOWN_ARROW);
1490
} else {
1491
say_sentence_num(0, 0);
1492
synth_insert_next_index(0);
1493
start_read_all_timer(vc, RA_TIMER);
1494
}
1495
break;
1496
case RA_FIND_NEXT_SENT:
1497
rv = get_sentence_buf(vc, 0);
1498
if (rv == -1)
1499
read_all_doc(vc);
1500
if (rv == 0) {
1501
kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1502
} else {
1503
say_sentence_num(1, 0);
1504
synth_insert_next_index(0);
1505
start_read_all_timer(vc, RA_TIMER);
1506
}
1507
break;
1508
case RA_FIND_PREV_SENT:
1509
break;
1510
case RA_TIMER:
1511
spk_get_index_count(&indcount, &sentcount);
1512
if (indcount < 2)
1513
kbd_fakekey2(vc, RA_DOWN_ARROW);
1514
else
1515
start_read_all_timer(vc, RA_TIMER);
1516
break;
1517
}
1518
}
1519
1520
static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1521
{
1522
unsigned long flags;
1523
1524
spin_lock_irqsave(&speakup_info.spinlock, flags);
1525
if (cursor_track == read_all_mode) {
1526
spk_parked &= 0xfe;
1527
if (!synth || up_flag || spk_shut_up) {
1528
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1529
return NOTIFY_STOP;
1530
}
1531
timer_delete(&cursor_timer);
1532
spk_shut_up &= 0xfe;
1533
spk_do_flush();
1534
start_read_all_timer(vc, value + 1);
1535
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1536
return NOTIFY_STOP;
1537
}
1538
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1539
return NOTIFY_OK;
1540
}
1541
1542
static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1543
{
1544
unsigned long flags;
1545
struct var_t *cursor_timeout;
1546
1547
spin_lock_irqsave(&speakup_info.spinlock, flags);
1548
spk_parked &= 0xfe;
1549
if (!synth || up_flag || spk_shut_up || cursor_track == CT_Off) {
1550
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1551
return;
1552
}
1553
spk_shut_up &= 0xfe;
1554
if (spk_no_intr)
1555
spk_do_flush();
1556
/* the key press flushes if !no_inter but we want to flush on cursor
1557
* moves regardless of no_inter state
1558
*/
1559
is_cursor = value + 1;
1560
old_cursor_pos = vc->vc_pos;
1561
old_cursor_x = vc->state.x;
1562
old_cursor_y = vc->state.y;
1563
speakup_console[vc->vc_num]->ht.cy = vc->state.y;
1564
cursor_con = vc->vc_num;
1565
if (cursor_track == CT_Highlight)
1566
reset_highlight_buffers(vc);
1567
cursor_timeout = spk_get_var(CURSOR_TIME);
1568
mod_timer(&cursor_timer,
1569
jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1570
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1571
}
1572
1573
static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
1574
{
1575
int i, bi, hi;
1576
int vc_num = vc->vc_num;
1577
1578
bi = (vc->vc_attr & 0x70) >> 4;
1579
hi = speakup_console[vc_num]->ht.highsize[bi];
1580
1581
i = 0;
1582
if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1583
speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1584
speakup_console[vc_num]->ht.rx[bi] = vc->state.x;
1585
speakup_console[vc_num]->ht.ry[bi] = vc->state.y;
1586
}
1587
while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1588
if (ic[i] > 32) {
1589
speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1590
hi++;
1591
} else if ((ic[i] == 32) && (hi != 0)) {
1592
if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1593
32) {
1594
speakup_console[vc_num]->ht.highbuf[bi][hi] =
1595
ic[i];
1596
hi++;
1597
}
1598
}
1599
i++;
1600
}
1601
speakup_console[vc_num]->ht.highsize[bi] = hi;
1602
}
1603
1604
static void reset_highlight_buffers(struct vc_data *vc)
1605
{
1606
int i;
1607
int vc_num = vc->vc_num;
1608
1609
for (i = 0; i < 8; i++)
1610
speakup_console[vc_num]->ht.highsize[i] = 0;
1611
}
1612
1613
static int count_highlight_color(struct vc_data *vc)
1614
{
1615
int i, bg;
1616
int cc;
1617
int vc_num = vc->vc_num;
1618
u16 ch;
1619
u16 *start = (u16 *)vc->vc_origin;
1620
1621
for (i = 0; i < 8; i++)
1622
speakup_console[vc_num]->ht.bgcount[i] = 0;
1623
1624
for (i = 0; i < vc->vc_rows; i++) {
1625
u16 *end = start + vc->vc_cols * 2;
1626
u16 *ptr;
1627
1628
for (ptr = start; ptr < end; ptr++) {
1629
ch = get_attributes(vc, ptr);
1630
bg = (ch & 0x70) >> 4;
1631
speakup_console[vc_num]->ht.bgcount[bg]++;
1632
}
1633
start += vc->vc_size_row;
1634
}
1635
1636
cc = 0;
1637
for (i = 0; i < 8; i++)
1638
if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1639
cc++;
1640
return cc;
1641
}
1642
1643
static int get_highlight_color(struct vc_data *vc)
1644
{
1645
int i, j;
1646
unsigned int cptr[8];
1647
int vc_num = vc->vc_num;
1648
1649
for (i = 0; i < 8; i++)
1650
cptr[i] = i;
1651
1652
for (i = 0; i < 7; i++)
1653
for (j = i + 1; j < 8; j++)
1654
if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1655
speakup_console[vc_num]->ht.bgcount[cptr[j]])
1656
swap(cptr[i], cptr[j]);
1657
1658
for (i = 0; i < 8; i++)
1659
if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1660
if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1661
return cptr[i];
1662
return -1;
1663
}
1664
1665
static int speak_highlight(struct vc_data *vc)
1666
{
1667
int hc, d;
1668
int vc_num = vc->vc_num;
1669
1670
if (count_highlight_color(vc) == 1)
1671
return 0;
1672
hc = get_highlight_color(vc);
1673
if (hc != -1) {
1674
d = vc->state.y - speakup_console[vc_num]->ht.cy;
1675
if ((d == 1) || (d == -1))
1676
if (speakup_console[vc_num]->ht.ry[hc] != vc->state.y)
1677
return 0;
1678
spk_parked |= 0x01;
1679
spk_do_flush();
1680
spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1681
speakup_console[vc_num]->ht.highsize[hc]);
1682
spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1683
spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1684
spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1685
return 1;
1686
}
1687
return 0;
1688
}
1689
1690
static void cursor_done(struct timer_list *unused)
1691
{
1692
struct vc_data *vc = vc_cons[cursor_con].d;
1693
unsigned long flags;
1694
1695
timer_delete(&cursor_timer);
1696
spin_lock_irqsave(&speakup_info.spinlock, flags);
1697
if (cursor_con != fg_console) {
1698
is_cursor = 0;
1699
goto out;
1700
}
1701
speakup_date(vc);
1702
if (win_enabled) {
1703
if (vc->state.x >= win_left && vc->state.x <= win_right &&
1704
vc->state.y >= win_top && vc->state.y <= win_bottom) {
1705
spk_keydown = 0;
1706
is_cursor = 0;
1707
goto out;
1708
}
1709
}
1710
if (cursor_track == read_all_mode) {
1711
handle_cursor_read_all(vc, read_all_key);
1712
goto out;
1713
}
1714
if (cursor_track == CT_Highlight) {
1715
if (speak_highlight(vc)) {
1716
spk_keydown = 0;
1717
is_cursor = 0;
1718
goto out;
1719
}
1720
}
1721
if (cursor_track == CT_Window)
1722
speakup_win_say(vc);
1723
else if (is_cursor == 1 || is_cursor == 4)
1724
say_line_from_to(vc, 0, vc->vc_cols, 0);
1725
else {
1726
if (spk_cur_phonetic == 1)
1727
say_phonetic_char(vc);
1728
else
1729
say_char(vc);
1730
}
1731
spk_keydown = 0;
1732
is_cursor = 0;
1733
out:
1734
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1735
}
1736
1737
/* called by: vt_notifier_call() */
1738
static void speakup_bs(struct vc_data *vc)
1739
{
1740
unsigned long flags;
1741
1742
if (!speakup_console[vc->vc_num])
1743
return;
1744
if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1745
/* Speakup output, discard */
1746
return;
1747
if (!spk_parked)
1748
speakup_date(vc);
1749
if (spk_shut_up || !synth) {
1750
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1751
return;
1752
}
1753
if (vc->vc_num == fg_console && spk_keydown) {
1754
spk_keydown = 0;
1755
if (!is_cursor)
1756
say_char(vc);
1757
}
1758
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1759
}
1760
1761
/* called by: vt_notifier_call() */
1762
static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
1763
{
1764
unsigned long flags;
1765
1766
if ((vc->vc_num != fg_console) || spk_shut_up || !synth)
1767
return;
1768
if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1769
/* Speakup output, discard */
1770
return;
1771
if (spk_bell_pos && spk_keydown && (vc->state.x == spk_bell_pos - 1))
1772
bleep(3);
1773
if ((is_cursor) || (cursor_track == read_all_mode)) {
1774
if (cursor_track == CT_Highlight)
1775
update_color_buffer(vc, str, len);
1776
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1777
return;
1778
}
1779
if (win_enabled) {
1780
if (vc->state.x >= win_left && vc->state.x <= win_right &&
1781
vc->state.y >= win_top && vc->state.y <= win_bottom) {
1782
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1783
return;
1784
}
1785
}
1786
1787
spkup_write(str, len);
1788
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1789
}
1790
1791
static void speakup_con_update(struct vc_data *vc)
1792
{
1793
unsigned long flags;
1794
1795
if (!speakup_console[vc->vc_num] || spk_parked || !synth)
1796
return;
1797
if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1798
/* Speakup output, discard */
1799
return;
1800
speakup_date(vc);
1801
if (vc->vc_mode == KD_GRAPHICS && !spk_paused && spk_str_pause[0]) {
1802
synth_printf("%s", spk_str_pause);
1803
spk_paused = true;
1804
}
1805
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1806
}
1807
1808
static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1809
{
1810
unsigned long flags;
1811
int on_off = 2;
1812
char *label;
1813
1814
if (!synth || up_flag || spk_killed)
1815
return;
1816
spin_lock_irqsave(&speakup_info.spinlock, flags);
1817
spk_shut_up &= 0xfe;
1818
if (spk_no_intr)
1819
spk_do_flush();
1820
switch (value) {
1821
case KVAL(K_CAPS):
1822
label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1823
on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1824
break;
1825
case KVAL(K_NUM):
1826
label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1827
on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1828
break;
1829
case KVAL(K_HOLD):
1830
label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1831
on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1832
if (speakup_console[vc->vc_num])
1833
speakup_console[vc->vc_num]->tty_stopped = on_off;
1834
break;
1835
default:
1836
spk_parked &= 0xfe;
1837
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1838
return;
1839
}
1840
if (on_off < 2)
1841
synth_printf("%s %s\n",
1842
label, spk_msg_get(MSG_STATUS_START + on_off));
1843
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1844
}
1845
1846
static int inc_dec_var(u_char value)
1847
{
1848
struct st_var_header *p_header;
1849
struct var_t *var_data;
1850
char num_buf[32];
1851
char *cp = num_buf;
1852
char *pn;
1853
int var_id = (int)value - VAR_START;
1854
int how = (var_id & 1) ? E_INC : E_DEC;
1855
1856
var_id = var_id / 2 + FIRST_SET_VAR;
1857
p_header = spk_get_var_header(var_id);
1858
if (!p_header)
1859
return -1;
1860
if (p_header->var_type != VAR_NUM)
1861
return -1;
1862
var_data = p_header->data;
1863
if (spk_set_num_var(1, p_header, how) != 0)
1864
return -1;
1865
if (!spk_close_press) {
1866
for (pn = p_header->name; *pn; pn++) {
1867
if (*pn == '_')
1868
*cp = SPACE;
1869
else
1870
*cp++ = *pn;
1871
}
1872
}
1873
snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1874
var_data->u.n.value);
1875
synth_printf("%s", num_buf);
1876
return 0;
1877
}
1878
1879
static void speakup_win_set(struct vc_data *vc)
1880
{
1881
char info[40];
1882
1883
if (win_start > 1) {
1884
synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1885
return;
1886
}
1887
if (spk_x < win_left || spk_y < win_top) {
1888
synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1889
return;
1890
}
1891
if (win_start && spk_x == win_left && spk_y == win_top) {
1892
win_left = 0;
1893
win_right = vc->vc_cols - 1;
1894
win_bottom = spk_y;
1895
snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1896
(int)win_top + 1);
1897
} else {
1898
if (!win_start) {
1899
win_top = spk_y;
1900
win_left = spk_x;
1901
} else {
1902
win_bottom = spk_y;
1903
win_right = spk_x;
1904
}
1905
snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1906
(win_start) ?
1907
spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1908
(int)spk_y + 1, (int)spk_x + 1);
1909
}
1910
synth_printf("%s\n", info);
1911
win_start++;
1912
}
1913
1914
static void speakup_win_clear(struct vc_data *vc)
1915
{
1916
win_top = 0;
1917
win_bottom = 0;
1918
win_left = 0;
1919
win_right = 0;
1920
win_start = 0;
1921
synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1922
}
1923
1924
static void speakup_win_enable(struct vc_data *vc)
1925
{
1926
if (win_start < 2) {
1927
synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1928
return;
1929
}
1930
win_enabled ^= 1;
1931
if (win_enabled)
1932
synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1933
else
1934
synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1935
}
1936
1937
static void speakup_bits(struct vc_data *vc)
1938
{
1939
int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1940
1941
if (spk_special_handler || val < 1 || val > 6) {
1942
synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1943
return;
1944
}
1945
pb_edit = &spk_punc_info[val];
1946
synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1947
spk_special_handler = edit_bits;
1948
}
1949
1950
static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1951
{
1952
static u_char goto_buf[8];
1953
static int num;
1954
int maxlen;
1955
char *cp;
1956
u16 wch;
1957
1958
if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1959
goto do_goto;
1960
if (type == KT_LATIN && ch == '\n')
1961
goto do_goto;
1962
if (type != 0)
1963
goto oops;
1964
if (ch == 8) {
1965
u16 wch;
1966
1967
if (num == 0)
1968
return -1;
1969
wch = goto_buf[--num];
1970
goto_buf[num] = '\0';
1971
spkup_write(&wch, 1);
1972
return 1;
1973
}
1974
if (ch < '+' || ch > 'y')
1975
goto oops;
1976
wch = ch;
1977
goto_buf[num++] = ch;
1978
goto_buf[num] = '\0';
1979
spkup_write(&wch, 1);
1980
maxlen = (*goto_buf >= '0') ? 3 : 4;
1981
if ((ch == '+' || ch == '-') && num == 1)
1982
return 1;
1983
if (ch >= '0' && ch <= '9' && num < maxlen)
1984
return 1;
1985
if (num < maxlen - 1 || num > maxlen)
1986
goto oops;
1987
if (ch < 'x' || ch > 'y') {
1988
oops:
1989
if (!spk_killed)
1990
synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1991
goto_buf[num = 0] = '\0';
1992
spk_special_handler = NULL;
1993
return 1;
1994
}
1995
1996
/* Do not replace with kstrtoul: here we need cp to be updated */
1997
goto_pos = simple_strtoul(goto_buf, &cp, 10);
1998
1999
if (*cp == 'x') {
2000
if (*goto_buf < '0')
2001
goto_pos += spk_x;
2002
else if (goto_pos > 0)
2003
goto_pos--;
2004
2005
if (goto_pos >= vc->vc_cols)
2006
goto_pos = vc->vc_cols - 1;
2007
goto_x = 1;
2008
} else {
2009
if (*goto_buf < '0')
2010
goto_pos += spk_y;
2011
else if (goto_pos > 0)
2012
goto_pos--;
2013
2014
if (goto_pos >= vc->vc_rows)
2015
goto_pos = vc->vc_rows - 1;
2016
goto_x = 0;
2017
}
2018
goto_buf[num = 0] = '\0';
2019
do_goto:
2020
spk_special_handler = NULL;
2021
spk_parked |= 0x01;
2022
if (goto_x) {
2023
spk_pos -= spk_x * 2;
2024
spk_x = goto_pos;
2025
spk_pos += goto_pos * 2;
2026
say_word(vc);
2027
} else {
2028
spk_y = goto_pos;
2029
spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
2030
say_line(vc);
2031
}
2032
return 1;
2033
}
2034
2035
static void speakup_goto(struct vc_data *vc)
2036
{
2037
if (spk_special_handler) {
2038
synth_printf("%s\n", spk_msg_get(MSG_ERROR));
2039
return;
2040
}
2041
synth_printf("%s\n", spk_msg_get(MSG_GOTO));
2042
spk_special_handler = handle_goto;
2043
}
2044
2045
static void speakup_help(struct vc_data *vc)
2046
{
2047
spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
2048
}
2049
2050
static void do_nothing(struct vc_data *vc)
2051
{
2052
return; /* flush done in do_spkup */
2053
}
2054
2055
static u_char key_speakup, spk_key_locked;
2056
2057
static void speakup_lock(struct vc_data *vc)
2058
{
2059
if (!spk_key_locked) {
2060
spk_key_locked = 16;
2061
key_speakup = 16;
2062
} else {
2063
spk_key_locked = 0;
2064
key_speakup = 0;
2065
}
2066
}
2067
2068
typedef void (*spkup_hand) (struct vc_data *);
2069
static spkup_hand spkup_handler[] = {
2070
/* must be ordered same as defines in speakup.h */
2071
do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2072
speakup_cut, speakup_paste, say_first_char, say_last_char,
2073
say_char, say_prev_char, say_next_char,
2074
say_word, say_prev_word, say_next_word,
2075
say_line, say_prev_line, say_next_line,
2076
top_edge, bottom_edge, left_edge, right_edge,
2077
spell_word, spell_word, say_screen,
2078
say_position, say_attributes,
2079
speakup_off, speakup_parked, say_line, /* this is for indent */
2080
say_from_top, say_to_bottom,
2081
say_from_left, say_to_right,
2082
say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2083
speakup_bits, speakup_bits, speakup_bits,
2084
speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2085
speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2086
};
2087
2088
static void do_spkup(struct vc_data *vc, u_char value)
2089
{
2090
if (spk_killed && value != SPEECH_KILL)
2091
return;
2092
spk_keydown = 0;
2093
spk_lastkey = 0;
2094
spk_shut_up &= 0xfe;
2095
this_speakup_key = value;
2096
if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2097
spk_do_flush();
2098
(*spkup_handler[value]) (vc);
2099
} else {
2100
if (inc_dec_var(value) < 0)
2101
bleep(9);
2102
}
2103
}
2104
2105
static const char *pad_chars = "0123456789+-*/\015,.?()";
2106
2107
static int
2108
speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2109
int up_flag)
2110
{
2111
unsigned long flags;
2112
int kh;
2113
u_char *key_info;
2114
u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2115
u_char shift_info, offset;
2116
int ret = 0;
2117
2118
if (!synth)
2119
return 0;
2120
2121
spin_lock_irqsave(&speakup_info.spinlock, flags);
2122
tty = vc->port.tty;
2123
if (type >= 0xf0)
2124
type -= 0xf0;
2125
if (type == KT_PAD &&
2126
(vt_get_leds(fg_console, VC_NUMLOCK))) {
2127
if (up_flag) {
2128
spk_keydown = 0;
2129
goto out;
2130
}
2131
value = pad_chars[value];
2132
spk_lastkey = value;
2133
spk_keydown++;
2134
spk_parked &= 0xfe;
2135
goto no_map;
2136
}
2137
if (keycode >= MAX_KEY)
2138
goto no_map;
2139
key_info = spk_our_keys[keycode];
2140
if (!key_info)
2141
goto no_map;
2142
/* Check valid read all mode keys */
2143
if ((cursor_track == read_all_mode) && (!up_flag)) {
2144
switch (value) {
2145
case KVAL(K_DOWN):
2146
case KVAL(K_UP):
2147
case KVAL(K_LEFT):
2148
case KVAL(K_RIGHT):
2149
case KVAL(K_PGUP):
2150
case KVAL(K_PGDN):
2151
break;
2152
default:
2153
stop_read_all(vc);
2154
break;
2155
}
2156
}
2157
shift_info = (shift_state & 0x0f) + key_speakup;
2158
offset = spk_shift_table[shift_info];
2159
if (offset) {
2160
new_key = key_info[offset];
2161
if (new_key) {
2162
ret = 1;
2163
if (new_key == SPK_KEY) {
2164
if (!spk_key_locked)
2165
key_speakup = (up_flag) ? 0 : 16;
2166
if (up_flag || spk_killed)
2167
goto out;
2168
spk_shut_up &= 0xfe;
2169
spk_do_flush();
2170
goto out;
2171
}
2172
if (up_flag)
2173
goto out;
2174
if (last_keycode == keycode &&
2175
time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2176
spk_close_press = 1;
2177
offset = spk_shift_table[shift_info + 32];
2178
/* double press? */
2179
if (offset && key_info[offset])
2180
new_key = key_info[offset];
2181
}
2182
last_keycode = keycode;
2183
last_spk_jiffy = jiffies;
2184
type = KT_SPKUP;
2185
value = new_key;
2186
}
2187
}
2188
no_map:
2189
if (type == KT_SPKUP && !spk_special_handler) {
2190
do_spkup(vc, new_key);
2191
spk_close_press = 0;
2192
ret = 1;
2193
goto out;
2194
}
2195
if (up_flag || spk_killed || type == KT_SHIFT)
2196
goto out;
2197
spk_shut_up &= 0xfe;
2198
kh = (value == KVAL(K_DOWN)) ||
2199
(value == KVAL(K_UP)) ||
2200
(value == KVAL(K_LEFT)) ||
2201
(value == KVAL(K_RIGHT));
2202
if ((cursor_track != read_all_mode) || !kh)
2203
if (!spk_no_intr)
2204
spk_do_flush();
2205
if (spk_special_handler) {
2206
if (type == KT_SPEC && value == 1) {
2207
value = '\n';
2208
type = KT_LATIN;
2209
} else if (type == KT_LETTER) {
2210
type = KT_LATIN;
2211
} else if (value == 0x7f) {
2212
value = 8; /* make del = backspace */
2213
}
2214
ret = (*spk_special_handler) (vc, type, value, keycode);
2215
spk_close_press = 0;
2216
if (ret < 0)
2217
bleep(9);
2218
goto out;
2219
}
2220
last_keycode = 0;
2221
out:
2222
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2223
return ret;
2224
}
2225
2226
static int keyboard_notifier_call(struct notifier_block *nb,
2227
unsigned long code, void *_param)
2228
{
2229
struct keyboard_notifier_param *param = _param;
2230
struct vc_data *vc = param->vc;
2231
int up = !param->down;
2232
int ret = NOTIFY_OK;
2233
static int keycode; /* to hold the current keycode */
2234
2235
in_keyboard_notifier = 1;
2236
2237
if (vc->vc_mode == KD_GRAPHICS)
2238
goto out;
2239
2240
/*
2241
* First, determine whether we are handling a fake keypress on
2242
* the current processor. If we are, then return NOTIFY_OK,
2243
* to pass the keystroke up the chain. This prevents us from
2244
* trying to take the Speakup lock while it is held by the
2245
* processor on which the simulated keystroke was generated.
2246
* Also, the simulated keystrokes should be ignored by Speakup.
2247
*/
2248
2249
if (speakup_fake_key_pressed())
2250
goto out;
2251
2252
switch (code) {
2253
case KBD_KEYCODE:
2254
/* speakup requires keycode and keysym currently */
2255
keycode = param->value;
2256
break;
2257
case KBD_UNBOUND_KEYCODE:
2258
/* not used yet */
2259
break;
2260
case KBD_UNICODE:
2261
/* not used yet */
2262
break;
2263
case KBD_KEYSYM:
2264
if (speakup_key(vc, param->shift, keycode, param->value, up))
2265
ret = NOTIFY_STOP;
2266
else if (KTYP(param->value) == KT_CUR)
2267
ret = pre_handle_cursor(vc, KVAL(param->value), up);
2268
break;
2269
case KBD_POST_KEYSYM:{
2270
unsigned char type = KTYP(param->value) - 0xf0;
2271
unsigned char val = KVAL(param->value);
2272
2273
switch (type) {
2274
case KT_SHIFT:
2275
do_handle_shift(vc, val, up);
2276
break;
2277
case KT_LATIN:
2278
case KT_LETTER:
2279
do_handle_latin(vc, val, up);
2280
break;
2281
case KT_CUR:
2282
do_handle_cursor(vc, val, up);
2283
break;
2284
case KT_SPEC:
2285
do_handle_spec(vc, val, up);
2286
break;
2287
}
2288
break;
2289
}
2290
}
2291
out:
2292
in_keyboard_notifier = 0;
2293
return ret;
2294
}
2295
2296
static int vt_notifier_call(struct notifier_block *nb,
2297
unsigned long code, void *_param)
2298
{
2299
struct vt_notifier_param *param = _param;
2300
struct vc_data *vc = param->vc;
2301
2302
switch (code) {
2303
case VT_ALLOCATE:
2304
if (vc->vc_mode == KD_TEXT)
2305
speakup_allocate(vc, GFP_ATOMIC);
2306
break;
2307
case VT_DEALLOCATE:
2308
speakup_deallocate(vc);
2309
break;
2310
case VT_WRITE:
2311
if (param->c == '\b') {
2312
speakup_bs(vc);
2313
} else {
2314
u16 d = param->c;
2315
2316
speakup_con_write(vc, &d, 1);
2317
}
2318
break;
2319
case VT_UPDATE:
2320
speakup_con_update(vc);
2321
break;
2322
}
2323
return NOTIFY_OK;
2324
}
2325
2326
/* called by: module_exit() */
2327
static void __exit speakup_exit(void)
2328
{
2329
int i;
2330
2331
unregister_keyboard_notifier(&keyboard_notifier_block);
2332
unregister_vt_notifier(&vt_notifier_block);
2333
speakup_unregister_devsynth();
2334
speakup_cancel_selection();
2335
speakup_cancel_paste();
2336
timer_delete_sync(&cursor_timer);
2337
kthread_stop(speakup_task);
2338
speakup_task = NULL;
2339
mutex_lock(&spk_mutex);
2340
synth_release();
2341
mutex_unlock(&spk_mutex);
2342
spk_ttyio_unregister_ldisc();
2343
2344
speakup_kobj_exit();
2345
2346
for (i = 0; i < MAX_NR_CONSOLES; i++)
2347
kfree(speakup_console[i]);
2348
2349
speakup_remove_virtual_keyboard();
2350
2351
for (i = 0; i < MAXVARS; i++)
2352
speakup_unregister_var(i);
2353
2354
for (i = 0; i < 256; i++) {
2355
if (spk_characters[i] != spk_default_chars[i])
2356
kfree(spk_characters[i]);
2357
}
2358
2359
spk_free_user_msgs();
2360
}
2361
2362
/* call by: module_init() */
2363
static int __init speakup_init(void)
2364
{
2365
int i;
2366
long err = 0;
2367
struct vc_data *vc = vc_cons[fg_console].d;
2368
struct var_t *var;
2369
2370
/* These first few initializations cannot fail. */
2371
spk_initialize_msgs(); /* Initialize arrays for i18n. */
2372
spk_reset_default_chars();
2373
spk_reset_default_chartab();
2374
spk_strlwr(synth_name);
2375
spk_vars[0].u.n.high = vc->vc_cols;
2376
for (var = spk_vars; var->var_id != MAXVARS; var++)
2377
speakup_register_var(var);
2378
for (var = synth_time_vars;
2379
(var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2380
speakup_register_var(var);
2381
for (i = 1; spk_punc_info[i].mask != 0; i++)
2382
spk_set_mask_bits(NULL, i, 2);
2383
2384
spk_set_key_info(spk_key_defaults, spk_key_buf);
2385
2386
/* From here on out, initializations can fail. */
2387
err = speakup_add_virtual_keyboard();
2388
if (err)
2389
goto error_virtkeyboard;
2390
2391
for (i = 0; i < MAX_NR_CONSOLES; i++)
2392
if (vc_cons[i].d) {
2393
err = speakup_allocate(vc_cons[i].d, GFP_KERNEL);
2394
if (err)
2395
goto error_kobjects;
2396
}
2397
2398
if (spk_quiet_boot)
2399
spk_shut_up |= 0x01;
2400
2401
err = speakup_kobj_init();
2402
if (err)
2403
goto error_kobjects;
2404
2405
spk_ttyio_register_ldisc();
2406
synth_init(synth_name);
2407
speakup_register_devsynth();
2408
/*
2409
* register_devsynth might fail, but this error is not fatal.
2410
* /dev/synth is an extra feature; the rest of Speakup
2411
* will work fine without it.
2412
*/
2413
2414
err = register_keyboard_notifier(&keyboard_notifier_block);
2415
if (err)
2416
goto error_kbdnotifier;
2417
err = register_vt_notifier(&vt_notifier_block);
2418
if (err)
2419
goto error_vtnotifier;
2420
2421
speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2422
2423
if (IS_ERR(speakup_task)) {
2424
err = PTR_ERR(speakup_task);
2425
goto error_task;
2426
}
2427
2428
set_user_nice(speakup_task, 10);
2429
wake_up_process(speakup_task);
2430
2431
pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2432
pr_info("synth name on entry is: %s\n", synth_name);
2433
goto out;
2434
2435
error_task:
2436
unregister_vt_notifier(&vt_notifier_block);
2437
2438
error_vtnotifier:
2439
unregister_keyboard_notifier(&keyboard_notifier_block);
2440
timer_delete(&cursor_timer);
2441
2442
error_kbdnotifier:
2443
speakup_unregister_devsynth();
2444
mutex_lock(&spk_mutex);
2445
synth_release();
2446
mutex_unlock(&spk_mutex);
2447
speakup_kobj_exit();
2448
2449
error_kobjects:
2450
for (i = 0; i < MAX_NR_CONSOLES; i++)
2451
kfree(speakup_console[i]);
2452
2453
speakup_remove_virtual_keyboard();
2454
2455
error_virtkeyboard:
2456
for (i = 0; i < MAXVARS; i++)
2457
speakup_unregister_var(i);
2458
2459
for (i = 0; i < 256; i++) {
2460
if (spk_characters[i] != spk_default_chars[i])
2461
kfree(spk_characters[i]);
2462
}
2463
2464
spk_free_user_msgs();
2465
2466
out:
2467
return err;
2468
}
2469
2470
module_param_named(bell_pos, spk_vars[BELL_POS_ID].u.n.default_val, int, 0444);
2471
module_param_named(spell_delay, spk_vars[SPELL_DELAY_ID].u.n.default_val, int, 0444);
2472
module_param_named(attrib_bleep, spk_vars[ATTRIB_BLEEP_ID].u.n.default_val, int, 0444);
2473
module_param_named(bleeps, spk_vars[BLEEPS_ID].u.n.default_val, int, 0444);
2474
module_param_named(bleep_time, spk_vars[BLEEP_TIME_ID].u.n.default_val, int, 0444);
2475
module_param_named(punc_level, spk_vars[PUNC_LEVEL_ID].u.n.default_val, int, 0444);
2476
module_param_named(reading_punc, spk_vars[READING_PUNC_ID].u.n.default_val, int, 0444);
2477
module_param_named(cursor_time, spk_vars[CURSOR_TIME_ID].u.n.default_val, int, 0444);
2478
module_param_named(say_control, spk_vars[SAY_CONTROL_ID].u.n.default_val, int, 0444);
2479
module_param_named(say_word_ctl, spk_vars[SAY_WORD_CTL_ID].u.n.default_val, int, 0444);
2480
module_param_named(no_interrupt, spk_vars[NO_INTERRUPT_ID].u.n.default_val, int, 0444);
2481
module_param_named(key_echo, spk_vars[KEY_ECHO_ID].u.n.default_val, int, 0444);
2482
module_param_named(cur_phonetic, spk_vars[CUR_PHONETIC_ID].u.n.default_val, int, 0444);
2483
2484
MODULE_PARM_DESC(bell_pos, "This works much like a typewriter bell. If for example 72 is echoed to bell_pos, it will beep the PC speaker when typing on a line past character 72.");
2485
MODULE_PARM_DESC(spell_delay, "This controls how fast a word is spelled when speakup's spell word review command is pressed.");
2486
MODULE_PARM_DESC(attrib_bleep, "Beeps the PC speaker when there is an attribute change such as background color when using speakup review commands. One = on, zero = off.");
2487
MODULE_PARM_DESC(bleeps, "This controls whether one hears beeps through the PC speaker when using speakup review commands.");
2488
MODULE_PARM_DESC(bleep_time, "This controls the duration of the PC speaker beeps speakup produces.");
2489
MODULE_PARM_DESC(punc_level, "Controls the level of punctuation spoken as the screen is displayed, not reviewed.");
2490
MODULE_PARM_DESC(reading_punc, "It controls the level of punctuation when reviewing the screen with speakup's screen review commands.");
2491
MODULE_PARM_DESC(cursor_time, "This controls cursor delay when using arrow keys.");
2492
MODULE_PARM_DESC(say_control, "This controls if speakup speaks shift, alt and control when those keys are pressed or not.");
2493
MODULE_PARM_DESC(say_word_ctl, "Sets the say_word_ctl on load.");
2494
MODULE_PARM_DESC(no_interrupt, "Controls if typing interrupts output from speakup.");
2495
MODULE_PARM_DESC(key_echo, "Controls if speakup speaks keys when they are typed. One = on zero = off or don't echo keys.");
2496
MODULE_PARM_DESC(cur_phonetic, "Controls if speakup speaks letters phonetically during navigation. One = on zero = off or don't speak phonetically.");
2497
2498
module_init(speakup_init);
2499
module_exit(speakup_exit);
2500
2501