// SPDX-License-Identifier: GPL-2.0+/* speakup.c * review functions for the speakup screen review package. * originally written by: Kirk Reiser and Andy Berdan. * * extensively modified by David Borowski. * ** Copyright (C) 1998 Kirk Reiser. * Copyright (C) 2003 David Borowski. */ #include <linux/kernel.h>#include <linux/vt.h>#include <linux/tty.h>#include <linux/mm.h> /* __get_free_page() and friends */#include <linux/vt_kern.h>#include <linux/ctype.h>#include <linux/selection.h>#include <linux/unistd.h>#include <linux/jiffies.h>#include <linux/kthread.h>#include <linux/keyboard.h> /* for KT_SHIFT */#include <linux/kbd_kern.h> /* for vc_kbd_* and friends */#include <linux/input.h>#include <linux/kmod.h> /* speakup_*_selection */#include <linux/module.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/types.h>#include <linux/consolemap.h> #include <linux/spinlock.h>#include <linux/notifier.h> #include <linux/uaccess.h> /* copy_from|to|user() and others */ #include "spk_priv.h"#include "speakup.h" #define MAX_DELAY msecs_to_jiffies(500)#define MINECHOCHAR SPACE MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");MODULE_DESCRIPTION("Speakup console speech");MODULE_LICENSE("GPL");MODULE_VERSION(SPEAKUP_VERSION); char *synth_name;module_param_named(synth, synth_name, charp, 0444);module_param_named(quiet, spk_quiet_boot, bool, 0444); MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found."); special_func spk_special_handler; short spk_pitch_shift, synth_flags;static u16 buf[256];int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;int spk_no_intr, spk_spell_delay;int spk_key_echo, spk_say_word_ctl;int spk_say_ctrl, spk_bell_pos;u16 spk_punc_mask;int spk_punc_level, spk_reading_punc;int spk_cur_phonetic;char spk_str_caps_start[MAXVARLEN + 1] = "\0";char spk_str_caps_stop[MAXVARLEN + 1] = "\0";char spk_str_pause[MAXVARLEN + 1] = "\0";bool spk_paused;const struct st_bits_data spk_punc_info[] = { {"none", "", 0}, {"some", "/$%&@", SOME}, {"most", "$%&#()=+*/@^<>|\\", MOST}, {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC}, {"delimiters", "", B_WDLM}, {"repeats", "()", CH_RPT}, {"extended numeric", "", B_EXNUM}, {"symbols", "", B_SYM}, {NULL, NULL}}; static char mark_cut_flag;#define MAX_KEY 160static u_char *spk_shift_table;u_char *spk_our_keys[MAX_KEY];u_char spk_key_buf[600];const u_char spk_key_defaults[] = {#include "speakupmap.h"}; /* cursor track modes, must be ordered same as cursor_msgs in enum msg_index_t */enum cursor_track { CT_Off = 0, CT_On, CT_Highlight, CT_Window, CT_Max, read_all_mode = CT_Max,}; /* Speakup Cursor Track Variables */static enum cursor_track cursor_track = 1, prev_cursor_track = 1; static struct tty_struct *tty; static void spkup_write(const u16 *in_buf, int count); static char *phonetic[] = { "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", "india", "juliett", "keelo", "leema", "mike", "november", "oscar", "papa", "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey", "x ray", "yankee", "zulu"}; /* array of 256 char pointers (one for each character description) * initialized to default_chars and user selectable via * /proc/speakup/characters */char *spk_characters[256]; char *spk_default_chars[256] = {/*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",/*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",/*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",/*024*/ "^x", "^y", "^z", "control", "control", "control", "control", "control",/*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and", "tick",/*040*/ "left paren", "right paren", "star", "plus", "comma", "dash", "dot", "slash",/*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",/*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",/*065*/ "EIGH", "B", "C", "D", "E", "F", "G",/*072*/ "H", "I", "J", "K", "L", "M", "N", "O",/*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",/*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket", "caret", "line",/*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",/*104*/ "h", "i", "j", "k", "l", "m", "n", "o",/*112*/ "p", "q", "r", "s", "t", "u", "v", "w",/*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",/*127*/ "del", "control", "control", "control", "control", "control", "control", "control", "control", "control", "control",/*138*/ "control", "control", "control", "control", "control", "control", "control", "control", "control", "control", "control", "control",/*150*/ "control", "control", "control", "control", "control", "control", "control", "control", "control", "control",/*160*/ "nbsp", "inverted bang",/*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",/*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",/*172*/ "not", "soft hyphen", "registered", "macron",/*176*/ "degrees", "plus or minus", "super two", "super three",/*180*/ "acute accent", "micro", "pilcrow", "middle dot",/*184*/ "cedilla", "super one", "male ordinal", "double right angle",/*188*/ "one quarter", "one half", "three quarters", "inverted question",/*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT", "A RING",/*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX", "E OOMLAUT",/*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH", "N TILDE",/*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",/*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE", "U CIRCUMFLEX",/*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",/*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",/*230*/ "ae", "c cidella", "e grave", "e acute",/*234*/ "e circumflex", "e oomlaut", "i grave", "i acute", "i circumflex",/*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute", "o circumflex",/*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave", "u acute",/* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"}; /* array of 256 u16 (one for each character) * initialized to default_chartab and user selectable via * /sys/module/speakup/parameters/chartab */u16 spk_chartab[256]; static u16 default_chartab[256] = { B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */ B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */ B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */ B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */ WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */ PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */ NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */ NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */ PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */ A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */ A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */ A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */ PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */ ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */ ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */ ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */ B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */ B_SYM, /* 135 */ B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */ B_CAPSYM, /* 143 */ B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */ B_SYM, /* 151 */ B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */ B_SYM, /* 159 */ WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */ B_SYM, /* 167 */ B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */ B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */ B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */ A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */ A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */ A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */ A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */ ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */ ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */ ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */ ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */}; struct task_struct *speakup_task;struct bleep spk_unprocessed_sound;static int spk_keydown;static u16 spk_lastkey;static u_char spk_close_press, keymap_flags;static u_char last_keycode, this_speakup_key;static u_long last_spk_jiffy; struct st_spk_t *speakup_console[MAX_NR_CONSOLES]; DEFINE_MUTEX(spk_mutex); static int keyboard_notifier_call(struct notifier_block *, unsigned long code, void *param); static struct notifier_block keyboard_notifier_block = { .notifier_call = keyboard_notifier_call,}; static int vt_notifier_call(struct notifier_block *, unsigned long code, void *param); static struct notifier_block vt_notifier_block = { .notifier_call = vt_notifier_call,}; static unsigned char get_attributes(struct vc_data *vc, u16 *pos){ pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true); return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8;} static void speakup_date(struct vc_data *vc){ spk_x = spk_cx = vc->state.x; spk_y = spk_cy = vc->state.y; spk_pos = spk_cp = vc->vc_pos; spk_old_attr = spk_attr; spk_attr = get_attributes(vc, (u16 *)spk_pos);} static void bleep(u16 val){ static const short vals[] = { 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659 }; short freq; int time = spk_bleep_time; freq = vals[val % 12]; if (val > 11) freq *= (1 << (val / 12)); spk_unprocessed_sound.freq = freq; spk_unprocessed_sound.jiffies = msecs_to_jiffies(time); spk_unprocessed_sound.active = 1; /* We can only have 1 active sound at a time. */} static void speakup_shut_up(struct vc_data *vc){ if (spk_killed) return; spk_shut_up |= 0x01; spk_parked &= 0xfe; speakup_date(vc); if (synth) spk_do_flush();} static void speech_kill(struct vc_data *vc){ char val = synth->is_alive(synth); if (val == 0) return; /* re-enables synth, if disabled */ if (val == 2 || spk_killed) { /* dead */ spk_shut_up &= ~0x40; synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE)); } else { synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP)); spk_shut_up |= 0x40; }} static void speakup_off(struct vc_data *vc){ if (spk_shut_up & 0x80) { spk_shut_up &= 0x7f; synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER)); } else { spk_shut_up |= 0x80; synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF)); } speakup_date(vc);} static void speakup_parked(struct vc_data *vc){ if (spk_parked & 0x80) { spk_parked = 0; synth_printf("%s\n", spk_msg_get(MSG_UNPARKED)); } else { spk_parked |= 0x80; synth_printf("%s\n", spk_msg_get(MSG_PARKED)); }} static void speakup_cut(struct vc_data *vc){ static const char err_buf[] = "set selection failed"; int ret; if (!mark_cut_flag) { mark_cut_flag = 1; spk_xs = (u16)spk_x; spk_ys = (u16)spk_y; spk_sel_cons = vc; synth_printf("%s\n", spk_msg_get(MSG_MARK)); return; } spk_xe = (u16)spk_x; spk_ye = (u16)spk_y; mark_cut_flag = 0; synth_printf("%s\n", spk_msg_get(MSG_CUT)); ret = speakup_set_selection(tty); switch (ret) { case 0: break; /* no error */ case -EFAULT: pr_warn("%sEFAULT\n", err_buf); break; case -EINVAL: pr_warn("%sEINVAL\n", err_buf); break; case -ENOMEM: pr_warn("%sENOMEM\n", err_buf); break; }} static void speakup_paste(struct vc_data *vc){ if (mark_cut_flag) { mark_cut_flag = 0; synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED)); } else { synth_printf("%s\n", spk_msg_get(MSG_PASTE)); speakup_paste_selection(tty); }} static void say_attributes(struct vc_data *vc){ int fg = spk_attr & 0x0f; int bg = spk_attr >> 4; synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg)); if (bg > 7) { synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING)); bg -= 8; } else { synth_printf(" %s ", spk_msg_get(MSG_ON)); } synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));} /* must be ordered same as edge_msgs in enum msg_index_t */enum edge { edge_none = 0, edge_top, edge_bottom, edge_left, edge_right, edge_quiet}; static void announce_edge(struct vc_data *vc, enum edge msg_id){ if (spk_bleeps & 1) bleep(spk_y); if ((spk_bleeps & 2) && (msg_id < edge_quiet)) synth_printf("%s\n", spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));} static void speak_char(u16 ch){ char *cp; struct var_t *direct = spk_get_var(DIRECT); if (ch >= 0x100 || (direct && direct->u.n.value)) { if (ch < 0x100 && IS_CHAR(ch, B_CAP)) { spk_pitch_shift++; synth_printf("%s", spk_str_caps_start); } synth_putwc_s(ch); if (ch < 0x100 && IS_CHAR(ch, B_CAP)) synth_printf("%s", spk_str_caps_stop); return; } cp = spk_characters[ch]; if (!cp) { pr_info("%s: cp == NULL!\n", __func__); return; } if (IS_CHAR(ch, B_CAP)) { spk_pitch_shift++; synth_printf("%s %s %s", spk_str_caps_start, cp, spk_str_caps_stop); } else { if (*cp == '^') { cp++; synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp); } else { synth_printf(" %s ", cp); } }} static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs){ u16 ch = ' '; if (vc && pos) { u16 w; u16 c; pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true); w = scr_readw(pos); c = w & 0xff; if (w & vc->vc_hi_font_mask) { w &= ~vc->vc_hi_font_mask; c |= 0x100; } ch = inverse_translate(vc, c, true); *attribs = (w & 0xff00) >> 8; } return ch;} static void say_char(struct vc_data *vc){ u16 ch; spk_old_attr = spk_attr; ch = get_char(vc, (u16 *)spk_pos, &spk_attr); if (spk_attr != spk_old_attr) { if (spk_attrib_bleep & 1) bleep(spk_y); if (spk_attrib_bleep & 2) say_attributes(vc); } speak_char(ch);} static void say_phonetic_char(struct vc_data *vc){ u16 ch; spk_old_attr = spk_attr; ch = get_char(vc, (u16 *)spk_pos, &spk_attr);Lines 1–500 of 2500. Load more
// SPDX-License-Identifier: GPL-2.0+ /* speakup.c * review functions for the speakup screen review package. * originally written by: Kirk Reiser and Andy Berdan. * * extensively modified by David Borowski. * ** Copyright (C) 1998 Kirk Reiser. * Copyright (C) 2003 David Borowski. */ #include <linux/kernel.h> #include <linux/vt.h> #include <linux/tty.h> #include <linux/mm.h> /* __get_free_page() and friends */ #include <linux/vt_kern.h> #include <linux/ctype.h> #include <linux/selection.h> #include <linux/unistd.h> #include <linux/jiffies.h> #include <linux/kthread.h> #include <linux/keyboard.h> /* for KT_SHIFT */ #include <linux/kbd_kern.h> /* for vc_kbd_* and friends */ #include <linux/input.h> #include <linux/kmod.h> /* speakup_*_selection */ #include <linux/module.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/types.h> #include <linux/consolemap.h> #include <linux/spinlock.h> #include <linux/notifier.h> #include <linux/uaccess.h> /* copy_from|to|user() and others */ #include "spk_priv.h" #include "speakup.h" #define MAX_DELAY msecs_to_jiffies(500) #define MINECHOCHAR SPACE MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>"); MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>"); MODULE_DESCRIPTION("Speakup console speech"); MODULE_LICENSE("GPL"); MODULE_VERSION(SPEAKUP_VERSION); char *synth_name; module_param_named(synth, synth_name, charp, 0444); module_param_named(quiet, spk_quiet_boot, bool, 0444); MODULE_PARM_DESC(synth, "Synth to start if speakup is built in."); MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found."); special_func spk_special_handler; short spk_pitch_shift, synth_flags; static u16 buf[256]; int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10; int spk_no_intr, spk_spell_delay; int spk_key_echo, spk_say_word_ctl; int spk_say_ctrl, spk_bell_pos; u16 spk_punc_mask; int spk_punc_level, spk_reading_punc; int spk_cur_phonetic; char spk_str_caps_start[MAXVARLEN + 1] = "\0"; char spk_str_caps_stop[MAXVARLEN + 1] = "\0"; char spk_str_pause[MAXVARLEN + 1] = "\0"; bool spk_paused; const struct st_bits_data spk_punc_info[] = { {"none", "", 0}, {"some", "/$%&@", SOME}, {"most", "$%&#()=+*/@^<>|\\", MOST}, {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC}, {"delimiters", "", B_WDLM}, {"repeats", "()", CH_RPT}, {"extended numeric", "", B_EXNUM}, {"symbols", "", B_SYM}, {NULL, NULL} }; static char mark_cut_flag; #define MAX_KEY 160 static u_char *spk_shift_table; u_char *spk_our_keys[MAX_KEY]; u_char spk_key_buf[600]; const u_char spk_key_defaults[] = { #include "speakupmap.h" }; /* cursor track modes, must be ordered same as cursor_msgs in enum msg_index_t */ enum cursor_track { CT_Off = 0, CT_On, CT_Highlight, CT_Window, CT_Max, read_all_mode = CT_Max, }; /* Speakup Cursor Track Variables */ static enum cursor_track cursor_track = 1, prev_cursor_track = 1; static struct tty_struct *tty; static void spkup_write(const u16 *in_buf, int count); static char *phonetic[] = { "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", "india", "juliett", "keelo", "leema", "mike", "november", "oscar", "papa", "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey", "x ray", "yankee", "zulu" }; /* array of 256 char pointers (one for each character description) * initialized to default_chars and user selectable via * /proc/speakup/characters */ char *spk_characters[256]; char *spk_default_chars[256] = { /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g", /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o", /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w", /*024*/ "^x", "^y", "^z", "control", "control", "control", "control", "control", /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and", "tick", /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash", "dot", "slash", /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at", /*065*/ "EIGH", "B", "C", "D", "E", "F", "G", /*072*/ "H", "I", "J", "K", "L", "M", "N", "O", /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X", /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket", "caret", "line", /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g", /*104*/ "h", "i", "j", "k", "l", "m", "n", "o", /*112*/ "p", "q", "r", "s", "t", "u", "v", "w", /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh", /*127*/ "del", "control", "control", "control", "control", "control", "control", "control", "control", "control", "control", /*138*/ "control", "control", "control", "control", "control", "control", "control", "control", "control", "control", "control", "control", /*150*/ "control", "control", "control", "control", "control", "control", "control", "control", "control", "control", /*160*/ "nbsp", "inverted bang", /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section", /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle", /*172*/ "not", "soft hyphen", "registered", "macron", /*176*/ "degrees", "plus or minus", "super two", "super three", /*180*/ "acute accent", "micro", "pilcrow", "middle dot", /*184*/ "cedilla", "super one", "male ordinal", "double right angle", /*188*/ "one quarter", "one half", "three quarters", "inverted question", /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT", "A RING", /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX", "E OOMLAUT", /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH", "N TILDE", /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT", /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE", "U CIRCUMFLEX", /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave", /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring", /*230*/ "ae", "c cidella", "e grave", "e acute", /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute", "i circumflex", /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute", "o circumflex", /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave", "u acute", /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut" }; /* array of 256 u16 (one for each character) * initialized to default_chartab and user selectable via * /sys/module/speakup/parameters/chartab */ u16 spk_chartab[256]; static u16 default_chartab[256] = { B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */ B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */ B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */ B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */ WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */ PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */ NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */ NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */ PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */ A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */ A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */ A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */ PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */ ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */ ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */ ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */ B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */ B_SYM, /* 135 */ B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */ B_CAPSYM, /* 143 */ B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */ B_SYM, /* 151 */ B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */ B_SYM, /* 159 */ WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */ B_SYM, /* 167 */ B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */ B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */ B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */ A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */ A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */ A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */ A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */ ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */ ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */ ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */ ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */ }; struct task_struct *speakup_task; struct bleep spk_unprocessed_sound; static int spk_keydown; static u16 spk_lastkey; static u_char spk_close_press, keymap_flags; static u_char last_keycode, this_speakup_key; static u_long last_spk_jiffy; struct st_spk_t *speakup_console[MAX_NR_CONSOLES]; DEFINE_MUTEX(spk_mutex); static int keyboard_notifier_call(struct notifier_block *, unsigned long code, void *param); static struct notifier_block keyboard_notifier_block = { .notifier_call = keyboard_notifier_call, }; static int vt_notifier_call(struct notifier_block *, unsigned long code, void *param); static struct notifier_block vt_notifier_block = { .notifier_call = vt_notifier_call, }; static unsigned char get_attributes(struct vc_data *vc, u16 *pos) { pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true); return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8; } static void speakup_date(struct vc_data *vc) { spk_x = spk_cx = vc->state.x; spk_y = spk_cy = vc->state.y; spk_pos = spk_cp = vc->vc_pos; spk_old_attr = spk_attr; spk_attr = get_attributes(vc, (u16 *)spk_pos); } static void bleep(u16 val) { static const short vals[] = { 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659 }; short freq; int time = spk_bleep_time; freq = vals[val % 12]; if (val > 11) freq *= (1 << (val / 12)); spk_unprocessed_sound.freq = freq; spk_unprocessed_sound.jiffies = msecs_to_jiffies(time); spk_unprocessed_sound.active = 1; /* We can only have 1 active sound at a time. */ } static void speakup_shut_up(struct vc_data *vc) { if (spk_killed) return; spk_shut_up |= 0x01; spk_parked &= 0xfe; speakup_date(vc); if (synth) spk_do_flush(); } static void speech_kill(struct vc_data *vc) { char val = synth->is_alive(synth); if (val == 0) return; /* re-enables synth, if disabled */ if (val == 2 || spk_killed) { /* dead */ spk_shut_up &= ~0x40; synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE)); } else { synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP)); spk_shut_up |= 0x40; } } static void speakup_off(struct vc_data *vc) { if (spk_shut_up & 0x80) { spk_shut_up &= 0x7f; synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER)); } else { spk_shut_up |= 0x80; synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF)); } speakup_date(vc); } static void speakup_parked(struct vc_data *vc) { if (spk_parked & 0x80) { spk_parked = 0; synth_printf("%s\n", spk_msg_get(MSG_UNPARKED)); } else { spk_parked |= 0x80; synth_printf("%s\n", spk_msg_get(MSG_PARKED)); } } static void speakup_cut(struct vc_data *vc) { static const char err_buf[] = "set selection failed"; int ret; if (!mark_cut_flag) { mark_cut_flag = 1; spk_xs = (u16)spk_x; spk_ys = (u16)spk_y; spk_sel_cons = vc; synth_printf("%s\n", spk_msg_get(MSG_MARK)); return; } spk_xe = (u16)spk_x; spk_ye = (u16)spk_y; mark_cut_flag = 0; synth_printf("%s\n", spk_msg_get(MSG_CUT)); ret = speakup_set_selection(tty); switch (ret) { case 0: break; /* no error */ case -EFAULT: pr_warn("%sEFAULT\n", err_buf); break; case -EINVAL: pr_warn("%sEINVAL\n", err_buf); break; case -ENOMEM: pr_warn("%sENOMEM\n", err_buf); break; } } static void speakup_paste(struct vc_data *vc) { if (mark_cut_flag) { mark_cut_flag = 0; synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED)); } else { synth_printf("%s\n", spk_msg_get(MSG_PASTE)); speakup_paste_selection(tty); } } static void say_attributes(struct vc_data *vc) { int fg = spk_attr & 0x0f; int bg = spk_attr >> 4; synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg)); if (bg > 7) { synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING)); bg -= 8; } else { synth_printf(" %s ", spk_msg_get(MSG_ON)); } synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg)); } /* must be ordered same as edge_msgs in enum msg_index_t */ enum edge { edge_none = 0, edge_top, edge_bottom, edge_left, edge_right, edge_quiet }; static void announce_edge(struct vc_data *vc, enum edge msg_id) { if (spk_bleeps & 1) bleep(spk_y); if ((spk_bleeps & 2) && (msg_id < edge_quiet)) synth_printf("%s\n", spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1)); } static void speak_char(u16 ch) { char *cp; struct var_t *direct = spk_get_var(DIRECT); if (ch >= 0x100 || (direct && direct->u.n.value)) { if (ch < 0x100 && IS_CHAR(ch, B_CAP)) { spk_pitch_shift++; synth_printf("%s", spk_str_caps_start); } synth_putwc_s(ch); if (ch < 0x100 && IS_CHAR(ch, B_CAP)) synth_printf("%s", spk_str_caps_stop); return; } cp = spk_characters[ch]; if (!cp) { pr_info("%s: cp == NULL!\n", __func__); return; } if (IS_CHAR(ch, B_CAP)) { spk_pitch_shift++; synth_printf("%s %s %s", spk_str_caps_start, cp, spk_str_caps_stop); } else { if (*cp == '^') { cp++; synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp); } else { synth_printf(" %s ", cp); } } } static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs) { u16 ch = ' '; if (vc && pos) { u16 w; u16 c; pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true); w = scr_readw(pos); c = w & 0xff; if (w & vc->vc_hi_font_mask) { w &= ~vc->vc_hi_font_mask; c |= 0x100; } ch = inverse_translate(vc, c, true); *attribs = (w & 0xff00) >> 8; } return ch; } static void say_char(struct vc_data *vc) { u16 ch; spk_old_attr = spk_attr; ch = get_char(vc, (u16 *)spk_pos, &spk_attr); if (spk_attr != spk_old_attr) { if (spk_attrib_bleep & 1) bleep(spk_y); if (spk_attrib_bleep & 2) say_attributes(vc); } speak_char(ch); } static void say_phonetic_char(struct vc_data *vc) { u16 ch; spk_old_attr = spk_attr; ch = get_char(vc, (u16 *)spk_pos, &spk_attr);