123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457 |
- // 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 <[email protected]>");
- MODULE_AUTHOR("Daniel Drake <[email protected]>");
- 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;
- short spk_punc_mask;
- int spk_punc_level, spk_reading_punc;
- 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 u_short (one for each character)
- * initialized to default_chartab and user selectable via
- * /sys/module/speakup/parameters/chartab
- */
- u_short spk_chartab[256];
- static u_short 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, (u_short *)spk_pos);
- }
- static void bleep(u_short 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 = (u_short)spk_x;
- spk_ys = (u_short)spk_y;
- spk_sel_cons = vc;
- synth_printf("%s\n", spk_msg_get(MSG_MARK));
- return;
- }
- spk_xe = (u_short)spk_x;
- spk_ye = (u_short)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, (u_short *)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, (u_short *)spk_pos, &spk_attr);
- if (ch <= 0x7f && isalpha(ch)) {
- ch &= 0x1f;
- synth_printf("%s\n", phonetic[--ch]);
- } else {
- if (ch < 0x100 && IS_CHAR(ch, B_NUM))
- synth_printf("%s ", spk_msg_get(MSG_NUMBER));
- speak_char(ch);
- }
- }
- static void say_prev_char(struct vc_data *vc)
- {
- spk_parked |= 0x01;
- if (spk_x == 0) {
- announce_edge(vc, edge_left);
- return;
- }
- spk_x--;
- spk_pos -= 2;
- say_char(vc);
- }
- static void say_next_char(struct vc_data *vc)
- {
- spk_parked |= 0x01;
- if (spk_x == vc->vc_cols - 1) {
- announce_edge(vc, edge_right);
- return;
- }
- spk_x++;
- spk_pos += 2;
- say_char(vc);
- }
- /* get_word - will first check to see if the character under the
- * reading cursor is a space and if spk_say_word_ctl is true it will
- * return the word space. If spk_say_word_ctl is not set it will check to
- * see if there is a word starting on the next position to the right
- * and return that word if it exists. If it does not exist it will
- * move left to the beginning of any previous word on the line or the
- * beginning off the line whichever comes first..
- */
- static u_long get_word(struct vc_data *vc)
- {
- u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
- u16 ch;
- u16 attr_ch;
- u_char temp;
- spk_old_attr = spk_attr;
- ch = get_char(vc, (u_short *)tmp_pos, &temp);
- /* decided to take out the sayword if on a space (mis-information */
- if (spk_say_word_ctl && ch == SPACE) {
- *buf = '\0';
- synth_printf("%s\n", spk_msg_get(MSG_SPACE));
- return 0;
- } else if (tmpx < vc->vc_cols - 2 &&
- (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
- get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) {
- tmp_pos += 2;
- tmpx++;
- } else {
- while (tmpx > 0) {
- ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
- if ((ch == SPACE || ch == 0 ||
- (ch < 0x100 && IS_WDLM(ch))) &&
- get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
- break;
- tmp_pos -= 2;
- tmpx--;
- }
- }
- attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
- buf[cnt++] = attr_ch;
- while (tmpx < vc->vc_cols - 1) {
- tmp_pos += 2;
- tmpx++;
- ch = get_char(vc, (u_short *)tmp_pos, &temp);
- if (ch == SPACE || ch == 0 ||
- (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
- ch > SPACE))
- break;
- buf[cnt++] = ch;
- }
- buf[cnt] = '\0';
- return cnt;
- }
- static void say_word(struct vc_data *vc)
- {
- u_long cnt = get_word(vc);
- u_short saved_punc_mask = spk_punc_mask;
- if (cnt == 0)
- return;
- spk_punc_mask = PUNC;
- buf[cnt++] = SPACE;
- spkup_write(buf, cnt);
- spk_punc_mask = saved_punc_mask;
- }
- static void say_prev_word(struct vc_data *vc)
- {
- u_char temp;
- u16 ch;
- enum edge edge_said = edge_none;
- u_short last_state = 0, state = 0;
- spk_parked |= 0x01;
- if (spk_x == 0) {
- if (spk_y == 0) {
- announce_edge(vc, edge_top);
- return;
- }
- spk_y--;
- spk_x = vc->vc_cols;
- edge_said = edge_quiet;
- }
- while (1) {
- if (spk_x == 0) {
- if (spk_y == 0) {
- edge_said = edge_top;
- break;
- }
- if (edge_said != edge_quiet)
- edge_said = edge_left;
- if (state > 0)
- break;
- spk_y--;
- spk_x = vc->vc_cols - 1;
- } else {
- spk_x--;
- }
- spk_pos -= 2;
- ch = get_char(vc, (u_short *)spk_pos, &temp);
- if (ch == SPACE || ch == 0)
- state = 0;
- else if (ch < 0x100 && IS_WDLM(ch))
- state = 1;
- else
- state = 2;
- if (state < last_state) {
- spk_pos += 2;
- spk_x++;
- break;
- }
- last_state = state;
- }
- if (spk_x == 0 && edge_said == edge_quiet)
- edge_said = edge_left;
- if (edge_said > edge_none && edge_said < edge_quiet)
- announce_edge(vc, edge_said);
- say_word(vc);
- }
- static void say_next_word(struct vc_data *vc)
- {
- u_char temp;
- u16 ch;
- enum edge edge_said = edge_none;
- u_short last_state = 2, state = 0;
- spk_parked |= 0x01;
- if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
- announce_edge(vc, edge_bottom);
- return;
- }
- while (1) {
- ch = get_char(vc, (u_short *)spk_pos, &temp);
- if (ch == SPACE || ch == 0)
- state = 0;
- else if (ch < 0x100 && IS_WDLM(ch))
- state = 1;
- else
- state = 2;
- if (state > last_state)
- break;
- if (spk_x >= vc->vc_cols - 1) {
- if (spk_y == vc->vc_rows - 1) {
- edge_said = edge_bottom;
- break;
- }
- state = 0;
- spk_y++;
- spk_x = 0;
- edge_said = edge_right;
- } else {
- spk_x++;
- }
- spk_pos += 2;
- last_state = state;
- }
- if (edge_said > edge_none)
- announce_edge(vc, edge_said);
- say_word(vc);
- }
- static void spell_word(struct vc_data *vc)
- {
- static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
- u16 *cp = buf;
- char *cp1;
- char *str_cap = spk_str_caps_stop;
- char *last_cap = spk_str_caps_stop;
- struct var_t *direct = spk_get_var(DIRECT);
- u16 ch;
- if (!get_word(vc))
- return;
- while ((ch = *cp)) {
- if (cp != buf)
- synth_printf(" %s ", delay_str[spk_spell_delay]);
- /* FIXME: Non-latin1 considered as lower case */
- if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
- str_cap = spk_str_caps_start;
- if (*spk_str_caps_stop)
- spk_pitch_shift++;
- else /* synth has no pitch */
- last_cap = spk_str_caps_stop;
- } else {
- str_cap = spk_str_caps_stop;
- }
- if (str_cap != last_cap) {
- synth_printf("%s", str_cap);
- last_cap = str_cap;
- }
- if (ch >= 0x100 || (direct && direct->u.n.value)) {
- synth_putwc_s(ch);
- } else if (this_speakup_key == SPELL_PHONETIC &&
- ch <= 0x7f && isalpha(ch)) {
- ch &= 0x1f;
- cp1 = phonetic[--ch];
- synth_printf("%s", cp1);
- } else {
- cp1 = spk_characters[ch];
- if (*cp1 == '^') {
- synth_printf("%s", spk_msg_get(MSG_CTRL));
- cp1++;
- }
- synth_printf("%s", cp1);
- }
- cp++;
- }
- if (str_cap != spk_str_caps_stop)
- synth_printf("%s", spk_str_caps_stop);
- }
- static int get_line(struct vc_data *vc)
- {
- u_long tmp = spk_pos - (spk_x * 2);
- int i = 0;
- u_char tmp2;
- spk_old_attr = spk_attr;
- spk_attr = get_attributes(vc, (u_short *)spk_pos);
- for (i = 0; i < vc->vc_cols; i++) {
- buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
- tmp += 2;
- }
- for (--i; i >= 0; i--)
- if (buf[i] != SPACE)
- break;
- return ++i;
- }
- static void say_line(struct vc_data *vc)
- {
- int i = get_line(vc);
- u16 *cp;
- u_short saved_punc_mask = spk_punc_mask;
- if (i == 0) {
- synth_printf("%s\n", spk_msg_get(MSG_BLANK));
- return;
- }
- buf[i++] = '\n';
- if (this_speakup_key == SAY_LINE_INDENT) {
- cp = buf;
- while (*cp == SPACE)
- cp++;
- synth_printf("%zd, ", (cp - buf) + 1);
- }
- spk_punc_mask = spk_punc_masks[spk_reading_punc];
- spkup_write(buf, i);
- spk_punc_mask = saved_punc_mask;
- }
- static void say_prev_line(struct vc_data *vc)
- {
- spk_parked |= 0x01;
- if (spk_y == 0) {
- announce_edge(vc, edge_top);
- return;
- }
- spk_y--;
- spk_pos -= vc->vc_size_row;
- say_line(vc);
- }
- static void say_next_line(struct vc_data *vc)
- {
- spk_parked |= 0x01;
- if (spk_y == vc->vc_rows - 1) {
- announce_edge(vc, edge_bottom);
- return;
- }
- spk_y++;
- spk_pos += vc->vc_size_row;
- say_line(vc);
- }
- static int say_from_to(struct vc_data *vc, u_long from, u_long to,
- int read_punc)
- {
- int i = 0;
- u_char tmp;
- u_short saved_punc_mask = spk_punc_mask;
- spk_old_attr = spk_attr;
- spk_attr = get_attributes(vc, (u_short *)from);
- while (from < to) {
- buf[i++] = get_char(vc, (u_short *)from, &tmp);
- from += 2;
- if (i >= vc->vc_size_row)
- break;
- }
- for (--i; i >= 0; i--)
- if (buf[i] != SPACE)
- break;
- buf[++i] = SPACE;
- buf[++i] = '\0';
- if (i < 1)
- return i;
- if (read_punc)
- spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
- spkup_write(buf, i);
- if (read_punc)
- spk_punc_mask = saved_punc_mask;
- return i - 1;
- }
- static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
- int read_punc)
- {
- u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
- u_long end = start + (to * 2);
- start += from * 2;
- if (say_from_to(vc, start, end, read_punc) <= 0)
- if (cursor_track != read_all_mode)
- synth_printf("%s\n", spk_msg_get(MSG_BLANK));
- }
- /* Sentence Reading Commands */
- static int currsentence;
- static int numsentences[2];
- static u16 *sentbufend[2];
- static u16 *sentmarks[2][10];
- static int currbuf;
- static int bn;
- static u16 sentbuf[2][256];
- static int say_sentence_num(int num, int prev)
- {
- bn = currbuf;
- currsentence = num + 1;
- if (prev && --bn == -1)
- bn = 1;
- if (num > numsentences[bn])
- return 0;
- spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
- return 1;
- }
- static int get_sentence_buf(struct vc_data *vc, int read_punc)
- {
- u_long start, end;
- int i, bn;
- u_char tmp;
- currbuf++;
- if (currbuf == 2)
- currbuf = 0;
- bn = currbuf;
- start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
- end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
- numsentences[bn] = 0;
- sentmarks[bn][0] = &sentbuf[bn][0];
- i = 0;
- spk_old_attr = spk_attr;
- spk_attr = get_attributes(vc, (u_short *)start);
- while (start < end) {
- sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
- if (i > 0) {
- if (sentbuf[bn][i] == SPACE &&
- sentbuf[bn][i - 1] == '.' &&
- numsentences[bn] < 9) {
- /* Sentence Marker */
- numsentences[bn]++;
- sentmarks[bn][numsentences[bn]] =
- &sentbuf[bn][i];
- }
- }
- i++;
- start += 2;
- if (i >= vc->vc_size_row)
- break;
- }
- for (--i; i >= 0; i--)
- if (sentbuf[bn][i] != SPACE)
- break;
- if (i < 1)
- return -1;
- sentbuf[bn][++i] = SPACE;
- sentbuf[bn][++i] = '\0';
- sentbufend[bn] = &sentbuf[bn][i];
- return numsentences[bn];
- }
- static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
- {
- u_long start = vc->vc_origin, end;
- if (from > 0)
- start += from * vc->vc_size_row;
- if (to > vc->vc_rows)
- to = vc->vc_rows;
- end = vc->vc_origin + (to * vc->vc_size_row);
- for (from = start; from < end; from = to) {
- to = from + vc->vc_size_row;
- say_from_to(vc, from, to, 1);
- }
- }
- static void say_screen(struct vc_data *vc)
- {
- say_screen_from_to(vc, 0, vc->vc_rows);
- }
- static void speakup_win_say(struct vc_data *vc)
- {
- u_long start, end, from, to;
- if (win_start < 2) {
- synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
- return;
- }
- start = vc->vc_origin + (win_top * vc->vc_size_row);
- end = vc->vc_origin + (win_bottom * vc->vc_size_row);
- while (start <= end) {
- from = start + (win_left * 2);
- to = start + (win_right * 2);
- say_from_to(vc, from, to, 1);
- start += vc->vc_size_row;
- }
- }
- static void top_edge(struct vc_data *vc)
- {
- spk_parked |= 0x01;
- spk_pos = vc->vc_origin + 2 * spk_x;
- spk_y = 0;
- say_line(vc);
- }
- static void bottom_edge(struct vc_data *vc)
- {
- spk_parked |= 0x01;
- spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
- spk_y = vc->vc_rows - 1;
- say_line(vc);
- }
- static void left_edge(struct vc_data *vc)
- {
- spk_parked |= 0x01;
- spk_pos -= spk_x * 2;
- spk_x = 0;
- say_char(vc);
- }
- static void right_edge(struct vc_data *vc)
- {
- spk_parked |= 0x01;
- spk_pos += (vc->vc_cols - spk_x - 1) * 2;
- spk_x = vc->vc_cols - 1;
- say_char(vc);
- }
- static void say_first_char(struct vc_data *vc)
- {
- int i, len = get_line(vc);
- u16 ch;
- spk_parked |= 0x01;
- if (len == 0) {
- synth_printf("%s\n", spk_msg_get(MSG_BLANK));
- return;
- }
- for (i = 0; i < len; i++)
- if (buf[i] != SPACE)
- break;
- ch = buf[i];
- spk_pos -= (spk_x - i) * 2;
- spk_x = i;
- synth_printf("%d, ", ++i);
- speak_char(ch);
- }
- static void say_last_char(struct vc_data *vc)
- {
- int len = get_line(vc);
- u16 ch;
- spk_parked |= 0x01;
- if (len == 0) {
- synth_printf("%s\n", spk_msg_get(MSG_BLANK));
- return;
- }
- ch = buf[--len];
- spk_pos -= (spk_x - len) * 2;
- spk_x = len;
- synth_printf("%d, ", ++len);
- speak_char(ch);
- }
- static void say_position(struct vc_data *vc)
- {
- synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
- vc->vc_num + 1);
- synth_printf("\n");
- }
- /* Added by brianb */
- static void say_char_num(struct vc_data *vc)
- {
- u_char tmp;
- u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);
- synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
- }
- /* these are stub functions to keep keyboard.c happy. */
- static void say_from_top(struct vc_data *vc)
- {
- say_screen_from_to(vc, 0, spk_y);
- }
- static void say_to_bottom(struct vc_data *vc)
- {
- say_screen_from_to(vc, spk_y, vc->vc_rows);
- }
- static void say_from_left(struct vc_data *vc)
- {
- say_line_from_to(vc, 0, spk_x, 1);
- }
- static void say_to_right(struct vc_data *vc)
- {
- say_line_from_to(vc, spk_x, vc->vc_cols, 1);
- }
- /* end of stub functions. */
- static void spkup_write(const u16 *in_buf, int count)
- {
- static int rep_count;
- static u16 ch = '\0', old_ch = '\0';
- static u_short char_type, last_type;
- int in_count = count;
- spk_keydown = 0;
- while (count--) {
- if (cursor_track == read_all_mode) {
- /* Insert Sentence Index */
- if ((in_buf == sentmarks[bn][currsentence]) &&
- (currsentence <= numsentences[bn]))
- synth_insert_next_index(currsentence++);
- }
- ch = *in_buf++;
- if (ch < 0x100)
- char_type = spk_chartab[ch];
- else
- char_type = ALPHA;
- if (ch == old_ch && !(char_type & B_NUM)) {
- if (++rep_count > 2)
- continue;
- } else {
- if ((last_type & CH_RPT) && rep_count > 2) {
- synth_printf(" ");
- synth_printf(spk_msg_get(MSG_REPEAT_DESC),
- ++rep_count);
- synth_printf(" ");
- }
- rep_count = 0;
- }
- if (ch == spk_lastkey) {
- rep_count = 0;
- if (spk_key_echo == 1 && ch >= MINECHOCHAR)
- speak_char(ch);
- } else if (char_type & B_ALPHA) {
- if ((synth_flags & SF_DEC) && (last_type & PUNC))
- synth_buffer_add(SPACE);
- synth_putwc_s(ch);
- } else if (char_type & B_NUM) {
- rep_count = 0;
- synth_putwc_s(ch);
- } else if (char_type & spk_punc_mask) {
- speak_char(ch);
- char_type &= ~PUNC; /* for dec nospell processing */
- } else if (char_type & SYNTH_OK) {
- /* these are usually puncts like . and , which synth
- * needs for expression.
- * suppress multiple to get rid of long pauses and
- * clear repeat count
- * so if someone has
- * repeats on you don't get nothing repeated count
- */
- if (ch != old_ch)
- synth_putwc_s(ch);
- else
- rep_count = 0;
- } else {
- /* send space and record position, if next is num overwrite space */
- if (old_ch != ch)
- synth_buffer_add(SPACE);
- else
- rep_count = 0;
- }
- old_ch = ch;
- last_type = char_type;
- }
- spk_lastkey = 0;
- if (in_count > 2 && rep_count > 2) {
- if (last_type & CH_RPT) {
- synth_printf(" ");
- synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
- ++rep_count);
- synth_printf(" ");
- }
- rep_count = 0;
- }
- }
- static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
- static void read_all_doc(struct vc_data *vc);
- static void cursor_done(struct timer_list *unused);
- static DEFINE_TIMER(cursor_timer, cursor_done);
- static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
- {
- unsigned long flags;
- if (!synth || up_flag || spk_killed)
- return;
- spin_lock_irqsave(&speakup_info.spinlock, flags);
- if (cursor_track == read_all_mode) {
- switch (value) {
- case KVAL(K_SHIFT):
- del_timer(&cursor_timer);
- spk_shut_up &= 0xfe;
- spk_do_flush();
- read_all_doc(vc);
- break;
- case KVAL(K_CTRL):
- del_timer(&cursor_timer);
- cursor_track = prev_cursor_track;
- spk_shut_up &= 0xfe;
- spk_do_flush();
- break;
- }
- } else {
- spk_shut_up &= 0xfe;
- spk_do_flush();
- }
- if (spk_say_ctrl && value < NUM_CTL_LABELS)
- synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- }
- static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
- {
- unsigned long flags;
- spin_lock_irqsave(&speakup_info.spinlock, flags);
- if (up_flag) {
- spk_lastkey = 0;
- spk_keydown = 0;
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- return;
- }
- if (!synth || spk_killed) {
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- return;
- }
- spk_shut_up &= 0xfe;
- spk_lastkey = value;
- spk_keydown++;
- spk_parked &= 0xfe;
- if (spk_key_echo == 2 && value >= MINECHOCHAR)
- speak_char(value);
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- }
- int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
- {
- int i = 0, states, key_data_len;
- const u_char *cp = key_info;
- u_char *cp1 = k_buffer;
- u_char ch, version, num_keys;
- version = *cp++;
- if (version != KEY_MAP_VER) {
- pr_debug("version found %d should be %d\n",
- version, KEY_MAP_VER);
- return -EINVAL;
- }
- num_keys = *cp;
- states = (int)cp[1];
- key_data_len = (states + 1) * (num_keys + 1);
- if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
- pr_debug("too many key_infos (%d over %u)\n",
- key_data_len + SHIFT_TBL_SIZE + 4,
- (unsigned int)(sizeof(spk_key_buf)));
- return -EINVAL;
- }
- memset(k_buffer, 0, SHIFT_TBL_SIZE);
- memset(spk_our_keys, 0, sizeof(spk_our_keys));
- spk_shift_table = k_buffer;
- spk_our_keys[0] = spk_shift_table;
- cp1 += SHIFT_TBL_SIZE;
- memcpy(cp1, cp, key_data_len + 3);
- /* get num_keys, states and data */
- cp1 += 2; /* now pointing at shift states */
- for (i = 1; i <= states; i++) {
- ch = *cp1++;
- if (ch >= SHIFT_TBL_SIZE) {
- pr_debug("(%d) not valid shift state (max_allowed = %d)\n",
- ch, SHIFT_TBL_SIZE);
- return -EINVAL;
- }
- spk_shift_table[ch] = i;
- }
- keymap_flags = *cp1++;
- while ((ch = *cp1)) {
- if (ch >= MAX_KEY) {
- pr_debug("(%d), not valid key, (max_allowed = %d)\n",
- ch, MAX_KEY);
- return -EINVAL;
- }
- spk_our_keys[ch] = cp1;
- cp1 += states + 1;
- }
- return 0;
- }
- static struct var_t spk_vars[] = {
- /* bell must be first to set high limit */
- {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
- {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
- {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
- {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
- {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
- {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
- {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
- {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
- {SAY_CONTROL, TOGGLE_0},
- {SAY_WORD_CTL, TOGGLE_0},
- {NO_INTERRUPT, TOGGLE_0},
- {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
- V_LAST_VAR
- };
- static void toggle_cursoring(struct vc_data *vc)
- {
- if (cursor_track == read_all_mode)
- cursor_track = prev_cursor_track;
- if (++cursor_track >= CT_Max)
- cursor_track = 0;
- synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
- }
- void spk_reset_default_chars(void)
- {
- int i;
- /* First, free any non-default */
- for (i = 0; i < 256; i++) {
- if (spk_characters[i] &&
- (spk_characters[i] != spk_default_chars[i]))
- kfree(spk_characters[i]);
- }
- memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
- }
- void spk_reset_default_chartab(void)
- {
- memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
- }
- static const struct st_bits_data *pb_edit;
- static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
- {
- short mask = pb_edit->mask, ch_type = spk_chartab[ch];
- if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
- return -1;
- if (ch == SPACE) {
- synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
- spk_special_handler = NULL;
- return 1;
- }
- if (mask < PUNC && !(ch_type & PUNC))
- return -1;
- spk_chartab[ch] ^= mask;
- speak_char(ch);
- synth_printf(" %s\n",
- (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
- spk_msg_get(MSG_OFF));
- return 1;
- }
- /* Allocation concurrency is protected by the console semaphore */
- static int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags)
- {
- int vc_num;
- vc_num = vc->vc_num;
- if (!speakup_console[vc_num]) {
- speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
- gfp_flags);
- if (!speakup_console[vc_num])
- return -ENOMEM;
- speakup_date(vc);
- } else if (!spk_parked) {
- speakup_date(vc);
- }
- return 0;
- }
- static void speakup_deallocate(struct vc_data *vc)
- {
- int vc_num;
- vc_num = vc->vc_num;
- kfree(speakup_console[vc_num]);
- speakup_console[vc_num] = NULL;
- }
- enum read_all_command {
- RA_NEXT_SENT = KVAL(K_DOWN)+1,
- RA_PREV_LINE = KVAL(K_LEFT)+1,
- RA_NEXT_LINE = KVAL(K_RIGHT)+1,
- RA_PREV_SENT = KVAL(K_UP)+1,
- RA_DOWN_ARROW,
- RA_TIMER,
- RA_FIND_NEXT_SENT,
- RA_FIND_PREV_SENT,
- };
- static u_char is_cursor;
- static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
- static int cursor_con;
- static void reset_highlight_buffers(struct vc_data *);
- static enum read_all_command read_all_key;
- static int in_keyboard_notifier;
- static void start_read_all_timer(struct vc_data *vc, enum read_all_command command);
- static void kbd_fakekey2(struct vc_data *vc, enum read_all_command command)
- {
- del_timer(&cursor_timer);
- speakup_fake_down_arrow();
- start_read_all_timer(vc, command);
- }
- static void read_all_doc(struct vc_data *vc)
- {
- if ((vc->vc_num != fg_console) || !synth || spk_shut_up)
- return;
- if (!synth_supports_indexing())
- return;
- if (cursor_track != read_all_mode)
- prev_cursor_track = cursor_track;
- cursor_track = read_all_mode;
- spk_reset_index_count(0);
- if (get_sentence_buf(vc, 0) == -1) {
- del_timer(&cursor_timer);
- if (!in_keyboard_notifier)
- speakup_fake_down_arrow();
- start_read_all_timer(vc, RA_DOWN_ARROW);
- } else {
- say_sentence_num(0, 0);
- synth_insert_next_index(0);
- start_read_all_timer(vc, RA_TIMER);
- }
- }
- static void stop_read_all(struct vc_data *vc)
- {
- del_timer(&cursor_timer);
- cursor_track = prev_cursor_track;
- spk_shut_up &= 0xfe;
- spk_do_flush();
- }
- static void start_read_all_timer(struct vc_data *vc, enum read_all_command command)
- {
- struct var_t *cursor_timeout;
- cursor_con = vc->vc_num;
- read_all_key = command;
- cursor_timeout = spk_get_var(CURSOR_TIME);
- mod_timer(&cursor_timer,
- jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
- }
- static void handle_cursor_read_all(struct vc_data *vc, enum read_all_command command)
- {
- int indcount, sentcount, rv, sn;
- switch (command) {
- case RA_NEXT_SENT:
- /* Get Current Sentence */
- spk_get_index_count(&indcount, &sentcount);
- /*printk("%d %d ", indcount, sentcount); */
- spk_reset_index_count(sentcount + 1);
- if (indcount == 1) {
- if (!say_sentence_num(sentcount + 1, 0)) {
- kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
- return;
- }
- synth_insert_next_index(0);
- } else {
- sn = 0;
- if (!say_sentence_num(sentcount + 1, 1)) {
- sn = 1;
- spk_reset_index_count(sn);
- } else {
- synth_insert_next_index(0);
- }
- if (!say_sentence_num(sn, 0)) {
- kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
- return;
- }
- synth_insert_next_index(0);
- }
- start_read_all_timer(vc, RA_TIMER);
- break;
- case RA_PREV_SENT:
- break;
- case RA_NEXT_LINE:
- read_all_doc(vc);
- break;
- case RA_PREV_LINE:
- break;
- case RA_DOWN_ARROW:
- if (get_sentence_buf(vc, 0) == -1) {
- kbd_fakekey2(vc, RA_DOWN_ARROW);
- } else {
- say_sentence_num(0, 0);
- synth_insert_next_index(0);
- start_read_all_timer(vc, RA_TIMER);
- }
- break;
- case RA_FIND_NEXT_SENT:
- rv = get_sentence_buf(vc, 0);
- if (rv == -1)
- read_all_doc(vc);
- if (rv == 0) {
- kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
- } else {
- say_sentence_num(1, 0);
- synth_insert_next_index(0);
- start_read_all_timer(vc, RA_TIMER);
- }
- break;
- case RA_FIND_PREV_SENT:
- break;
- case RA_TIMER:
- spk_get_index_count(&indcount, &sentcount);
- if (indcount < 2)
- kbd_fakekey2(vc, RA_DOWN_ARROW);
- else
- start_read_all_timer(vc, RA_TIMER);
- break;
- }
- }
- static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
- {
- unsigned long flags;
- spin_lock_irqsave(&speakup_info.spinlock, flags);
- if (cursor_track == read_all_mode) {
- spk_parked &= 0xfe;
- if (!synth || up_flag || spk_shut_up) {
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- return NOTIFY_STOP;
- }
- del_timer(&cursor_timer);
- spk_shut_up &= 0xfe;
- spk_do_flush();
- start_read_all_timer(vc, value + 1);
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- return NOTIFY_STOP;
- }
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- return NOTIFY_OK;
- }
- static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
- {
- unsigned long flags;
- struct var_t *cursor_timeout;
- spin_lock_irqsave(&speakup_info.spinlock, flags);
- spk_parked &= 0xfe;
- if (!synth || up_flag || spk_shut_up || cursor_track == CT_Off) {
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- return;
- }
- spk_shut_up &= 0xfe;
- if (spk_no_intr)
- spk_do_flush();
- /* the key press flushes if !no_inter but we want to flush on cursor
- * moves regardless of no_inter state
- */
- is_cursor = value + 1;
- old_cursor_pos = vc->vc_pos;
- old_cursor_x = vc->state.x;
- old_cursor_y = vc->state.y;
- speakup_console[vc->vc_num]->ht.cy = vc->state.y;
- cursor_con = vc->vc_num;
- if (cursor_track == CT_Highlight)
- reset_highlight_buffers(vc);
- cursor_timeout = spk_get_var(CURSOR_TIME);
- mod_timer(&cursor_timer,
- jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- }
- static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
- {
- int i, bi, hi;
- int vc_num = vc->vc_num;
- bi = (vc->vc_attr & 0x70) >> 4;
- hi = speakup_console[vc_num]->ht.highsize[bi];
- i = 0;
- if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
- speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
- speakup_console[vc_num]->ht.rx[bi] = vc->state.x;
- speakup_console[vc_num]->ht.ry[bi] = vc->state.y;
- }
- while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
- if (ic[i] > 32) {
- speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
- hi++;
- } else if ((ic[i] == 32) && (hi != 0)) {
- if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
- 32) {
- speakup_console[vc_num]->ht.highbuf[bi][hi] =
- ic[i];
- hi++;
- }
- }
- i++;
- }
- speakup_console[vc_num]->ht.highsize[bi] = hi;
- }
- static void reset_highlight_buffers(struct vc_data *vc)
- {
- int i;
- int vc_num = vc->vc_num;
- for (i = 0; i < 8; i++)
- speakup_console[vc_num]->ht.highsize[i] = 0;
- }
- static int count_highlight_color(struct vc_data *vc)
- {
- int i, bg;
- int cc;
- int vc_num = vc->vc_num;
- u16 ch;
- u16 *start = (u16 *)vc->vc_origin;
- for (i = 0; i < 8; i++)
- speakup_console[vc_num]->ht.bgcount[i] = 0;
- for (i = 0; i < vc->vc_rows; i++) {
- u16 *end = start + vc->vc_cols * 2;
- u16 *ptr;
- for (ptr = start; ptr < end; ptr++) {
- ch = get_attributes(vc, ptr);
- bg = (ch & 0x70) >> 4;
- speakup_console[vc_num]->ht.bgcount[bg]++;
- }
- start += vc->vc_size_row;
- }
- cc = 0;
- for (i = 0; i < 8; i++)
- if (speakup_console[vc_num]->ht.bgcount[i] > 0)
- cc++;
- return cc;
- }
- static int get_highlight_color(struct vc_data *vc)
- {
- int i, j;
- unsigned int cptr[8];
- int vc_num = vc->vc_num;
- for (i = 0; i < 8; i++)
- cptr[i] = i;
- for (i = 0; i < 7; i++)
- for (j = i + 1; j < 8; j++)
- if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
- speakup_console[vc_num]->ht.bgcount[cptr[j]])
- swap(cptr[i], cptr[j]);
- for (i = 0; i < 8; i++)
- if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
- if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
- return cptr[i];
- return -1;
- }
- static int speak_highlight(struct vc_data *vc)
- {
- int hc, d;
- int vc_num = vc->vc_num;
- if (count_highlight_color(vc) == 1)
- return 0;
- hc = get_highlight_color(vc);
- if (hc != -1) {
- d = vc->state.y - speakup_console[vc_num]->ht.cy;
- if ((d == 1) || (d == -1))
- if (speakup_console[vc_num]->ht.ry[hc] != vc->state.y)
- return 0;
- spk_parked |= 0x01;
- spk_do_flush();
- spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
- speakup_console[vc_num]->ht.highsize[hc]);
- spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
- spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
- spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
- return 1;
- }
- return 0;
- }
- static void cursor_done(struct timer_list *unused)
- {
- struct vc_data *vc = vc_cons[cursor_con].d;
- unsigned long flags;
- del_timer(&cursor_timer);
- spin_lock_irqsave(&speakup_info.spinlock, flags);
- if (cursor_con != fg_console) {
- is_cursor = 0;
- goto out;
- }
- speakup_date(vc);
- if (win_enabled) {
- if (vc->state.x >= win_left && vc->state.x <= win_right &&
- vc->state.y >= win_top && vc->state.y <= win_bottom) {
- spk_keydown = 0;
- is_cursor = 0;
- goto out;
- }
- }
- if (cursor_track == read_all_mode) {
- handle_cursor_read_all(vc, read_all_key);
- goto out;
- }
- if (cursor_track == CT_Highlight) {
- if (speak_highlight(vc)) {
- spk_keydown = 0;
- is_cursor = 0;
- goto out;
- }
- }
- if (cursor_track == CT_Window)
- speakup_win_say(vc);
- else if (is_cursor == 1 || is_cursor == 4)
- say_line_from_to(vc, 0, vc->vc_cols, 0);
- else
- say_char(vc);
- spk_keydown = 0;
- is_cursor = 0;
- out:
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- }
- /* called by: vt_notifier_call() */
- static void speakup_bs(struct vc_data *vc)
- {
- unsigned long flags;
- if (!speakup_console[vc->vc_num])
- return;
- if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
- /* Speakup output, discard */
- return;
- if (!spk_parked)
- speakup_date(vc);
- if (spk_shut_up || !synth) {
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- return;
- }
- if (vc->vc_num == fg_console && spk_keydown) {
- spk_keydown = 0;
- if (!is_cursor)
- say_char(vc);
- }
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- }
- /* called by: vt_notifier_call() */
- static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
- {
- unsigned long flags;
- if ((vc->vc_num != fg_console) || spk_shut_up || !synth)
- return;
- if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
- /* Speakup output, discard */
- return;
- if (spk_bell_pos && spk_keydown && (vc->state.x == spk_bell_pos - 1))
- bleep(3);
- if ((is_cursor) || (cursor_track == read_all_mode)) {
- if (cursor_track == CT_Highlight)
- update_color_buffer(vc, str, len);
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- return;
- }
- if (win_enabled) {
- if (vc->state.x >= win_left && vc->state.x <= win_right &&
- vc->state.y >= win_top && vc->state.y <= win_bottom) {
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- return;
- }
- }
- spkup_write(str, len);
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- }
- static void speakup_con_update(struct vc_data *vc)
- {
- unsigned long flags;
- if (!speakup_console[vc->vc_num] || spk_parked || !synth)
- return;
- if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
- /* Speakup output, discard */
- return;
- speakup_date(vc);
- if (vc->vc_mode == KD_GRAPHICS && !spk_paused && spk_str_pause[0]) {
- synth_printf("%s", spk_str_pause);
- spk_paused = true;
- }
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- }
- static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
- {
- unsigned long flags;
- int on_off = 2;
- char *label;
- if (!synth || up_flag || spk_killed)
- return;
- spin_lock_irqsave(&speakup_info.spinlock, flags);
- spk_shut_up &= 0xfe;
- if (spk_no_intr)
- spk_do_flush();
- switch (value) {
- case KVAL(K_CAPS):
- label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
- on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
- break;
- case KVAL(K_NUM):
- label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
- on_off = vt_get_leds(fg_console, VC_NUMLOCK);
- break;
- case KVAL(K_HOLD):
- label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
- on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
- if (speakup_console[vc->vc_num])
- speakup_console[vc->vc_num]->tty_stopped = on_off;
- break;
- default:
- spk_parked &= 0xfe;
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- return;
- }
- if (on_off < 2)
- synth_printf("%s %s\n",
- label, spk_msg_get(MSG_STATUS_START + on_off));
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- }
- static int inc_dec_var(u_char value)
- {
- struct st_var_header *p_header;
- struct var_t *var_data;
- char num_buf[32];
- char *cp = num_buf;
- char *pn;
- int var_id = (int)value - VAR_START;
- int how = (var_id & 1) ? E_INC : E_DEC;
- var_id = var_id / 2 + FIRST_SET_VAR;
- p_header = spk_get_var_header(var_id);
- if (!p_header)
- return -1;
- if (p_header->var_type != VAR_NUM)
- return -1;
- var_data = p_header->data;
- if (spk_set_num_var(1, p_header, how) != 0)
- return -1;
- if (!spk_close_press) {
- for (pn = p_header->name; *pn; pn++) {
- if (*pn == '_')
- *cp = SPACE;
- else
- *cp++ = *pn;
- }
- }
- snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
- var_data->u.n.value);
- synth_printf("%s", num_buf);
- return 0;
- }
- static void speakup_win_set(struct vc_data *vc)
- {
- char info[40];
- if (win_start > 1) {
- synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
- return;
- }
- if (spk_x < win_left || spk_y < win_top) {
- synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
- return;
- }
- if (win_start && spk_x == win_left && spk_y == win_top) {
- win_left = 0;
- win_right = vc->vc_cols - 1;
- win_bottom = spk_y;
- snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
- (int)win_top + 1);
- } else {
- if (!win_start) {
- win_top = spk_y;
- win_left = spk_x;
- } else {
- win_bottom = spk_y;
- win_right = spk_x;
- }
- snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
- (win_start) ?
- spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
- (int)spk_y + 1, (int)spk_x + 1);
- }
- synth_printf("%s\n", info);
- win_start++;
- }
- static void speakup_win_clear(struct vc_data *vc)
- {
- win_top = 0;
- win_bottom = 0;
- win_left = 0;
- win_right = 0;
- win_start = 0;
- synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
- }
- static void speakup_win_enable(struct vc_data *vc)
- {
- if (win_start < 2) {
- synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
- return;
- }
- win_enabled ^= 1;
- if (win_enabled)
- synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
- else
- synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
- }
- static void speakup_bits(struct vc_data *vc)
- {
- int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
- if (spk_special_handler || val < 1 || val > 6) {
- synth_printf("%s\n", spk_msg_get(MSG_ERROR));
- return;
- }
- pb_edit = &spk_punc_info[val];
- synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
- spk_special_handler = edit_bits;
- }
- static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
- {
- static u_char goto_buf[8];
- static int num;
- int maxlen;
- char *cp;
- u16 wch;
- if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
- goto do_goto;
- if (type == KT_LATIN && ch == '\n')
- goto do_goto;
- if (type != 0)
- goto oops;
- if (ch == 8) {
- u16 wch;
- if (num == 0)
- return -1;
- wch = goto_buf[--num];
- goto_buf[num] = '\0';
- spkup_write(&wch, 1);
- return 1;
- }
- if (ch < '+' || ch > 'y')
- goto oops;
- wch = ch;
- goto_buf[num++] = ch;
- goto_buf[num] = '\0';
- spkup_write(&wch, 1);
- maxlen = (*goto_buf >= '0') ? 3 : 4;
- if ((ch == '+' || ch == '-') && num == 1)
- return 1;
- if (ch >= '0' && ch <= '9' && num < maxlen)
- return 1;
- if (num < maxlen - 1 || num > maxlen)
- goto oops;
- if (ch < 'x' || ch > 'y') {
- oops:
- if (!spk_killed)
- synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
- goto_buf[num = 0] = '\0';
- spk_special_handler = NULL;
- return 1;
- }
- /* Do not replace with kstrtoul: here we need cp to be updated */
- goto_pos = simple_strtoul(goto_buf, &cp, 10);
- if (*cp == 'x') {
- if (*goto_buf < '0')
- goto_pos += spk_x;
- else if (goto_pos > 0)
- goto_pos--;
- if (goto_pos >= vc->vc_cols)
- goto_pos = vc->vc_cols - 1;
- goto_x = 1;
- } else {
- if (*goto_buf < '0')
- goto_pos += spk_y;
- else if (goto_pos > 0)
- goto_pos--;
- if (goto_pos >= vc->vc_rows)
- goto_pos = vc->vc_rows - 1;
- goto_x = 0;
- }
- goto_buf[num = 0] = '\0';
- do_goto:
- spk_special_handler = NULL;
- spk_parked |= 0x01;
- if (goto_x) {
- spk_pos -= spk_x * 2;
- spk_x = goto_pos;
- spk_pos += goto_pos * 2;
- say_word(vc);
- } else {
- spk_y = goto_pos;
- spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
- say_line(vc);
- }
- return 1;
- }
- static void speakup_goto(struct vc_data *vc)
- {
- if (spk_special_handler) {
- synth_printf("%s\n", spk_msg_get(MSG_ERROR));
- return;
- }
- synth_printf("%s\n", spk_msg_get(MSG_GOTO));
- spk_special_handler = handle_goto;
- }
- static void speakup_help(struct vc_data *vc)
- {
- spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
- }
- static void do_nothing(struct vc_data *vc)
- {
- return; /* flush done in do_spkup */
- }
- static u_char key_speakup, spk_key_locked;
- static void speakup_lock(struct vc_data *vc)
- {
- if (!spk_key_locked) {
- spk_key_locked = 16;
- key_speakup = 16;
- } else {
- spk_key_locked = 0;
- key_speakup = 0;
- }
- }
- typedef void (*spkup_hand) (struct vc_data *);
- static spkup_hand spkup_handler[] = {
- /* must be ordered same as defines in speakup.h */
- do_nothing, speakup_goto, speech_kill, speakup_shut_up,
- speakup_cut, speakup_paste, say_first_char, say_last_char,
- say_char, say_prev_char, say_next_char,
- say_word, say_prev_word, say_next_word,
- say_line, say_prev_line, say_next_line,
- top_edge, bottom_edge, left_edge, right_edge,
- spell_word, spell_word, say_screen,
- say_position, say_attributes,
- speakup_off, speakup_parked, say_line, /* this is for indent */
- say_from_top, say_to_bottom,
- say_from_left, say_to_right,
- say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
- speakup_bits, speakup_bits, speakup_bits,
- speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
- speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
- };
- static void do_spkup(struct vc_data *vc, u_char value)
- {
- if (spk_killed && value != SPEECH_KILL)
- return;
- spk_keydown = 0;
- spk_lastkey = 0;
- spk_shut_up &= 0xfe;
- this_speakup_key = value;
- if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
- spk_do_flush();
- (*spkup_handler[value]) (vc);
- } else {
- if (inc_dec_var(value) < 0)
- bleep(9);
- }
- }
- static const char *pad_chars = "0123456789+-*/\015,.?()";
- static int
- speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
- int up_flag)
- {
- unsigned long flags;
- int kh;
- u_char *key_info;
- u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
- u_char shift_info, offset;
- int ret = 0;
- if (!synth)
- return 0;
- spin_lock_irqsave(&speakup_info.spinlock, flags);
- tty = vc->port.tty;
- if (type >= 0xf0)
- type -= 0xf0;
- if (type == KT_PAD &&
- (vt_get_leds(fg_console, VC_NUMLOCK))) {
- if (up_flag) {
- spk_keydown = 0;
- goto out;
- }
- value = pad_chars[value];
- spk_lastkey = value;
- spk_keydown++;
- spk_parked &= 0xfe;
- goto no_map;
- }
- if (keycode >= MAX_KEY)
- goto no_map;
- key_info = spk_our_keys[keycode];
- if (!key_info)
- goto no_map;
- /* Check valid read all mode keys */
- if ((cursor_track == read_all_mode) && (!up_flag)) {
- switch (value) {
- case KVAL(K_DOWN):
- case KVAL(K_UP):
- case KVAL(K_LEFT):
- case KVAL(K_RIGHT):
- case KVAL(K_PGUP):
- case KVAL(K_PGDN):
- break;
- default:
- stop_read_all(vc);
- break;
- }
- }
- shift_info = (shift_state & 0x0f) + key_speakup;
- offset = spk_shift_table[shift_info];
- if (offset) {
- new_key = key_info[offset];
- if (new_key) {
- ret = 1;
- if (new_key == SPK_KEY) {
- if (!spk_key_locked)
- key_speakup = (up_flag) ? 0 : 16;
- if (up_flag || spk_killed)
- goto out;
- spk_shut_up &= 0xfe;
- spk_do_flush();
- goto out;
- }
- if (up_flag)
- goto out;
- if (last_keycode == keycode &&
- time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
- spk_close_press = 1;
- offset = spk_shift_table[shift_info + 32];
- /* double press? */
- if (offset && key_info[offset])
- new_key = key_info[offset];
- }
- last_keycode = keycode;
- last_spk_jiffy = jiffies;
- type = KT_SPKUP;
- value = new_key;
- }
- }
- no_map:
- if (type == KT_SPKUP && !spk_special_handler) {
- do_spkup(vc, new_key);
- spk_close_press = 0;
- ret = 1;
- goto out;
- }
- if (up_flag || spk_killed || type == KT_SHIFT)
- goto out;
- spk_shut_up &= 0xfe;
- kh = (value == KVAL(K_DOWN)) ||
- (value == KVAL(K_UP)) ||
- (value == KVAL(K_LEFT)) ||
- (value == KVAL(K_RIGHT));
- if ((cursor_track != read_all_mode) || !kh)
- if (!spk_no_intr)
- spk_do_flush();
- if (spk_special_handler) {
- if (type == KT_SPEC && value == 1) {
- value = '\n';
- type = KT_LATIN;
- } else if (type == KT_LETTER) {
- type = KT_LATIN;
- } else if (value == 0x7f) {
- value = 8; /* make del = backspace */
- }
- ret = (*spk_special_handler) (vc, type, value, keycode);
- spk_close_press = 0;
- if (ret < 0)
- bleep(9);
- goto out;
- }
- last_keycode = 0;
- out:
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- return ret;
- }
- static int keyboard_notifier_call(struct notifier_block *nb,
- unsigned long code, void *_param)
- {
- struct keyboard_notifier_param *param = _param;
- struct vc_data *vc = param->vc;
- int up = !param->down;
- int ret = NOTIFY_OK;
- static int keycode; /* to hold the current keycode */
- in_keyboard_notifier = 1;
- if (vc->vc_mode == KD_GRAPHICS)
- goto out;
- /*
- * First, determine whether we are handling a fake keypress on
- * the current processor. If we are, then return NOTIFY_OK,
- * to pass the keystroke up the chain. This prevents us from
- * trying to take the Speakup lock while it is held by the
- * processor on which the simulated keystroke was generated.
- * Also, the simulated keystrokes should be ignored by Speakup.
- */
- if (speakup_fake_key_pressed())
- goto out;
- switch (code) {
- case KBD_KEYCODE:
- /* speakup requires keycode and keysym currently */
- keycode = param->value;
- break;
- case KBD_UNBOUND_KEYCODE:
- /* not used yet */
- break;
- case KBD_UNICODE:
- /* not used yet */
- break;
- case KBD_KEYSYM:
- if (speakup_key(vc, param->shift, keycode, param->value, up))
- ret = NOTIFY_STOP;
- else if (KTYP(param->value) == KT_CUR)
- ret = pre_handle_cursor(vc, KVAL(param->value), up);
- break;
- case KBD_POST_KEYSYM:{
- unsigned char type = KTYP(param->value) - 0xf0;
- unsigned char val = KVAL(param->value);
- switch (type) {
- case KT_SHIFT:
- do_handle_shift(vc, val, up);
- break;
- case KT_LATIN:
- case KT_LETTER:
- do_handle_latin(vc, val, up);
- break;
- case KT_CUR:
- do_handle_cursor(vc, val, up);
- break;
- case KT_SPEC:
- do_handle_spec(vc, val, up);
- break;
- }
- break;
- }
- }
- out:
- in_keyboard_notifier = 0;
- return ret;
- }
- static int vt_notifier_call(struct notifier_block *nb,
- unsigned long code, void *_param)
- {
- struct vt_notifier_param *param = _param;
- struct vc_data *vc = param->vc;
- switch (code) {
- case VT_ALLOCATE:
- if (vc->vc_mode == KD_TEXT)
- speakup_allocate(vc, GFP_ATOMIC);
- break;
- case VT_DEALLOCATE:
- speakup_deallocate(vc);
- break;
- case VT_WRITE:
- if (param->c == '\b') {
- speakup_bs(vc);
- } else {
- u16 d = param->c;
- speakup_con_write(vc, &d, 1);
- }
- break;
- case VT_UPDATE:
- speakup_con_update(vc);
- break;
- }
- return NOTIFY_OK;
- }
- /* called by: module_exit() */
- static void __exit speakup_exit(void)
- {
- int i;
- unregister_keyboard_notifier(&keyboard_notifier_block);
- unregister_vt_notifier(&vt_notifier_block);
- speakup_unregister_devsynth();
- speakup_cancel_selection();
- speakup_cancel_paste();
- del_timer_sync(&cursor_timer);
- kthread_stop(speakup_task);
- speakup_task = NULL;
- mutex_lock(&spk_mutex);
- synth_release();
- mutex_unlock(&spk_mutex);
- spk_ttyio_unregister_ldisc();
- speakup_kobj_exit();
- for (i = 0; i < MAX_NR_CONSOLES; i++)
- kfree(speakup_console[i]);
- speakup_remove_virtual_keyboard();
- for (i = 0; i < MAXVARS; i++)
- speakup_unregister_var(i);
- for (i = 0; i < 256; i++) {
- if (spk_characters[i] != spk_default_chars[i])
- kfree(spk_characters[i]);
- }
- spk_free_user_msgs();
- }
- /* call by: module_init() */
- static int __init speakup_init(void)
- {
- int i;
- long err = 0;
- struct vc_data *vc = vc_cons[fg_console].d;
- struct var_t *var;
- /* These first few initializations cannot fail. */
- spk_initialize_msgs(); /* Initialize arrays for i18n. */
- spk_reset_default_chars();
- spk_reset_default_chartab();
- spk_strlwr(synth_name);
- spk_vars[0].u.n.high = vc->vc_cols;
- for (var = spk_vars; var->var_id != MAXVARS; var++)
- speakup_register_var(var);
- for (var = synth_time_vars;
- (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
- speakup_register_var(var);
- for (i = 1; spk_punc_info[i].mask != 0; i++)
- spk_set_mask_bits(NULL, i, 2);
- spk_set_key_info(spk_key_defaults, spk_key_buf);
- /* From here on out, initializations can fail. */
- err = speakup_add_virtual_keyboard();
- if (err)
- goto error_virtkeyboard;
- for (i = 0; i < MAX_NR_CONSOLES; i++)
- if (vc_cons[i].d) {
- err = speakup_allocate(vc_cons[i].d, GFP_KERNEL);
- if (err)
- goto error_kobjects;
- }
- if (spk_quiet_boot)
- spk_shut_up |= 0x01;
- err = speakup_kobj_init();
- if (err)
- goto error_kobjects;
- spk_ttyio_register_ldisc();
- synth_init(synth_name);
- speakup_register_devsynth();
- /*
- * register_devsynth might fail, but this error is not fatal.
- * /dev/synth is an extra feature; the rest of Speakup
- * will work fine without it.
- */
- err = register_keyboard_notifier(&keyboard_notifier_block);
- if (err)
- goto error_kbdnotifier;
- err = register_vt_notifier(&vt_notifier_block);
- if (err)
- goto error_vtnotifier;
- speakup_task = kthread_create(speakup_thread, NULL, "speakup");
- if (IS_ERR(speakup_task)) {
- err = PTR_ERR(speakup_task);
- goto error_task;
- }
- set_user_nice(speakup_task, 10);
- wake_up_process(speakup_task);
- pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
- pr_info("synth name on entry is: %s\n", synth_name);
- goto out;
- error_task:
- unregister_vt_notifier(&vt_notifier_block);
- error_vtnotifier:
- unregister_keyboard_notifier(&keyboard_notifier_block);
- del_timer(&cursor_timer);
- error_kbdnotifier:
- speakup_unregister_devsynth();
- mutex_lock(&spk_mutex);
- synth_release();
- mutex_unlock(&spk_mutex);
- speakup_kobj_exit();
- error_kobjects:
- for (i = 0; i < MAX_NR_CONSOLES; i++)
- kfree(speakup_console[i]);
- speakup_remove_virtual_keyboard();
- error_virtkeyboard:
- for (i = 0; i < MAXVARS; i++)
- speakup_unregister_var(i);
- for (i = 0; i < 256; i++) {
- if (spk_characters[i] != spk_default_chars[i])
- kfree(spk_characters[i]);
- }
- spk_free_user_msgs();
- out:
- return err;
- }
- module_init(speakup_init);
- module_exit(speakup_exit);
|