2018-01-11 11:08:40 +01:00
// SPDX-License-Identifier: GPL-2.0+
2010-10-07 13:20:02 -05:00
/* speakup.c
2010-10-15 22:13:34 -05:00
* 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 .
2017-02-12 16:15:58 +05:30
*/
2010-10-07 13:20:02 -05:00
# include <linux/kernel.h>
# include <linux/vt.h>
# include <linux/tty.h>
2010-10-15 22:13:34 -05:00
# include <linux/mm.h> /* __get_free_page() and friends */
2010-10-07 13:20:02 -05:00
# 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 */
2010-10-15 22:13:34 -05:00
# include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
2010-10-07 13:20:02 -05:00
# 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>
2010-10-15 22:13:34 -05:00
# include <linux/uaccess.h> /* copy_from|to|user() and others */
2010-10-07 13:20:02 -05:00
# 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 ;
2017-01-28 19:35:01 +13:00
module_param_named ( synth , synth_name , charp , 0444 ) ;
module_param_named ( quiet , spk_quiet_boot , bool , 0444 ) ;
2010-10-07 13:20:02 -05:00
MODULE_PARM_DESC ( synth , " Synth to start if speakup is built in. " ) ;
MODULE_PARM_DESC ( quiet , " Do not announce when the synthesizer is found. " ) ;
2013-01-02 02:37:40 +01:00
special_func spk_special_handler ;
2010-10-07 13:20:02 -05:00
2013-01-02 02:37:40 +01:00
short spk_pitch_shift , synth_flags ;
2017-03-04 15:01:56 +01:00
static u16 buf [ 256 ] ;
2013-01-02 02:37:40 +01:00
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 ;
2022-11-15 15:05:30 +05:00
int spk_cur_phonetic ;
2014-09-09 20:04:31 +02:00
char spk_str_caps_start [ MAXVARLEN + 1 ] = " \0 " ;
char spk_str_caps_stop [ MAXVARLEN + 1 ] = " \0 " ;
2018-05-02 02:56:10 +02:00
char spk_str_pause [ MAXVARLEN + 1 ] = " \0 " ;
2018-05-13 11:38:30 +02:00
bool spk_paused ;
2013-01-02 02:37:40 +01:00
const struct st_bits_data spk_punc_info [ ] = {
2010-10-15 22:13:34 -05:00
{ " none " , " " , 0 } ,
{ " some " , " /$%&@ " , SOME } ,
{ " most " , " $%&#()=+*/@^<>| \\ " , MOST } ,
{ " all " , " ! \" #$%&'()*+,-./:;<=>?@[ \\ ]^_`{|}~ " , PUNC } ,
{ " delimiters " , " " , B_WDLM } ,
{ " repeats " , " () " , CH_RPT } ,
{ " extended numeric " , " " , B_EXNUM } ,
{ " symbols " , " " , B_SYM } ,
2013-10-03 01:08:42 -07:00
{ NULL , NULL }
2010-10-07 13:20:02 -05:00
} ;
2010-10-15 22:13:34 -05:00
2010-10-07 13:20:02 -05:00
static char mark_cut_flag ;
# define MAX_KEY 160
2013-05-22 14:37:25 +05:30
static u_char * spk_shift_table ;
u_char * spk_our_keys [ MAX_KEY ] ;
2013-01-02 02:37:40 +01:00
u_char spk_key_buf [ 600 ] ;
const u_char spk_key_defaults [ ] = {
2010-10-07 13:20:02 -05:00
# include "speakupmap.h"
} ;
2020-11-02 10:59:45 +01:00
/* cursor track modes, must be ordered same as cursor_msgs in enum msg_index_t */
enum cursor_track {
2010-10-07 13:20:02 -05:00
CT_Off = 0 ,
CT_On ,
CT_Highlight ,
CT_Window ,
2020-11-02 10:59:45 +01:00
CT_Max ,
read_all_mode = CT_Max ,
2010-10-07 13:20:02 -05:00
} ;
2017-03-14 10:46:42 +05:30
2020-11-02 10:59:45 +01:00
/* Speakup Cursor Track Variables */
static enum cursor_track cursor_track = 1 , prev_cursor_track = 1 ;
2010-10-07 13:20:02 -05:00
static struct tty_struct * tty ;
2017-03-04 15:01:56 +01:00
static void spkup_write ( const u16 * in_buf , int count ) ;
2010-10-07 13:20:02 -05:00
static char * phonetic [ ] = {
" alfa " , " bravo " , " charlie " , " delta " , " echo " , " foxtrot " , " golf " , " hotel " ,
2010-10-15 22:13:34 -05:00
" india " , " juliett " , " keelo " , " leema " , " mike " , " november " , " oscar " ,
" papa " ,
2010-10-07 13:20:02 -05:00
" 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
2015-08-14 22:34:37 +03:00
* / proc / speakup / characters
*/
2013-01-02 02:37:40 +01:00
char * spk_characters [ 256 ] ;
2010-10-07 13:20:02 -05:00
2013-01-02 02:37:40 +01:00
char * spk_default_chars [ 256 ] = {
2010-10-15 22:13:34 -05:00
/*000*/ " null " , " ^a " , " ^b " , " ^c " , " ^d " , " ^e " , " ^f " , " ^g " ,
2010-10-07 13:20:02 -05:00
/*008*/ " ^h " , " ^i " , " ^j " , " ^k " , " ^l " , " ^m " , " ^n " , " ^o " ,
/*016*/ " ^p " , " ^q " , " ^r " , " ^s " , " ^t " , " ^u " , " ^v " , " ^w " ,
2010-10-15 22:13:34 -05:00
/*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 " ,
2010-10-07 13:20:02 -05:00
" 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 " ,
2010-10-15 22:13:34 -05:00
/*089*/ " Y " , " ZED " , " left bracket " , " backslash " , " right bracket " ,
" caret " ,
2010-10-07 13:20:02 -05:00
" 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 " ,
2010-10-15 22:13:34 -05:00
/*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 " ,
2010-10-07 13:20:02 -05:00
/*160*/ " nbsp " , " inverted bang " ,
2010-10-15 22:13:34 -05:00
/*162*/ " cents " , " pounds " , " currency " , " yen " , " broken bar " , " section " ,
/*168*/ " diaeresis " , " copyright " , " female ordinal " , " double left angle " ,
2010-10-07 13:20:02 -05:00
/*172*/ " not " , " soft hyphen " , " registered " , " macron " ,
2010-10-15 22:13:34 -05:00
/*176*/ " degrees " , " plus or minus " , " super two " , " super three " ,
/*180*/ " acute accent " , " micro " , " pilcrow " , " middle dot " ,
2010-10-07 13:20:02 -05:00
/*184*/ " cedilla " , " super one " , " male ordinal " , " double right angle " ,
2010-10-15 22:13:34 -05:00
/*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 " ,
2010-10-07 13:20:02 -05:00
/*210*/ " O GRAVE " , " O ACUTE " , " O CIRCUMFLEX " , " O TILDE " , " O OOMLAUT " ,
2010-10-15 22:13:34 -05:00
/*215*/ " multiplied by " , " O STROKE " , " U GRAVE " , " U ACUTE " ,
" U CIRCUMFLEX " ,
2010-10-07 13:20:02 -05:00
/*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 " ,
2010-10-15 22:13:34 -05:00
/*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 " ,
2010-10-07 13:20:02 -05:00
/* 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
2015-08-14 22:34:37 +03:00
* / sys / module / speakup / parameters / chartab
*/
2010-10-07 13:20:02 -05:00
u_short spk_chartab [ 256 ] ;
static u_short default_chartab [ 256 ] = {
2010-10-15 22:13:34 -05:00
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 */
2010-10-07 13:20:02 -05:00
} ;
struct task_struct * speakup_task ;
2013-01-02 02:37:40 +01:00
struct bleep spk_unprocessed_sound ;
2010-10-07 13:20:02 -05:00
static int spk_keydown ;
2017-03-04 15:01:56 +01:00
static u16 spk_lastkey ;
static u_char spk_close_press , keymap_flags ;
2010-10-07 13:20:02 -05:00
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 ) ;
2013-01-02 02:36:56 +01:00
static struct notifier_block keyboard_notifier_block = {
2010-10-07 13:20:02 -05:00
. notifier_call = keyboard_notifier_call ,
} ;
static int vt_notifier_call ( struct notifier_block * ,
unsigned long code , void * param ) ;
2013-01-02 02:36:56 +01:00
static struct notifier_block vt_notifier_block = {
2010-10-07 13:20:02 -05:00
. notifier_call = vt_notifier_call ,
} ;
2016-01-25 01:32:08 +01:00
static unsigned char get_attributes ( struct vc_data * vc , u16 * pos )
2010-10-07 13:20:02 -05:00
{
2020-08-18 10:56:53 +02:00
pos = screen_pos ( vc , pos - ( u16 * ) vc - > vc_origin , true ) ;
2016-03-15 21:34:59 +01:00
return ( scr_readw ( pos ) & ~ vc - > vc_hi_font_mask ) > > 8 ;
2010-10-07 13:20:02 -05:00
}
static void speakup_date ( struct vc_data * vc )
{
2020-06-15 09:48:33 +02:00
spk_x = spk_cx = vc - > state . x ;
spk_y = spk_cy = vc - > state . y ;
2010-10-07 13:20:02 -05:00
spk_pos = spk_cp = vc - > vc_pos ;
spk_old_attr = spk_attr ;
2016-01-25 01:32:08 +01:00
spk_attr = get_attributes ( vc , ( u_short * ) spk_pos ) ;
2010-10-07 13:20:02 -05:00
}
static void bleep ( u_short val )
{
static const short vals [ ] = {
350 , 370 , 392 , 414 , 440 , 466 , 491 , 523 , 554 , 587 , 619 , 659
} ;
short freq ;
2013-01-02 02:37:40 +01:00
int time = spk_bleep_time ;
2014-09-09 20:04:34 +02:00
2010-10-15 22:13:34 -05:00
freq = vals [ val % 12 ] ;
2010-10-07 13:20:02 -05:00
if ( val > 11 )
2010-10-15 22:13:34 -05:00
freq * = ( 1 < < ( val / 12 ) ) ;
2013-01-02 02:37:40 +01:00
spk_unprocessed_sound . freq = freq ;
spk_unprocessed_sound . jiffies = msecs_to_jiffies ( time ) ;
spk_unprocessed_sound . active = 1 ;
2010-10-07 13:20:02 -05:00
/* 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 ) ;
2017-03-24 16:59:59 +05:30
if ( synth )
2013-01-02 02:37:40 +01:00
spk_do_flush ( ) ;
2010-10-07 13:20:02 -05:00
}
static void speech_kill ( struct vc_data * vc )
{
char val = synth - > is_alive ( synth ) ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
if ( val = = 0 )
return ;
/* re-enables synth, if disabled */
if ( val = = 2 | | spk_killed ) {
/* dead */
spk_shut_up & = ~ 0x40 ;
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_IAM_ALIVE ) ) ;
2010-10-07 13:20:02 -05:00
} else {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_YOU_KILLED_SPEAKUP ) ) ;
2010-10-07 13:20:02 -05:00
spk_shut_up | = 0x40 ;
}
}
static void speakup_off ( struct vc_data * vc )
{
if ( spk_shut_up & 0x80 ) {
spk_shut_up & = 0x7f ;
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_HEY_THATS_BETTER ) ) ;
2010-10-07 13:20:02 -05:00
} else {
spk_shut_up | = 0x80 ;
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_YOU_TURNED_ME_OFF ) ) ;
2010-10-07 13:20:02 -05:00
}
speakup_date ( vc ) ;
}
static void speakup_parked ( struct vc_data * vc )
{
if ( spk_parked & 0x80 ) {
spk_parked = 0 ;
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_UNPARKED ) ) ;
2010-10-07 13:20:02 -05:00
} else {
spk_parked | = 0x80 ;
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_PARKED ) ) ;
2010-10-07 13:20:02 -05:00
}
}
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 ;
2016-11-06 15:09:18 +01:00
spk_xs = ( u_short ) spk_x ;
spk_ys = ( u_short ) spk_y ;
2010-10-07 13:20:02 -05:00
spk_sel_cons = vc ;
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_MARK ) ) ;
2010-10-07 13:20:02 -05:00
return ;
}
2016-11-06 15:09:18 +01:00
spk_xe = ( u_short ) spk_x ;
spk_ye = ( u_short ) spk_y ;
2010-10-07 13:20:02 -05:00
mark_cut_flag = 0 ;
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_CUT ) ) ;
2010-10-07 13:20:02 -05:00
ret = speakup_set_selection ( tty ) ;
switch ( ret ) {
case 0 :
2010-10-15 22:13:34 -05:00
break ; /* no error */
case - EFAULT :
2010-10-07 13:20:02 -05:00
pr_warn ( " %sEFAULT \n " , err_buf ) ;
break ;
2010-10-15 22:13:34 -05:00
case - EINVAL :
2010-10-07 13:20:02 -05:00
pr_warn ( " %sEINVAL \n " , err_buf ) ;
break ;
2010-10-15 22:13:34 -05:00
case - ENOMEM :
2010-10-07 13:20:02 -05:00
pr_warn ( " %sENOMEM \n " , err_buf ) ;
break ;
}
}
static void speakup_paste ( struct vc_data * vc )
{
if ( mark_cut_flag ) {
mark_cut_flag = 0 ;
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_MARK_CLEARED ) ) ;
2010-10-07 13:20:02 -05:00
} else {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_PASTE ) ) ;
2010-10-07 13:20:02 -05:00
speakup_paste_selection ( tty ) ;
}
}
static void say_attributes ( struct vc_data * vc )
{
int fg = spk_attr & 0x0f ;
int bg = spk_attr > > 4 ;
2014-09-09 20:04:34 +02:00
2013-01-02 02:37:40 +01:00
synth_printf ( " %s " , spk_msg_get ( MSG_COLORS_START + fg ) ) ;
2010-10-07 13:20:02 -05:00
if ( bg > 7 ) {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s " , spk_msg_get ( MSG_ON_BLINKING ) ) ;
2010-10-07 13:20:02 -05:00
bg - = 8 ;
2017-03-21 17:12:28 +05:30
} else {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s " , spk_msg_get ( MSG_ON ) ) ;
2017-03-21 17:12:28 +05:30
}
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_COLORS_START + bg ) ) ;
2010-10-07 13:20:02 -05:00
}
2020-11-02 10:59:45 +01:00
/* must be ordered same as edge_msgs in enum msg_index_t */
enum edge {
edge_none = 0 ,
edge_top ,
2010-10-07 13:20:02 -05:00
edge_bottom ,
edge_left ,
edge_right ,
edge_quiet
} ;
2020-11-02 10:59:45 +01:00
static void announce_edge ( struct vc_data * vc , enum edge msg_id )
2010-10-07 13:20:02 -05:00
{
2013-01-02 02:37:40 +01:00
if ( spk_bleeps & 1 )
2010-10-07 13:20:02 -05:00
bleep ( spk_y ) ;
2013-01-02 02:37:40 +01:00
if ( ( spk_bleeps & 2 ) & & ( msg_id < edge_quiet ) )
2015-03-28 13:21:39 -07:00
synth_printf ( " %s \n " ,
2018-03-05 09:34:13 -08:00
spk_msg_get ( MSG_EDGE_MSGS_START + msg_id - 1 ) ) ;
2010-10-07 13:20:02 -05:00
}
2017-03-04 15:01:56 +01:00
static void speak_char ( u16 ch )
2010-10-07 13:20:02 -05:00
{
2017-03-04 15:01:56 +01:00
char * cp ;
2013-01-02 02:37:40 +01:00
struct var_t * direct = spk_get_var ( DIRECT ) ;
2014-09-09 20:04:34 +02:00
2017-03-13 01:17:14 +01:00
if ( ch > = 0x100 | | ( direct & & direct - > u . n . value ) ) {
2017-03-14 20:56:21 +01:00
if ( ch < 0x100 & & IS_CHAR ( ch , B_CAP ) ) {
2013-01-02 02:37:40 +01:00
spk_pitch_shift + + ;
synth_printf ( " %s " , spk_str_caps_start ) ;
2010-10-07 13:20:02 -05:00
}
2017-03-04 15:01:56 +01:00
synth_putwc_s ( ch ) ;
2017-03-14 20:56:21 +01:00
if ( ch < 0x100 & & IS_CHAR ( ch , B_CAP ) )
2013-01-02 02:37:40 +01:00
synth_printf ( " %s " , spk_str_caps_stop ) ;
2010-10-07 13:20:02 -05:00
return ;
}
2017-03-04 15:01:56 +01:00
cp = spk_characters [ ch ] ;
2017-03-24 16:59:59 +05:30
if ( ! cp ) {
2017-09-06 13:14:25 +01:00
pr_info ( " %s: cp == NULL! \n " , __func__ ) ;
2010-10-07 13:20:02 -05:00
return ;
}
if ( IS_CHAR ( ch , B_CAP ) ) {
2013-01-02 02:37:40 +01:00
spk_pitch_shift + + ;
2017-03-22 00:55:31 +01:00
synth_printf ( " %s %s %s " ,
spk_str_caps_start , cp , spk_str_caps_stop ) ;
2010-10-07 13:20:02 -05:00
} else {
if ( * cp = = ' ^ ' ) {
cp + + ;
2017-03-22 00:55:31 +01:00
synth_printf ( " %s%s " , spk_msg_get ( MSG_CTRL ) , cp ) ;
2018-02-24 15:25:49 -08:00
} else {
2017-03-22 00:55:31 +01:00
synth_printf ( " %s " , cp ) ;
2018-02-24 15:25:49 -08:00
}
2010-10-07 13:20:02 -05:00
}
}
2013-05-17 11:51:18 -07:00
static u16 get_char ( struct vc_data * vc , u16 * pos , u_char * attribs )
2010-10-07 13:20:02 -05:00
{
u16 ch = ' ' ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
if ( vc & & pos ) {
2016-01-25 01:32:08 +01:00
u16 w ;
u16 c ;
2020-08-18 10:56:53 +02:00
pos = screen_pos ( vc , pos - ( u16 * ) vc - > vc_origin , true ) ;
2016-01-25 01:32:08 +01:00
w = scr_readw ( pos ) ;
c = w & 0xff ;
2010-10-07 13:20:02 -05:00
2016-03-15 21:34:59 +01:00
if ( w & vc - > vc_hi_font_mask ) {
w & = ~ vc - > vc_hi_font_mask ;
2010-10-07 13:20:02 -05:00
c | = 0x100 ;
2016-03-15 21:34:59 +01:00
}
2010-10-07 13:20:02 -05:00
2022-06-07 12:49:17 +02:00
ch = inverse_translate ( vc , c , true ) ;
2010-10-07 13:20:02 -05:00
* attribs = ( w & 0xff00 ) > > 8 ;
}
return ch ;
}
static void say_char ( struct vc_data * vc )
{
2017-03-04 15:01:56 +01:00
u16 ch ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
spk_old_attr = spk_attr ;
2016-11-06 15:09:18 +01:00
ch = get_char ( vc , ( u_short * ) spk_pos , & spk_attr ) ;
2010-10-07 13:20:02 -05:00
if ( spk_attr ! = spk_old_attr ) {
2013-01-02 02:37:40 +01:00
if ( spk_attrib_bleep & 1 )
2010-10-07 13:20:02 -05:00
bleep ( spk_y ) ;
2013-01-02 02:37:40 +01:00
if ( spk_attrib_bleep & 2 )
2010-10-07 13:20:02 -05:00
say_attributes ( vc ) ;
}
2017-03-04 15:01:56 +01:00
speak_char ( ch ) ;
2010-10-07 13:20:02 -05:00
}
static void say_phonetic_char ( struct vc_data * vc )
{
2017-03-04 15:01:56 +01:00
u16 ch ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
spk_old_attr = spk_attr ;
2016-11-06 15:09:18 +01:00
ch = get_char ( vc , ( u_short * ) spk_pos , & spk_attr ) ;
2017-03-04 15:01:56 +01:00
if ( ch < = 0x7f & & isalpha ( ch ) ) {
2010-10-07 13:20:02 -05:00
ch & = 0x1f ;
synth_printf ( " %s \n " , phonetic [ - - ch ] ) ;
} else {
2017-03-04 15:01:56 +01:00
if ( ch < 0x100 & & IS_CHAR ( ch , B_NUM ) )
2013-01-02 02:37:40 +01:00
synth_printf ( " %s " , spk_msg_get ( MSG_NUMBER ) ) ;
2010-10-07 13:20:02 -05:00
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
2013-01-02 02:37:40 +01:00
* 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
2010-10-15 22:13:34 -05:00
* 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
2015-08-14 22:34:37 +03:00
* beginning off the line whichever comes first . .
*/
2010-10-07 13:20:02 -05:00
static u_long get_word ( struct vc_data * vc )
{
u_long cnt = 0 , tmpx = spk_x , tmp_pos = spk_pos ;
2017-03-04 15:01:56 +01:00
u16 ch ;
u16 attr_ch ;
2010-10-07 13:20:02 -05:00
u_char temp ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
spk_old_attr = spk_attr ;
2017-03-04 15:01:56 +01:00
ch = get_char ( vc , ( u_short * ) tmp_pos , & temp ) ;
2010-10-07 13:20:02 -05:00
/* decided to take out the sayword if on a space (mis-information */
2013-01-02 02:37:40 +01:00
if ( spk_say_word_ctl & & ch = = SPACE ) {
2010-10-07 13:20:02 -05:00
* buf = ' \0 ' ;
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_SPACE ) ) ;
2010-10-07 13:20:02 -05:00
return 0 ;
2017-03-04 15:01:56 +01:00
} else if ( tmpx < vc - > vc_cols - 2 & &
( ch = = SPACE | | ch = = 0 | | ( ch < 0x100 & & IS_WDLM ( ch ) ) ) & &
2020-03-06 01:30:47 +01:00
get_char ( vc , ( u_short * ) tmp_pos + 1 , & temp ) > SPACE ) {
2010-10-07 13:20:02 -05:00
tmp_pos + = 2 ;
tmpx + + ;
2018-02-24 15:25:49 -08:00
} else {
2010-10-07 13:20:02 -05:00
while ( tmpx > 0 ) {
2017-03-04 15:01:56 +01:00
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 )
2010-10-07 13:20:02 -05:00
break ;
tmp_pos - = 2 ;
tmpx - - ;
}
2018-02-24 15:25:49 -08:00
}
2016-11-06 15:09:18 +01:00
attr_ch = get_char ( vc , ( u_short * ) tmp_pos , & spk_attr ) ;
2017-03-04 15:01:56 +01:00
buf [ cnt + + ] = attr_ch ;
2024-04-15 14:02:23 +03:00
while ( tmpx < vc - > vc_cols - 1 & & cnt < ARRAY_SIZE ( buf ) - 1 ) {
2010-10-07 13:20:02 -05:00
tmp_pos + = 2 ;
tmpx + + ;
2017-03-04 15:01:56 +01:00
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 ) )
2010-10-07 13:20:02 -05:00
break ;
buf [ cnt + + ] = ch ;
}
buf [ cnt ] = ' \0 ' ;
return cnt ;
}
static void say_word ( struct vc_data * vc )
{
u_long cnt = get_word ( vc ) ;
2013-01-02 02:37:40 +01:00
u_short saved_punc_mask = spk_punc_mask ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
if ( cnt = = 0 )
return ;
2013-01-02 02:37:40 +01:00
spk_punc_mask = PUNC ;
2010-10-07 13:20:02 -05:00
buf [ cnt + + ] = SPACE ;
spkup_write ( buf , cnt ) ;
2013-01-02 02:37:40 +01:00
spk_punc_mask = saved_punc_mask ;
2010-10-07 13:20:02 -05:00
}
static void say_prev_word ( struct vc_data * vc )
{
u_char temp ;
2017-03-04 15:01:56 +01:00
u16 ch ;
2020-11-02 10:59:45 +01:00
enum edge edge_said = edge_none ;
u_short last_state = 0 , state = 0 ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
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 ;
2017-03-21 17:12:28 +05:30
} else {
2010-10-07 13:20:02 -05:00
spk_x - - ;
2017-03-21 17:12:28 +05:30
}
2010-10-15 22:13:34 -05:00
spk_pos - = 2 ;
2017-03-04 15:01:56 +01:00
ch = get_char ( vc , ( u_short * ) spk_pos , & temp ) ;
2010-10-07 13:20:02 -05:00
if ( ch = = SPACE | | ch = = 0 )
state = 0 ;
2017-03-04 15:01:56 +01:00
else if ( ch < 0x100 & & IS_WDLM ( ch ) )
2010-10-07 13:20:02 -05:00
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 ;
2020-11-02 10:59:45 +01:00
if ( edge_said > edge_none & & edge_said < edge_quiet )
2010-10-07 13:20:02 -05:00
announce_edge ( vc , edge_said ) ;
say_word ( vc ) ;
}
static void say_next_word ( struct vc_data * vc )
{
u_char temp ;
2017-03-04 15:01:56 +01:00
u16 ch ;
2020-11-02 10:59:45 +01:00
enum edge edge_said = edge_none ;
u_short last_state = 2 , state = 0 ;
2010-10-07 13:20:02 -05:00
2014-09-09 20:04:34 +02:00
spk_parked | = 0x01 ;
2010-10-07 13:20:02 -05:00
if ( spk_x = = vc - > vc_cols - 1 & & spk_y = = vc - > vc_rows - 1 ) {
announce_edge ( vc , edge_bottom ) ;
return ;
}
while ( 1 ) {
2017-03-04 15:01:56 +01:00
ch = get_char ( vc , ( u_short * ) spk_pos , & temp ) ;
2010-10-07 13:20:02 -05:00
if ( ch = = SPACE | | ch = = 0 )
state = 0 ;
2017-03-04 15:01:56 +01:00
else if ( ch < 0x100 & & IS_WDLM ( ch ) )
2010-10-07 13:20:02 -05:00
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 ;
2017-03-21 17:12:28 +05:30
} else {
2010-10-07 13:20:02 -05:00
spk_x + + ;
2017-03-21 17:12:28 +05:30
}
2010-10-07 13:20:02 -05:00
spk_pos + = 2 ;
last_state = state ;
}
2020-11-02 10:59:45 +01:00
if ( edge_said > edge_none )
2010-10-07 13:20:02 -05:00
announce_edge ( vc , edge_said ) ;
say_word ( vc ) ;
}
static void spell_word ( struct vc_data * vc )
{
2014-10-07 10:59:18 +03:00
static char const * delay_str [ ] = { " " , " , " , " . " , " . . " , " . . . " } ;
2017-03-04 15:01:56 +01:00
u16 * cp = buf ;
char * cp1 ;
char * str_cap = spk_str_caps_stop ;
char * last_cap = spk_str_caps_stop ;
2017-03-13 01:17:14 +01:00
struct var_t * direct = spk_get_var ( DIRECT ) ;
2017-03-04 15:01:56 +01:00
u16 ch ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
if ( ! get_word ( vc ) )
return ;
2017-03-04 15:01:56 +01:00
while ( ( ch = * cp ) ) {
2010-10-07 13:20:02 -05:00
if ( cp ! = buf )
2013-01-02 02:37:40 +01:00
synth_printf ( " %s " , delay_str [ spk_spell_delay ] ) ;
2017-03-13 01:17:14 +01:00
/* FIXME: Non-latin1 considered as lower case */
if ( ch < 0x100 & & IS_CHAR ( ch , B_CAP ) ) {
2013-01-02 02:37:40 +01:00
str_cap = spk_str_caps_start ;
if ( * spk_str_caps_stop )
spk_pitch_shift + + ;
2010-10-15 22:13:34 -05:00
else /* synth has no pitch */
2013-01-02 02:37:40 +01:00
last_cap = spk_str_caps_stop ;
2017-03-21 17:12:28 +05:30
} else {
2013-01-02 02:37:40 +01:00
str_cap = spk_str_caps_stop ;
2017-03-21 17:12:28 +05:30
}
2010-10-07 13:20:02 -05:00
if ( str_cap ! = last_cap ) {
synth_printf ( " %s " , str_cap ) ;
last_cap = str_cap ;
}
2017-03-13 01:17:14 +01:00
if ( ch > = 0x100 | | ( direct & & direct - > u . n . value ) ) {
synth_putwc_s ( ch ) ;
} else if ( this_speakup_key = = SPELL_PHONETIC & &
2017-03-04 15:01:56 +01:00
ch < = 0x7f & & isalpha ( ch ) ) {
ch & = 0x1f ;
2010-10-07 13:20:02 -05:00
cp1 = phonetic [ - - ch ] ;
2017-03-13 01:17:14 +01:00
synth_printf ( " %s " , cp1 ) ;
2010-10-07 13:20:02 -05:00
} else {
2013-01-02 02:37:40 +01:00
cp1 = spk_characters [ ch ] ;
2010-10-07 13:20:02 -05:00
if ( * cp1 = = ' ^ ' ) {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s " , spk_msg_get ( MSG_CTRL ) ) ;
2010-10-07 13:20:02 -05:00
cp1 + + ;
}
2017-03-13 01:17:14 +01:00
synth_printf ( " %s " , cp1 ) ;
2010-10-07 13:20:02 -05:00
}
cp + + ;
}
2013-01-02 02:37:40 +01:00
if ( str_cap ! = spk_str_caps_stop )
synth_printf ( " %s " , spk_str_caps_stop ) ;
2010-10-07 13:20:02 -05:00
}
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 ;
2016-01-25 01:32:08 +01:00
spk_attr = get_attributes ( vc , ( u_short * ) spk_pos ) ;
2010-10-07 13:20:02 -05:00
for ( i = 0 ; i < vc - > vc_cols ; i + + ) {
2017-03-04 15:01:56 +01:00
buf [ i ] = get_char ( vc , ( u_short * ) tmp , & tmp2 ) ;
2010-10-07 13:20:02 -05:00
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 ) ;
2017-03-04 15:01:56 +01:00
u16 * cp ;
2013-01-02 02:37:40 +01:00
u_short saved_punc_mask = spk_punc_mask ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
if ( i = = 0 ) {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_BLANK ) ) ;
2010-10-07 13:20:02 -05:00
return ;
}
buf [ i + + ] = ' \n ' ;
if ( this_speakup_key = = SAY_LINE_INDENT ) {
2010-10-15 22:13:34 -05:00
cp = buf ;
while ( * cp = = SPACE )
cp + + ;
2017-03-04 08:13:11 -08:00
synth_printf ( " %zd, " , ( cp - buf ) + 1 ) ;
2010-10-07 13:20:02 -05:00
}
2013-01-02 02:37:40 +01:00
spk_punc_mask = spk_punc_masks [ spk_reading_punc ] ;
2010-10-07 13:20:02 -05:00
spkup_write ( buf , i ) ;
2013-01-02 02:37:40 +01:00
spk_punc_mask = saved_punc_mask ;
2010-10-07 13:20:02 -05:00
}
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 ;
2013-01-02 02:37:40 +01:00
u_short saved_punc_mask = spk_punc_mask ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
spk_old_attr = spk_attr ;
2016-01-25 01:32:08 +01:00
spk_attr = get_attributes ( vc , ( u_short * ) from ) ;
2010-10-07 13:20:02 -05:00
while ( from < to ) {
2017-03-04 15:01:56 +01:00
buf [ i + + ] = get_char ( vc , ( u_short * ) from , & tmp ) ;
2010-10-07 13:20:02 -05:00
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 )
2013-01-02 02:37:40 +01:00
spk_punc_mask = spk_punc_info [ spk_reading_punc ] . mask ;
2010-10-07 13:20:02 -05:00
spkup_write ( buf , i ) ;
if ( read_punc )
2013-01-02 02:37:40 +01:00
spk_punc_mask = saved_punc_mask ;
2010-10-07 13:20:02 -05:00
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 ) ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
start + = from * 2 ;
if ( say_from_to ( vc , start , end , read_punc ) < = 0 )
if ( cursor_track ! = read_all_mode )
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_BLANK ) ) ;
2010-10-07 13:20:02 -05:00
}
/* Sentence Reading Commands */
static int currsentence ;
static int numsentences [ 2 ] ;
2017-03-04 15:01:56 +01:00
static u16 * sentbufend [ 2 ] ;
static u16 * sentmarks [ 2 ] [ 10 ] ;
2010-10-07 13:20:02 -05:00
static int currbuf ;
static int bn ;
2017-03-04 15:01:56 +01:00
static u16 sentbuf [ 2 ] [ 256 ] ;
2010-10-07 13:20:02 -05:00
2010-10-15 22:13:34 -05:00
static int say_sentence_num ( int num , int prev )
2010-10-07 13:20:02 -05:00
{
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 ) ;
2010-10-15 22:13:34 -05:00
end = vc - > vc_origin + ( ( spk_y ) * vc - > vc_size_row ) + vc - > vc_cols * 2 ;
2010-10-07 13:20:02 -05:00
numsentences [ bn ] = 0 ;
sentmarks [ bn ] [ 0 ] = & sentbuf [ bn ] [ 0 ] ;
i = 0 ;
spk_old_attr = spk_attr ;
2016-01-25 01:32:08 +01:00
spk_attr = get_attributes ( vc , ( u_short * ) start ) ;
2010-10-07 13:20:02 -05:00
while ( start < end ) {
2017-03-04 15:01:56 +01:00
sentbuf [ bn ] [ i ] = get_char ( vc , ( u_short * ) start , & tmp ) ;
2010-10-07 13:20:02 -05:00
if ( i > 0 ) {
2019-02-28 17:59:04 +05:30
if ( sentbuf [ bn ] [ i ] = = SPACE & &
sentbuf [ bn ] [ i - 1 ] = = ' . ' & &
2017-03-21 17:12:25 +05:30
numsentences [ bn ] < 9 ) {
2010-10-07 13:20:02 -05:00
/* Sentence Marker */
numsentences [ bn ] + + ;
sentmarks [ bn ] [ numsentences [ bn ] ] =
2010-10-15 22:13:34 -05:00
& sentbuf [ bn ] [ i ] ;
2010-10-07 13:20:02 -05:00
}
}
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 ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
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 ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
if ( win_start < 2 ) {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_NO_WINDOW ) ) ;
2010-10-07 13:20:02 -05:00
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 ) ;
2017-03-04 15:01:56 +01:00
u16 ch ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
spk_parked | = 0x01 ;
if ( len = = 0 ) {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_BLANK ) ) ;
2010-10-07 13:20:02 -05:00
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 ) ;
2017-03-04 15:01:56 +01:00
u16 ch ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
spk_parked | = 0x01 ;
if ( len = = 0 ) {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_BLANK ) ) ;
2010-10-07 13:20:02 -05:00
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 )
{
2013-01-02 02:37:40 +01:00
synth_printf ( spk_msg_get ( MSG_POS_INFO ) , spk_y + 1 , spk_x + 1 ,
2010-10-15 22:13:34 -05:00
vc - > vc_num + 1 ) ;
2010-10-07 13:20:02 -05:00
synth_printf ( " \n " ) ;
}
/* Added by brianb */
static void say_char_num ( struct vc_data * vc )
{
u_char tmp ;
2017-03-04 15:01:56 +01:00
u16 ch = get_char ( vc , ( u_short * ) spk_pos , & tmp ) ;
2014-09-09 20:04:34 +02:00
2013-01-02 02:37:40 +01:00
synth_printf ( spk_msg_get ( MSG_CHAR_INFO ) , ch , ch ) ;
2010-10-07 13:20:02 -05:00
}
/* 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. */
2017-03-04 15:01:56 +01:00
static void spkup_write ( const u16 * in_buf , int count )
2010-10-07 13:20:02 -05:00
{
2010-10-15 22:13:34 -05:00
static int rep_count ;
2017-03-04 15:01:56 +01:00
static u16 ch = ' \0 ' , old_ch = ' \0 ' ;
2010-10-15 22:13:34 -05:00
static u_short char_type , last_type ;
2010-10-07 13:20:02 -05:00
int in_count = count ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
spk_keydown = 0 ;
while ( count - - ) {
if ( cursor_track = = read_all_mode ) {
/* Insert Sentence Index */
if ( ( in_buf = = sentmarks [ bn ] [ currsentence ] ) & &
2010-10-15 22:13:34 -05:00
( currsentence < = numsentences [ bn ] ) )
2010-10-07 13:20:02 -05:00
synth_insert_next_index ( currsentence + + ) ;
}
2017-03-04 15:01:56 +01:00
ch = * in_buf + + ;
if ( ch < 0x100 )
char_type = spk_chartab [ ch ] ;
else
char_type = ALPHA ;
2010-10-15 22:13:34 -05:00
if ( ch = = old_ch & & ! ( char_type & B_NUM ) ) {
2010-10-07 13:20:02 -05:00
if ( + + rep_count > 2 )
continue ;
} else {
2010-10-15 22:13:34 -05:00
if ( ( last_type & CH_RPT ) & & rep_count > 2 ) {
2010-10-07 13:20:02 -05:00
synth_printf ( " " ) ;
2013-01-02 02:37:40 +01:00
synth_printf ( spk_msg_get ( MSG_REPEAT_DESC ) ,
2010-10-15 22:13:34 -05:00
+ + rep_count ) ;
2010-10-07 13:20:02 -05:00
synth_printf ( " " ) ;
}
rep_count = 0 ;
}
if ( ch = = spk_lastkey ) {
rep_count = 0 ;
2013-01-02 02:37:40 +01:00
if ( spk_key_echo = = 1 & & ch > = MINECHOCHAR )
2010-10-07 13:20:02 -05:00
speak_char ( ch ) ;
} else if ( char_type & B_ALPHA ) {
if ( ( synth_flags & SF_DEC ) & & ( last_type & PUNC ) )
synth_buffer_add ( SPACE ) ;
2017-03-04 15:01:56 +01:00
synth_putwc_s ( ch ) ;
2010-10-07 13:20:02 -05:00
} else if ( char_type & B_NUM ) {
rep_count = 0 ;
2017-03-04 15:01:56 +01:00
synth_putwc_s ( ch ) ;
2013-01-02 02:37:40 +01:00
} else if ( char_type & spk_punc_mask ) {
2010-10-07 13:20:02 -05:00
speak_char ( ch ) ;
2010-10-15 22:13:34 -05:00
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
2015-08-14 22:34:37 +03:00
* repeats on you don ' t get nothing repeated count
*/
2010-10-07 13:20:02 -05:00
if ( ch ! = old_ch )
2017-03-04 15:01:56 +01:00
synth_putwc_s ( ch ) ;
2010-10-07 13:20:02 -05:00
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 ) {
2010-10-15 22:13:34 -05:00
if ( last_type & CH_RPT ) {
2010-10-07 13:20:02 -05:00
synth_printf ( " " ) ;
2015-03-28 13:21:39 -07:00
synth_printf ( spk_msg_get ( MSG_REPEAT_DESC2 ) ,
2017-03-21 17:12:34 +05:30
+ + rep_count ) ;
2010-10-07 13:20:02 -05:00
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 ) ;
2017-08-28 11:28:21 -07:00
static void cursor_done ( struct timer_list * unused ) ;
2017-10-04 16:27:04 -07:00
static DEFINE_TIMER ( cursor_timer , cursor_done ) ;
2010-10-07 13:20:02 -05:00
static void do_handle_shift ( struct vc_data * vc , u_char value , char up_flag )
{
unsigned long flags ;
2014-09-09 20:04:34 +02:00
2017-03-24 16:59:59 +05:30
if ( ! synth | | up_flag | | spk_killed )
2010-10-07 13:20:02 -05:00
return ;
2013-05-13 00:02:56 -05:00
spin_lock_irqsave ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
if ( cursor_track = = read_all_mode ) {
switch ( value ) {
case KVAL ( K_SHIFT ) :
del_timer ( & cursor_timer ) ;
spk_shut_up & = 0xfe ;
2013-01-02 02:37:40 +01:00
spk_do_flush ( ) ;
2010-10-07 13:20:02 -05:00
read_all_doc ( vc ) ;
break ;
case KVAL ( K_CTRL ) :
del_timer ( & cursor_timer ) ;
cursor_track = prev_cursor_track ;
spk_shut_up & = 0xfe ;
2013-01-02 02:37:40 +01:00
spk_do_flush ( ) ;
2010-10-07 13:20:02 -05:00
break ;
}
} else {
spk_shut_up & = 0xfe ;
2013-01-02 02:37:40 +01:00
spk_do_flush ( ) ;
2010-10-07 13:20:02 -05:00
}
2013-01-02 02:37:40 +01:00
if ( spk_say_ctrl & & value < NUM_CTL_LABELS )
synth_printf ( " %s " , spk_msg_get ( MSG_CTL_START + value ) ) ;
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
}
static void do_handle_latin ( struct vc_data * vc , u_char value , char up_flag )
{
unsigned long flags ;
2014-09-09 20:04:34 +02:00
2013-05-13 00:02:56 -05:00
spin_lock_irqsave ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
if ( up_flag ) {
2016-02-23 21:38:58 -08:00
spk_lastkey = 0 ;
spk_keydown = 0 ;
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
return ;
}
2017-03-24 16:59:59 +05:30
if ( ! synth | | spk_killed ) {
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
return ;
}
spk_shut_up & = 0xfe ;
spk_lastkey = value ;
spk_keydown + + ;
spk_parked & = 0xfe ;
2013-01-02 02:37:40 +01:00
if ( spk_key_echo = = 2 & & value > = MINECHOCHAR )
2010-10-07 13:20:02 -05:00
speak_char ( value ) ;
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
}
2013-01-02 02:37:40 +01:00
int spk_set_key_info ( const u_char * key_info , u_char * k_buffer )
2010-10-07 13:20:02 -05:00
{
int i = 0 , states , key_data_len ;
const u_char * cp = key_info ;
u_char * cp1 = k_buffer ;
u_char ch , version , num_keys ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
version = * cp + + ;
2017-03-21 12:40:22 +05:30
if ( version ! = KEY_MAP_VER ) {
pr_debug ( " version found %d should be %d \n " ,
version , KEY_MAP_VER ) ;
return - EINVAL ;
}
2010-10-07 13:20:02 -05:00
num_keys = * cp ;
2010-10-15 22:13:34 -05:00
states = ( int ) cp [ 1 ] ;
2010-10-07 13:20:02 -05:00
key_data_len = ( states + 1 ) * ( num_keys + 1 ) ;
2017-03-21 12:40:22 +05:30
if ( key_data_len + SHIFT_TBL_SIZE + 4 > = sizeof ( spk_key_buf ) ) {
pr_debug ( " too many key_infos (%d over %u) \n " ,
2019-02-28 17:59:04 +05:30
key_data_len + SHIFT_TBL_SIZE + 4 ,
( unsigned int ) ( sizeof ( spk_key_buf ) ) ) ;
2017-03-21 12:40:22 +05:30
return - EINVAL ;
}
2010-10-07 13:20:02 -05:00
memset ( k_buffer , 0 , SHIFT_TBL_SIZE ) ;
2013-01-02 02:37:40 +01:00
memset ( spk_our_keys , 0 , sizeof ( spk_our_keys ) ) ;
spk_shift_table = k_buffer ;
spk_our_keys [ 0 ] = spk_shift_table ;
2010-10-07 13:20:02 -05:00
cp1 + = SHIFT_TBL_SIZE ;
memcpy ( cp1 , cp , key_data_len + 3 ) ;
2010-10-15 22:13:34 -05:00
/* get num_keys, states and data */
cp1 + = 2 ; /* now pointing at shift states */
2010-10-07 13:20:02 -05:00
for ( i = 1 ; i < = states ; i + + ) {
ch = * cp1 + + ;
2017-03-21 12:40:22 +05:30
if ( ch > = SHIFT_TBL_SIZE ) {
2019-02-28 17:59:04 +05:30
pr_debug ( " (%d) not valid shift state (max_allowed = %d) \n " ,
ch , SHIFT_TBL_SIZE ) ;
2017-03-21 12:40:22 +05:30
return - EINVAL ;
}
2013-01-02 02:37:40 +01:00
spk_shift_table [ ch ] = i ;
2010-10-07 13:20:02 -05:00
}
keymap_flags = * cp1 + + ;
while ( ( ch = * cp1 ) ) {
2017-03-21 12:40:22 +05:30
if ( ch > = MAX_KEY ) {
2019-02-28 17:59:04 +05:30
pr_debug ( " (%d), not valid key, (max_allowed = %d) \n " ,
ch , MAX_KEY ) ;
2017-03-21 12:40:22 +05:30
return - EINVAL ;
}
2013-01-02 02:37:40 +01:00
spk_our_keys [ ch ] = cp1 ;
2010-10-07 13:20:02 -05:00
cp1 + = states + 1 ;
}
return 0 ;
}
2022-11-15 15:05:29 +05:00
enum spk_vars_id {
BELL_POS_ID = 0 , SPELL_DELAY_ID , ATTRIB_BLEEP_ID ,
BLEEPS_ID , BLEEP_TIME_ID , PUNC_LEVEL_ID ,
READING_PUNC_ID , CURSOR_TIME_ID , SAY_CONTROL_ID ,
SAY_WORD_CTL_ID , NO_INTERRUPT_ID , KEY_ECHO_ID ,
2022-11-15 15:05:30 +05:00
CUR_PHONETIC_ID , V_LAST_VAR_ID , NB_ID
2022-11-15 15:05:29 +05:00
} ;
static struct var_t spk_vars [ NB_ID ] = {
2010-10-07 13:20:02 -05:00
/* bell must be first to set high limit */
2022-11-15 15:05:29 +05:00
[ BELL_POS_ID ] = { BELL_POS , . u . n = { NULL , 0 , 0 , 0 , 0 , 0 , NULL } } ,
[ SPELL_DELAY_ID ] = { SPELL_DELAY , . u . n = { NULL , 0 , 0 , 4 , 0 , 0 , NULL } } ,
[ ATTRIB_BLEEP_ID ] = { ATTRIB_BLEEP , . u . n = { NULL , 1 , 0 , 3 , 0 , 0 , NULL } } ,
[ BLEEPS_ID ] = { BLEEPS , . u . n = { NULL , 3 , 0 , 3 , 0 , 0 , NULL } } ,
[ BLEEP_TIME_ID ] = { BLEEP_TIME , . u . n = { NULL , 30 , 1 , 200 , 0 , 0 , NULL } } ,
[ PUNC_LEVEL_ID ] = { PUNC_LEVEL , . u . n = { NULL , 1 , 0 , 4 , 0 , 0 , NULL } } ,
[ READING_PUNC_ID ] = { READING_PUNC , . u . n = { NULL , 1 , 0 , 4 , 0 , 0 , NULL } } ,
[ CURSOR_TIME_ID ] = { CURSOR_TIME , . u . n = { NULL , 120 , 50 , 600 , 0 , 0 , NULL } } ,
2023-04-30 17:16:17 -07:00
[ SAY_CONTROL_ID ] = { SAY_CONTROL , TOGGLE_0 } ,
2022-11-15 15:05:29 +05:00
[ SAY_WORD_CTL_ID ] = { SAY_WORD_CTL , TOGGLE_0 } ,
[ NO_INTERRUPT_ID ] = { NO_INTERRUPT , TOGGLE_0 } ,
[ KEY_ECHO_ID ] = { KEY_ECHO , . u . n = { NULL , 1 , 0 , 2 , 0 , 0 , NULL } } ,
2022-11-15 15:05:30 +05:00
[ CUR_PHONETIC_ID ] = { CUR_PHONETIC , . u . n = { NULL , 0 , 0 , 1 , 0 , 0 , NULL } } ,
2010-10-07 13:20:02 -05:00
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 ;
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_CURSOR_MSGS_START + cursor_track ) ) ;
2010-10-07 13:20:02 -05:00
}
2013-01-02 02:37:40 +01:00
void spk_reset_default_chars ( void )
2010-10-07 13:20:02 -05:00
{
int i ;
/* First, free any non-default */
for ( i = 0 ; i < 256 ; i + + ) {
2017-03-21 17:12:25 +05:30
if ( spk_characters [ i ] & &
( spk_characters [ i ] ! = spk_default_chars [ i ] ) )
2013-01-02 02:37:40 +01:00
kfree ( spk_characters [ i ] ) ;
2010-10-07 13:20:02 -05:00
}
2013-01-02 02:37:40 +01:00
memcpy ( spk_characters , spk_default_chars , sizeof ( spk_default_chars ) ) ;
2010-10-07 13:20:02 -05:00
}
2013-01-02 02:37:40 +01:00
void spk_reset_default_chartab ( void )
2010-10-07 13:20:02 -05:00
{
memcpy ( spk_chartab , default_chartab , sizeof ( default_chartab ) ) ;
}
2010-10-15 22:13:34 -05:00
static const struct st_bits_data * pb_edit ;
2010-10-07 13:20:02 -05:00
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 ] ;
2014-09-09 20:04:34 +02:00
2010-10-15 22:13:34 -05:00
if ( type ! = KT_LATIN | | ( ch_type & B_NUM ) | | ch < SPACE )
2010-10-07 13:20:02 -05:00
return - 1 ;
if ( ch = = SPACE ) {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_EDIT_DONE ) ) ;
spk_special_handler = NULL ;
2010-10-07 13:20:02 -05:00
return 1 ;
}
2010-10-15 22:13:34 -05:00
if ( mask < PUNC & & ! ( ch_type & PUNC ) )
2010-10-07 13:20:02 -05:00
return - 1 ;
spk_chartab [ ch ] ^ = mask ;
speak_char ( ch ) ;
synth_printf ( " %s \n " ,
2013-01-02 02:37:40 +01:00
( spk_chartab [ ch ] & mask ) ? spk_msg_get ( MSG_ON ) :
spk_msg_get ( MSG_OFF ) ) ;
2010-10-07 13:20:02 -05:00
return 1 ;
}
/* Allocation concurrency is protected by the console semaphore */
2017-03-24 14:07:11 +05:30
static int speakup_allocate ( struct vc_data * vc , gfp_t gfp_flags )
2010-10-07 13:20:02 -05:00
{
int vc_num ;
vc_num = vc - > vc_num ;
2017-03-24 16:59:59 +05:30
if ( ! speakup_console [ vc_num ] ) {
2010-10-07 13:20:02 -05:00
speakup_console [ vc_num ] = kzalloc ( sizeof ( * speakup_console [ 0 ] ) ,
2017-03-24 14:07:11 +05:30
gfp_flags ) ;
2017-03-04 22:16:54 +05:30
if ( ! speakup_console [ vc_num ] )
2010-12-19 22:50:24 +00:00
return - ENOMEM ;
2010-10-07 13:20:02 -05:00
speakup_date ( vc ) ;
2017-03-21 17:12:28 +05:30
} else if ( ! spk_parked ) {
2010-10-07 13:20:02 -05:00
speakup_date ( vc ) ;
2017-03-21 17:12:28 +05:30
}
2010-12-19 22:50:24 +00:00
return 0 ;
2010-10-07 13:20:02 -05:00
}
2013-05-22 14:37:25 +05:30
static void speakup_deallocate ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
int vc_num ;
vc_num = vc - > vc_num ;
2011-03-13 00:29:10 -05:00
kfree ( speakup_console [ vc_num ] ) ;
speakup_console [ vc_num ] = NULL ;
2010-10-07 13:20:02 -05:00
}
2020-11-02 10:59:45 +01:00
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 ,
} ;
2010-10-07 13:20:02 -05:00
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 * ) ;
2020-11-02 10:59:45 +01:00
static enum read_all_command read_all_key ;
2010-10-07 13:20:02 -05:00
2017-09-05 12:51:59 +01:00
static int in_keyboard_notifier ;
2020-11-02 10:59:45 +01:00
static void start_read_all_timer ( struct vc_data * vc , enum read_all_command command ) ;
2010-10-07 13:20:02 -05:00
2020-11-02 10:59:45 +01:00
static void kbd_fakekey2 ( struct vc_data * vc , enum read_all_command command )
2010-10-07 13:20:02 -05:00
{
del_timer ( & cursor_timer ) ;
speakup_fake_down_arrow ( ) ;
start_read_all_timer ( vc , command ) ;
}
2010-10-15 22:13:34 -05:00
static void read_all_doc ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
2017-03-24 16:59:59 +05:30
if ( ( vc - > vc_num ! = fg_console ) | | ! synth | | spk_shut_up )
2010-10-07 13:20:02 -05:00
return ;
if ( ! synth_supports_indexing ( ) )
return ;
if ( cursor_track ! = read_all_mode )
prev_cursor_track = cursor_track ;
cursor_track = read_all_mode ;
2013-01-02 02:37:40 +01:00
spk_reset_index_count ( 0 ) ;
2017-03-21 17:12:28 +05:30
if ( get_sentence_buf ( vc , 0 ) = = - 1 ) {
2017-09-05 12:51:59 +01:00
del_timer ( & cursor_timer ) ;
if ( ! in_keyboard_notifier )
speakup_fake_down_arrow ( ) ;
start_read_all_timer ( vc , RA_DOWN_ARROW ) ;
2017-03-21 17:12:28 +05:30
} else {
2010-10-07 13:20:02 -05:00
say_sentence_num ( 0 , 0 ) ;
synth_insert_next_index ( 0 ) ;
start_read_all_timer ( vc , RA_TIMER ) ;
}
}
2010-10-15 22:13:34 -05:00
static void stop_read_all ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
del_timer ( & cursor_timer ) ;
cursor_track = prev_cursor_track ;
spk_shut_up & = 0xfe ;
2013-01-02 02:37:40 +01:00
spk_do_flush ( ) ;
2010-10-07 13:20:02 -05:00
}
2020-11-02 10:59:45 +01:00
static void start_read_all_timer ( struct vc_data * vc , enum read_all_command command )
2010-10-07 13:20:02 -05:00
{
struct var_t * cursor_timeout ;
cursor_con = vc - > vc_num ;
read_all_key = command ;
2013-01-02 02:37:40 +01:00
cursor_timeout = spk_get_var ( CURSOR_TIME ) ;
2010-10-15 22:13:34 -05:00
mod_timer ( & cursor_timer ,
jiffies + msecs_to_jiffies ( cursor_timeout - > u . n . value ) ) ;
2010-10-07 13:20:02 -05:00
}
2020-11-02 10:59:45 +01:00
static void handle_cursor_read_all ( struct vc_data * vc , enum read_all_command command )
2010-10-07 13:20:02 -05:00
{
int indcount , sentcount , rv , sn ;
switch ( command ) {
case RA_NEXT_SENT :
/* Get Current Sentence */
2013-01-02 02:37:40 +01:00
spk_get_index_count ( & indcount , & sentcount ) ;
2010-10-07 13:20:02 -05:00
/*printk("%d %d ", indcount, sentcount); */
2013-01-02 02:37:40 +01:00
spk_reset_index_count ( sentcount + 1 ) ;
2010-10-07 13:20:02 -05:00
if ( indcount = = 1 ) {
2010-10-15 22:13:34 -05:00
if ( ! say_sentence_num ( sentcount + 1 , 0 ) ) {
2010-10-07 13:20:02 -05:00
kbd_fakekey2 ( vc , RA_FIND_NEXT_SENT ) ;
return ;
}
synth_insert_next_index ( 0 ) ;
} else {
sn = 0 ;
2010-10-15 22:13:34 -05:00
if ( ! say_sentence_num ( sentcount + 1 , 1 ) ) {
2010-10-07 13:20:02 -05:00
sn = 1 ;
2013-01-02 02:37:40 +01:00
spk_reset_index_count ( sn ) ;
2017-03-21 17:12:28 +05:30
} else {
2010-10-07 13:20:02 -05:00
synth_insert_next_index ( 0 ) ;
2017-03-21 17:12:28 +05:30
}
2010-10-07 13:20:02 -05:00
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 ) ;
2017-03-21 17:12:28 +05:30
if ( rv = = 0 ) {
2010-10-07 13:20:02 -05:00
kbd_fakekey2 ( vc , RA_FIND_NEXT_SENT ) ;
2017-03-21 17:12:28 +05:30
} else {
2010-10-07 13:20:02 -05:00
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 :
2013-01-02 02:37:40 +01:00
spk_get_index_count ( & indcount , & sentcount ) ;
2010-10-07 13:20:02 -05:00
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 ;
2014-09-09 20:04:34 +02:00
2013-05-13 00:02:56 -05:00
spin_lock_irqsave ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
if ( cursor_track = = read_all_mode ) {
spk_parked & = 0xfe ;
2017-03-24 16:59:59 +05:30
if ( ! synth | | up_flag | | spk_shut_up ) {
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
return NOTIFY_STOP ;
}
del_timer ( & cursor_timer ) ;
spk_shut_up & = 0xfe ;
2013-01-02 02:37:40 +01:00
spk_do_flush ( ) ;
2010-10-15 22:13:34 -05:00
start_read_all_timer ( vc , value + 1 ) ;
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
return NOTIFY_STOP ;
}
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
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 ;
2013-05-13 00:02:56 -05:00
spin_lock_irqsave ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
spk_parked & = 0xfe ;
2017-03-24 16:59:59 +05:30
if ( ! synth | | up_flag | | spk_shut_up | | cursor_track = = CT_Off ) {
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
return ;
}
spk_shut_up & = 0xfe ;
2013-01-02 02:37:40 +01:00
if ( spk_no_intr )
spk_do_flush ( ) ;
2010-10-07 13:20:02 -05:00
/* the key press flushes if !no_inter but we want to flush on cursor
2015-08-14 22:34:37 +03:00
* moves regardless of no_inter state
*/
2010-10-07 13:20:02 -05:00
is_cursor = value + 1 ;
old_cursor_pos = vc - > vc_pos ;
2020-06-15 09:48:33 +02:00
old_cursor_x = vc - > state . x ;
old_cursor_y = vc - > state . y ;
speakup_console [ vc - > vc_num ] - > ht . cy = vc - > state . y ;
2010-10-07 13:20:02 -05:00
cursor_con = vc - > vc_num ;
if ( cursor_track = = CT_Highlight )
reset_highlight_buffers ( vc ) ;
2013-01-02 02:37:40 +01:00
cursor_timeout = spk_get_var ( CURSOR_TIME ) ;
2010-10-15 22:13:34 -05:00
mod_timer ( & cursor_timer ,
jiffies + msecs_to_jiffies ( cursor_timeout - > u . n . value ) ) ;
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
}
2017-03-04 15:01:56 +01:00
static void update_color_buffer ( struct vc_data * vc , const u16 * ic , int len )
2010-10-07 13:20:02 -05:00
{
int i , bi , hi ;
int vc_num = vc - > vc_num ;
2015-03-04 07:35:28 +02:00
bi = ( vc - > vc_attr & 0x70 ) > > 4 ;
2010-10-07 13:20:02 -05:00
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 ;
2020-06-15 09:48:33 +02:00
speakup_console [ vc_num ] - > ht . rx [ bi ] = vc - > state . x ;
speakup_console [ vc_num ] - > ht . ry [ bi ] = vc - > state . y ;
2010-10-07 13:20:02 -05:00
}
while ( ( hi < COLOR_BUFFER_SIZE ) & & ( i < len ) ) {
2017-03-04 15:01:56 +01:00
if ( ic [ i ] > 32 ) {
2010-10-07 13:20:02 -05:00
speakup_console [ vc_num ] - > ht . highbuf [ bi ] [ hi ] = ic [ i ] ;
hi + + ;
} else if ( ( ic [ i ] = = 32 ) & & ( hi ! = 0 ) ) {
2010-10-15 22:13:34 -05:00
if ( speakup_console [ vc_num ] - > ht . highbuf [ bi ] [ hi - 1 ] ! =
32 ) {
2010-10-07 13:20:02 -05:00
speakup_console [ vc_num ] - > ht . highbuf [ bi ] [ hi ] =
2010-10-15 22:13:34 -05:00
ic [ i ] ;
2010-10-07 13:20:02 -05:00
hi + + ;
}
}
i + + ;
}
speakup_console [ vc_num ] - > ht . highsize [ bi ] = hi ;
}
2010-10-15 22:13:34 -05:00
static void reset_highlight_buffers ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
int i ;
int vc_num = vc - > vc_num ;
2014-09-09 20:04:34 +02:00
2010-10-15 22:13:34 -05:00
for ( i = 0 ; i < 8 ; i + + )
2010-10-07 13:20:02 -05:00
speakup_console [ vc_num ] - > ht . highsize [ i ] = 0 ;
}
2010-10-15 22:13:34 -05:00
static int count_highlight_color ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
int i , bg ;
int cc ;
int vc_num = vc - > vc_num ;
u16 ch ;
2016-11-06 15:09:18 +01:00
u16 * start = ( u16 * ) vc - > vc_origin ;
2010-10-07 13:20:02 -05:00
for ( i = 0 ; i < 8 ; i + + )
speakup_console [ vc_num ] - > ht . bgcount [ i ] = 0 ;
for ( i = 0 ; i < vc - > vc_rows ; i + + ) {
2010-10-15 22:13:34 -05:00
u16 * end = start + vc - > vc_cols * 2 ;
2010-10-07 13:20:02 -05:00
u16 * ptr ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
for ( ptr = start ; ptr < end ; ptr + + ) {
2016-01-25 01:32:08 +01:00
ch = get_attributes ( vc , ptr ) ;
2010-10-07 13:20:02 -05:00
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 ;
}
2010-10-15 22:13:34 -05:00
static int get_highlight_color ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
int i , j ;
2015-06-10 18:33:38 +02:00
unsigned int cptr [ 8 ] ;
2010-10-07 13:20:02 -05:00
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 ] ] >
2015-06-10 18:33:38 +02:00
speakup_console [ vc_num ] - > ht . bgcount [ cptr [ j ] ] )
swap ( cptr [ i ] , cptr [ j ] ) ;
2010-10-07 13:20:02 -05:00
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 ;
}
2010-10-15 22:13:34 -05:00
static int speak_highlight ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
int hc , d ;
int vc_num = vc - > vc_num ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
if ( count_highlight_color ( vc ) = = 1 )
return 0 ;
hc = get_highlight_color ( vc ) ;
if ( hc ! = - 1 ) {
2020-06-15 09:48:33 +02:00
d = vc - > state . y - speakup_console [ vc_num ] - > ht . cy ;
2010-10-07 13:20:02 -05:00
if ( ( d = = 1 ) | | ( d = = - 1 ) )
2020-06-15 09:48:33 +02:00
if ( speakup_console [ vc_num ] - > ht . ry [ hc ] ! = vc - > state . y )
2010-10-07 13:20:02 -05:00
return 0 ;
spk_parked | = 0x01 ;
2013-01-02 02:37:40 +01:00
spk_do_flush ( ) ;
2010-10-07 13:20:02 -05:00
spkup_write ( speakup_console [ vc_num ] - > ht . highbuf [ hc ] ,
2010-10-15 22:13:34 -05:00
speakup_console [ vc_num ] - > ht . highsize [ hc ] ) ;
2010-10-07 13:20:02 -05:00
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 ;
}
2017-08-28 11:28:21 -07:00
static void cursor_done ( struct timer_list * unused )
2010-10-07 13:20:02 -05:00
{
struct vc_data * vc = vc_cons [ cursor_con ] . d ;
unsigned long flags ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
del_timer ( & cursor_timer ) ;
2013-05-13 00:02:56 -05:00
spin_lock_irqsave ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
if ( cursor_con ! = fg_console ) {
is_cursor = 0 ;
goto out ;
}
speakup_date ( vc ) ;
if ( win_enabled ) {
2020-06-15 09:48:33 +02:00
if ( vc - > state . x > = win_left & & vc - > state . x < = win_right & &
vc - > state . y > = win_top & & vc - > state . y < = win_bottom ) {
2016-02-23 21:38:58 -08:00
spk_keydown = 0 ;
is_cursor = 0 ;
2010-10-07 13:20:02 -05:00
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 ) ) {
2016-02-23 21:38:58 -08:00
spk_keydown = 0 ;
is_cursor = 0 ;
2010-10-07 13:20:02 -05:00
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 ) ;
2022-11-15 15:05:30 +05:00
else {
if ( spk_cur_phonetic = = 1 )
say_phonetic_char ( vc ) ;
else
say_char ( vc ) ;
}
2016-02-23 21:38:58 -08:00
spk_keydown = 0 ;
is_cursor = 0 ;
2010-10-07 13:20:02 -05:00
out :
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
}
/* called by: vt_notifier_call() */
static void speakup_bs ( struct vc_data * vc )
{
unsigned long flags ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
if ( ! speakup_console [ vc - > vc_num ] )
return ;
2013-05-13 00:02:56 -05:00
if ( ! spin_trylock_irqsave ( & speakup_info . spinlock , flags ) )
2010-10-07 13:20:02 -05:00
/* Speakup output, discard */
return ;
if ( ! spk_parked )
speakup_date ( vc ) ;
2017-03-24 16:59:59 +05:30
if ( spk_shut_up | | ! synth ) {
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
return ;
}
if ( vc - > vc_num = = fg_console & & spk_keydown ) {
spk_keydown = 0 ;
if ( ! is_cursor )
say_char ( vc ) ;
}
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
}
/* called by: vt_notifier_call() */
2017-03-04 15:01:56 +01:00
static void speakup_con_write ( struct vc_data * vc , u16 * str , int len )
2010-10-07 13:20:02 -05:00
{
unsigned long flags ;
2014-09-09 20:04:34 +02:00
2017-03-24 16:59:59 +05:30
if ( ( vc - > vc_num ! = fg_console ) | | spk_shut_up | | ! synth )
2010-10-07 13:20:02 -05:00
return ;
2013-05-13 00:02:56 -05:00
if ( ! spin_trylock_irqsave ( & speakup_info . spinlock , flags ) )
2010-10-07 13:20:02 -05:00
/* Speakup output, discard */
return ;
2020-06-15 09:48:33 +02:00
if ( spk_bell_pos & & spk_keydown & & ( vc - > state . x = = spk_bell_pos - 1 ) )
2010-10-07 13:20:02 -05:00
bleep ( 3 ) ;
if ( ( is_cursor ) | | ( cursor_track = = read_all_mode ) ) {
if ( cursor_track = = CT_Highlight )
update_color_buffer ( vc , str , len ) ;
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
return ;
}
if ( win_enabled ) {
2020-06-15 09:48:33 +02:00
if ( vc - > state . x > = win_left & & vc - > state . x < = win_right & &
vc - > state . y > = win_top & & vc - > state . y < = win_bottom ) {
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
return ;
}
}
spkup_write ( str , len ) ;
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
}
2013-05-22 14:37:25 +05:30
static void speakup_con_update ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
unsigned long flags ;
2014-09-09 20:04:34 +02:00
2022-10-10 21:57:20 +05:00
if ( ! speakup_console [ vc - > vc_num ] | | spk_parked | | ! synth )
2010-10-07 13:20:02 -05:00
return ;
2013-05-13 00:02:56 -05:00
if ( ! spin_trylock_irqsave ( & speakup_info . spinlock , flags ) )
2010-10-07 13:20:02 -05:00
/* Speakup output, discard */
return ;
speakup_date ( vc ) ;
2018-05-13 11:38:30 +02:00
if ( vc - > vc_mode = = KD_GRAPHICS & & ! spk_paused & & spk_str_pause [ 0 ] ) {
2018-05-02 02:56:10 +02:00
synth_printf ( " %s " , spk_str_pause ) ;
2018-05-14 22:57:25 +02:00
spk_paused = true ;
2018-05-02 02:56:10 +02:00
}
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
}
static void do_handle_spec ( struct vc_data * vc , u_char value , char up_flag )
{
unsigned long flags ;
int on_off = 2 ;
char * label ;
2014-09-09 20:04:34 +02:00
2017-03-24 16:59:59 +05:30
if ( ! synth | | up_flag | | spk_killed )
2010-10-07 13:20:02 -05:00
return ;
2013-05-13 00:02:56 -05:00
spin_lock_irqsave ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
spk_shut_up & = 0xfe ;
2013-01-02 02:37:40 +01:00
if ( spk_no_intr )
spk_do_flush ( ) ;
2010-10-07 13:20:02 -05:00
switch ( value ) {
case KVAL ( K_CAPS ) :
2013-01-02 02:37:40 +01:00
label = spk_msg_get ( MSG_KEYNAME_CAPSLOCK ) ;
2012-02-28 14:49:23 +00:00
on_off = vt_get_leds ( fg_console , VC_CAPSLOCK ) ;
2010-10-07 13:20:02 -05:00
break ;
case KVAL ( K_NUM ) :
2013-01-02 02:37:40 +01:00
label = spk_msg_get ( MSG_KEYNAME_NUMLOCK ) ;
2012-02-28 14:49:23 +00:00
on_off = vt_get_leds ( fg_console , VC_NUMLOCK ) ;
2010-10-07 13:20:02 -05:00
break ;
case KVAL ( K_HOLD ) :
2013-01-02 02:37:40 +01:00
label = spk_msg_get ( MSG_KEYNAME_SCROLLLOCK ) ;
2012-02-28 14:49:23 +00:00
on_off = vt_get_leds ( fg_console , VC_SCROLLOCK ) ;
2010-10-07 13:20:02 -05:00
if ( speakup_console [ vc - > vc_num ] )
speakup_console [ vc - > vc_num ] - > tty_stopped = on_off ;
break ;
default :
spk_parked & = 0xfe ;
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
return ;
}
if ( on_off < 2 )
synth_printf ( " %s %s \n " ,
2013-01-02 02:37:40 +01:00
label , spk_msg_get ( MSG_STATUS_START + on_off ) ) ;
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
}
2010-10-15 22:13:34 -05:00
static int inc_dec_var ( u_char value )
2010-10-07 13:20:02 -05:00
{
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 ;
2010-10-15 22:13:34 -05:00
int how = ( var_id & 1 ) ? E_INC : E_DEC ;
2014-09-09 20:04:34 +02:00
2010-10-15 22:13:34 -05:00
var_id = var_id / 2 + FIRST_SET_VAR ;
2013-01-02 02:37:40 +01:00
p_header = spk_get_var_header ( var_id ) ;
2017-03-24 16:59:59 +05:30
if ( ! p_header )
2010-10-07 13:20:02 -05:00
return - 1 ;
if ( p_header - > var_type ! = VAR_NUM )
return - 1 ;
var_data = p_header - > data ;
2013-01-02 02:37:40 +01:00
if ( spk_set_num_var ( 1 , p_header , how ) ! = 0 )
2010-10-07 13:20:02 -05:00
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 " ,
2010-10-15 22:13:34 -05:00
var_data - > u . n . value ) ;
2010-10-07 13:20:02 -05:00
synth_printf ( " %s " , num_buf ) ;
return 0 ;
}
2010-10-15 22:13:34 -05:00
static void speakup_win_set ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
char info [ 40 ] ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
if ( win_start > 1 ) {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_WINDOW_ALREADY_SET ) ) ;
2010-10-07 13:20:02 -05:00
return ;
}
if ( spk_x < win_left | | spk_y < win_top ) {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_END_BEFORE_START ) ) ;
2010-10-07 13:20:02 -05:00
return ;
}
if ( win_start & & spk_x = = win_left & & spk_y = = win_top ) {
win_left = 0 ;
2010-10-15 22:13:34 -05:00
win_right = vc - > vc_cols - 1 ;
2010-10-07 13:20:02 -05:00
win_bottom = spk_y ;
2013-01-02 02:37:40 +01:00
snprintf ( info , sizeof ( info ) , spk_msg_get ( MSG_WINDOW_LINE ) ,
2010-10-15 22:13:34 -05:00
( int ) win_top + 1 ) ;
2010-10-07 13:20:02 -05:00
} else {
if ( ! win_start ) {
win_top = spk_y ;
win_left = spk_x ;
} else {
win_bottom = spk_y ;
win_right = spk_x ;
}
2013-01-02 02:37:40 +01:00
snprintf ( info , sizeof ( info ) , spk_msg_get ( MSG_WINDOW_BOUNDARY ) ,
2015-03-28 13:21:39 -07:00
( win_start ) ?
spk_msg_get ( MSG_END ) : spk_msg_get ( MSG_START ) ,
2010-10-15 22:13:34 -05:00
( int ) spk_y + 1 , ( int ) spk_x + 1 ) ;
2010-10-07 13:20:02 -05:00
}
synth_printf ( " %s \n " , info ) ;
win_start + + ;
}
2010-10-15 22:13:34 -05:00
static void speakup_win_clear ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
2016-02-23 21:38:58 -08:00
win_top = 0 ;
win_bottom = 0 ;
win_left = 0 ;
win_right = 0 ;
2010-10-07 13:20:02 -05:00
win_start = 0 ;
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_WINDOW_CLEARED ) ) ;
2010-10-07 13:20:02 -05:00
}
2010-10-15 22:13:34 -05:00
static void speakup_win_enable ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
if ( win_start < 2 ) {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_NO_WINDOW ) ) ;
2010-10-07 13:20:02 -05:00
return ;
}
win_enabled ^ = 1 ;
if ( win_enabled )
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_WINDOW_SILENCED ) ) ;
2010-10-07 13:20:02 -05:00
else
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_WINDOW_SILENCE_DISABLED ) ) ;
2010-10-07 13:20:02 -05:00
}
2010-10-15 22:13:34 -05:00
static void speakup_bits ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
int val = this_speakup_key - ( FIRST_EDIT_BITS - 1 ) ;
2014-09-09 20:04:34 +02:00
2017-03-24 16:59:59 +05:30
if ( spk_special_handler | | val < 1 | | val > 6 ) {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_ERROR ) ) ;
2010-10-07 13:20:02 -05:00
return ;
}
2013-01-02 02:37:40 +01:00
pb_edit = & spk_punc_info [ val ] ;
synth_printf ( spk_msg_get ( MSG_EDIT_PROMPT ) , pb_edit - > name ) ;
spk_special_handler = edit_bits ;
2010-10-07 13:20:02 -05:00
}
static int handle_goto ( struct vc_data * vc , u_char type , u_char ch , u_short key )
{
2012-06-16 16:55:20 -05:00
static u_char goto_buf [ 8 ] ;
2010-10-15 22:13:34 -05:00
static int num ;
2014-04-09 19:45:46 +09:00
int maxlen ;
2010-10-07 13:20:02 -05:00
char * cp ;
2017-03-04 15:01:56 +01:00
u16 wch ;
2014-04-09 19:45:46 +09:00
2010-10-07 13:20:02 -05:00
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 ) {
2017-03-04 15:01:56 +01:00
u16 wch ;
2017-06-09 14:14:32 +02:00
2010-10-07 13:20:02 -05:00
if ( num = = 0 )
return - 1 ;
2017-03-04 15:01:56 +01:00
wch = goto_buf [ - - num ] ;
2010-10-07 13:20:02 -05:00
goto_buf [ num ] = ' \0 ' ;
2017-03-04 15:01:56 +01:00
spkup_write ( & wch , 1 ) ;
2010-10-07 13:20:02 -05:00
return 1 ;
}
if ( ch < ' + ' | | ch > ' y ' )
goto oops ;
2017-03-04 15:01:56 +01:00
wch = ch ;
2010-10-07 13:20:02 -05:00
goto_buf [ num + + ] = ch ;
goto_buf [ num ] = ' \0 ' ;
2017-03-04 15:01:56 +01:00
spkup_write ( & wch , 1 ) ;
2010-10-07 13:20:02 -05:00
maxlen = ( * goto_buf > = ' 0 ' ) ? 3 : 4 ;
if ( ( ch = = ' + ' | | ch = = ' - ' ) & & num = = 1 )
return 1 ;
if ( ch > = ' 0 ' & & ch < = ' 9 ' & & num < maxlen )
return 1 ;
2010-10-15 22:13:34 -05:00
if ( num < maxlen - 1 | | num > maxlen )
2010-10-07 13:20:02 -05:00
goto oops ;
if ( ch < ' x ' | | ch > ' y ' ) {
oops :
if ( ! spk_killed )
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_GOTO_CANCELED ) ) ;
2010-10-07 13:20:02 -05:00
goto_buf [ num = 0 ] = ' \0 ' ;
2013-01-02 02:37:40 +01:00
spk_special_handler = NULL ;
2010-10-07 13:20:02 -05:00
return 1 ;
}
2014-04-09 19:45:46 +09:00
2019-02-23 20:42:19 +01:00
/* Do not replace with kstrtoul: here we need cp to be updated */
2014-04-09 19:45:46 +09:00
goto_pos = simple_strtoul ( goto_buf , & cp , 10 ) ;
2010-10-07 13:20:02 -05:00
if ( * cp = = ' x ' ) {
if ( * goto_buf < ' 0 ' )
goto_pos + = spk_x ;
2014-04-09 19:45:46 +09:00
else if ( goto_pos > 0 )
2010-10-07 13:20:02 -05:00
goto_pos - - ;
2014-04-09 19:45:46 +09:00
2010-10-07 13:20:02 -05:00
if ( goto_pos > = vc - > vc_cols )
2010-10-15 22:13:34 -05:00
goto_pos = vc - > vc_cols - 1 ;
2010-10-07 13:20:02 -05:00
goto_x = 1 ;
} else {
if ( * goto_buf < ' 0 ' )
goto_pos + = spk_y ;
2014-04-09 19:45:46 +09:00
else if ( goto_pos > 0 )
2010-10-07 13:20:02 -05:00
goto_pos - - ;
2014-04-09 19:45:46 +09:00
2010-10-07 13:20:02 -05:00
if ( goto_pos > = vc - > vc_rows )
2010-10-15 22:13:34 -05:00
goto_pos = vc - > vc_rows - 1 ;
2010-10-07 13:20:02 -05:00
goto_x = 0 ;
}
2010-10-15 22:13:34 -05:00
goto_buf [ num = 0 ] = ' \0 ' ;
2010-10-07 13:20:02 -05:00
do_goto :
2013-01-02 02:37:40 +01:00
spk_special_handler = NULL ;
2010-10-07 13:20:02 -05:00
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 ;
}
2010-10-15 22:13:34 -05:00
static void speakup_goto ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
2017-03-24 16:59:59 +05:30
if ( spk_special_handler ) {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_ERROR ) ) ;
2010-10-07 13:20:02 -05:00
return ;
}
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_GOTO ) ) ;
spk_special_handler = handle_goto ;
2010-10-07 13:20:02 -05:00
}
static void speakup_help ( struct vc_data * vc )
{
2013-01-02 02:37:40 +01:00
spk_handle_help ( vc , KT_SPKUP , SPEAKUP_HELP , 0 ) ;
2010-10-07 13:20:02 -05:00
}
2010-10-15 22:13:34 -05:00
static void do_nothing ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
2010-10-15 22:13:34 -05:00
return ; /* flush done in do_spkup */
2010-10-07 13:20:02 -05:00
}
2010-10-15 22:13:34 -05:00
2010-10-07 13:20:02 -05:00
static u_char key_speakup , spk_key_locked ;
2010-10-15 22:13:34 -05:00
static void speakup_lock ( struct vc_data * vc )
2010-10-07 13:20:02 -05:00
{
2016-02-23 21:38:58 -08:00
if ( ! spk_key_locked ) {
spk_key_locked = 16 ;
key_speakup = 16 ;
} else {
spk_key_locked = 0 ;
key_speakup = 0 ;
}
2010-10-07 13:20:02 -05:00
}
2010-10-15 22:13:34 -05:00
typedef void ( * spkup_hand ) ( struct vc_data * ) ;
2013-05-22 14:37:25 +05:30
static spkup_hand spkup_handler [ ] = {
2010-10-07 13:20:02 -05:00
/* 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 ,
2010-10-15 22:13:34 -05:00
speakup_off , speakup_parked , say_line , /* this is for indent */
2010-10-07 13:20:02 -05:00
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 ] ) {
2013-01-02 02:37:40 +01:00
spk_do_flush ( ) ;
2010-10-15 22:13:34 -05:00
( * spkup_handler [ value ] ) ( vc ) ;
2010-10-07 13:20:02 -05:00
} else {
if ( inc_dec_var ( value ) < 0 )
bleep ( 9 ) ;
}
}
static const char * pad_chars = " 0123456789+-*/ \015 ,.?() " ;
2013-05-22 14:37:25 +05:30
static int
2010-10-07 13:20:02 -05:00
speakup_key ( struct vc_data * vc , int shift_state , int keycode , u_short keysym ,
2010-10-15 22:13:34 -05:00
int up_flag )
2010-10-07 13:20:02 -05:00
{
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 ;
2014-09-09 20:04:34 +02:00
2017-09-18 01:30:35 +05:30
if ( ! synth )
2010-10-07 13:20:02 -05:00
return 0 ;
2013-05-13 00:02:56 -05:00
spin_lock_irqsave ( & speakup_info . spinlock , flags ) ;
2010-10-07 19:30:49 -07:00
tty = vc - > port . tty ;
2010-10-07 13:20:02 -05:00
if ( type > = 0xf0 )
type - = 0xf0 ;
2017-03-21 17:12:25 +05:30
if ( type = = KT_PAD & &
( vt_get_leds ( fg_console , VC_NUMLOCK ) ) ) {
2010-10-07 13:20:02 -05:00
if ( up_flag ) {
spk_keydown = 0 ;
goto out ;
}
2020-03-15 23:12:47 +01:00
value = pad_chars [ value ] ;
spk_lastkey = value ;
2010-10-07 13:20:02 -05:00
spk_keydown + + ;
spk_parked & = 0xfe ;
goto no_map ;
}
if ( keycode > = MAX_KEY )
goto no_map ;
2013-01-02 02:37:40 +01:00
key_info = spk_our_keys [ keycode ] ;
2013-05-22 16:19:30 +05:30
if ( ! key_info )
2010-10-07 13:20:02 -05:00
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 ;
}
}
2010-10-15 22:13:34 -05:00
shift_info = ( shift_state & 0x0f ) + key_speakup ;
2013-01-02 02:37:40 +01:00
offset = spk_shift_table [ shift_info ] ;
2010-10-07 13:20:02 -05:00
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 ;
2013-01-02 02:37:40 +01:00
spk_do_flush ( ) ;
2010-10-07 13:20:02 -05:00
goto out ;
}
if ( up_flag )
goto out ;
if ( last_keycode = = keycode & &
2014-06-13 01:17:30 +02:00
time_after ( last_spk_jiffy + MAX_DELAY , jiffies ) ) {
2010-10-07 13:20:02 -05:00
spk_close_press = 1 ;
2013-01-02 02:37:40 +01:00
offset = spk_shift_table [ shift_info + 32 ] ;
2010-10-15 22:13:34 -05:00
/* double press? */
2010-10-07 13:20:02 -05:00
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 :
2017-03-24 16:59:59 +05:30
if ( type = = KT_SPKUP & & ! spk_special_handler ) {
2010-10-07 13:20:02 -05:00
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 ;
2017-03-21 17:12:30 +05:30
kh = ( value = = KVAL ( K_DOWN ) ) | |
( value = = KVAL ( K_UP ) ) | |
( value = = KVAL ( K_LEFT ) ) | |
( value = = KVAL ( K_RIGHT ) ) ;
2010-10-07 13:20:02 -05:00
if ( ( cursor_track ! = read_all_mode ) | | ! kh )
2013-01-02 02:37:40 +01:00
if ( ! spk_no_intr )
spk_do_flush ( ) ;
if ( spk_special_handler ) {
2010-10-07 13:20:02 -05:00
if ( type = = KT_SPEC & & value = = 1 ) {
value = ' \n ' ;
type = KT_LATIN ;
2017-03-21 17:12:28 +05:30
} else if ( type = = KT_LETTER ) {
2010-10-07 13:20:02 -05:00
type = KT_LATIN ;
2017-03-21 17:12:28 +05:30
} else if ( value = = 0x7f ) {
2010-10-15 22:13:34 -05:00
value = 8 ; /* make del = backspace */
2017-03-21 17:12:28 +05:30
}
2013-01-02 02:37:40 +01:00
ret = ( * spk_special_handler ) ( vc , type , value , keycode ) ;
2010-10-07 13:20:02 -05:00
spk_close_press = 0 ;
if ( ret < 0 )
bleep ( 9 ) ;
goto out ;
}
last_keycode = 0 ;
out :
2013-05-13 00:02:56 -05:00
spin_unlock_irqrestore ( & speakup_info . spinlock , flags ) ;
2010-10-07 13:20:02 -05:00
return ret ;
}
static int keyboard_notifier_call ( struct notifier_block * nb ,
2010-10-15 22:13:34 -05:00
unsigned long code , void * _param )
2010-10-07 13:20:02 -05:00
{
struct keyboard_notifier_param * param = _param ;
struct vc_data * vc = param - > vc ;
int up = ! param - > down ;
int ret = NOTIFY_OK ;
2010-10-15 22:13:34 -05:00
static int keycode ; /* to hold the current keycode */
2010-10-07 13:20:02 -05:00
2017-09-05 12:51:59 +01:00
in_keyboard_notifier = 1 ;
2010-10-07 13:20:02 -05:00
if ( vc - > vc_mode = = KD_GRAPHICS )
2017-09-05 12:51:59 +01:00
goto out ;
2010-10-07 13:20:02 -05:00
/*
* 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 ( ) )
2017-09-05 12:51:59 +01:00
goto out ;
2010-10-07 13:20:02 -05:00
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 ;
2010-10-15 22:13:34 -05:00
else if ( KTYP ( param - > value ) = = KT_CUR )
ret = pre_handle_cursor ( vc , KVAL ( param - > value ) , up ) ;
2010-10-07 13:20:02 -05:00
break ;
2010-10-15 22:13:34 -05:00
case KBD_POST_KEYSYM : {
unsigned char type = KTYP ( param - > value ) - 0xf0 ;
unsigned char val = KVAL ( param - > value ) ;
2014-09-09 20:04:34 +02:00
2010-10-15 22:13:34 -05:00
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 ;
}
2010-10-07 13:20:02 -05:00
break ;
}
}
2017-09-05 12:51:59 +01:00
out :
in_keyboard_notifier = 0 ;
2010-10-07 13:20:02 -05:00
return ret ;
}
static int vt_notifier_call ( struct notifier_block * nb ,
2010-10-15 22:13:34 -05:00
unsigned long code , void * _param )
2010-10-07 13:20:02 -05:00
{
struct vt_notifier_param * param = _param ;
struct vc_data * vc = param - > vc ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
switch ( code ) {
case VT_ALLOCATE :
if ( vc - > vc_mode = = KD_TEXT )
2017-03-24 14:07:11 +05:30
speakup_allocate ( vc , GFP_ATOMIC ) ;
2010-10-07 13:20:02 -05:00
break ;
case VT_DEALLOCATE :
speakup_deallocate ( vc ) ;
break ;
case VT_WRITE :
2017-03-21 17:12:28 +05:30
if ( param - > c = = ' \b ' ) {
2010-10-07 13:20:02 -05:00
speakup_bs ( vc ) ;
2017-03-21 17:12:28 +05:30
} else {
2017-03-04 15:01:56 +01:00
u16 d = param - > c ;
2017-06-09 14:14:32 +02:00
2010-10-15 22:13:34 -05:00
speakup_con_write ( vc , & d , 1 ) ;
}
2010-10-07 13:20:02 -05:00
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 ( ) ;
2019-04-17 13:21:14 +01:00
speakup_cancel_selection ( ) ;
2014-05-19 00:56:22 +01:00
speakup_cancel_paste ( ) ;
2016-03-06 06:45:07 +05:30
del_timer_sync ( & cursor_timer ) ;
2010-10-07 13:20:02 -05:00
kthread_stop ( speakup_task ) ;
speakup_task = NULL ;
mutex_lock ( & spk_mutex ) ;
synth_release ( ) ;
mutex_unlock ( & spk_mutex ) ;
2017-07-16 17:18:26 +01:00
spk_ttyio_unregister_ldisc ( ) ;
2010-10-07 13:20:02 -05:00
2010-12-19 22:50:24 +00:00
speakup_kobj_exit ( ) ;
for ( i = 0 ; i < MAX_NR_CONSOLES ; i + + )
kfree ( speakup_console [ i ] ) ;
speakup_remove_virtual_keyboard ( ) ;
2010-10-07 13:20:02 -05:00
for ( i = 0 ; i < MAXVARS ; i + + )
speakup_unregister_var ( i ) ;
for ( i = 0 ; i < 256 ; i + + ) {
2013-01-02 02:37:40 +01:00
if ( spk_characters [ i ] ! = spk_default_chars [ i ] )
kfree ( spk_characters [ i ] ) ;
2010-10-07 13:20:02 -05:00
}
2010-12-19 22:50:24 +00:00
2013-01-02 02:37:40 +01:00
spk_free_user_msgs ( ) ;
2010-10-07 13:20:02 -05:00
}
/* call by: module_init() */
static int __init speakup_init ( void )
{
int i ;
2010-12-19 22:50:24 +00:00
long err = 0 ;
2010-10-07 13:20:02 -05:00
struct vc_data * vc = vc_cons [ fg_console ] . d ;
struct var_t * var ;
2010-12-19 22:50:24 +00:00
/* These first few initializations cannot fail. */
2013-01-02 02:37:40 +01:00
spk_initialize_msgs ( ) ; /* Initialize arrays for i18n. */
spk_reset_default_chars ( ) ;
spk_reset_default_chartab ( ) ;
spk_strlwr ( synth_name ) ;
2010-10-07 13:20:02 -05:00
spk_vars [ 0 ] . u . n . high = vc - > vc_cols ;
2010-10-15 22:13:34 -05:00
for ( var = spk_vars ; var - > var_id ! = MAXVARS ; var + + )
2010-10-07 13:20:02 -05:00
speakup_register_var ( var ) ;
2010-10-15 22:13:34 -05:00
for ( var = synth_time_vars ;
( var - > var_id > = 0 ) & & ( var - > var_id < MAXVARS ) ; var + + )
2010-10-07 13:20:02 -05:00
speakup_register_var ( var ) ;
2013-01-02 02:37:40 +01:00
for ( i = 1 ; spk_punc_info [ i ] . mask ! = 0 ; i + + )
2013-05-22 16:19:30 +05:30
spk_set_mask_bits ( NULL , i , 2 ) ;
2010-10-07 13:20:02 -05:00
2013-01-02 02:37:40 +01:00
spk_set_key_info ( spk_key_defaults , spk_key_buf ) ;
2010-10-07 13:20:02 -05:00
2010-12-19 22:50:24 +00:00
/* From here on out, initializations can fail. */
err = speakup_add_virtual_keyboard ( ) ;
if ( err )
goto error_virtkeyboard ;
2010-10-07 13:20:02 -05:00
for ( i = 0 ; i < MAX_NR_CONSOLES ; i + + )
2010-12-19 22:50:24 +00:00
if ( vc_cons [ i ] . d ) {
2017-03-24 14:07:11 +05:30
err = speakup_allocate ( vc_cons [ i ] . d , GFP_KERNEL ) ;
2010-12-19 22:50:24 +00:00
if ( err )
goto error_kobjects ;
}
2013-01-02 02:37:40 +01:00
if ( spk_quiet_boot )
2011-11-22 13:46:23 -06:00
spk_shut_up | = 0x01 ;
2010-12-19 22:50:24 +00:00
err = speakup_kobj_init ( ) ;
if ( err )
goto error_kobjects ;
2010-10-07 13:20:02 -05:00
2017-07-16 17:18:26 +01:00
spk_ttyio_register_ldisc ( ) ;
2010-10-07 13:20:02 -05:00
synth_init ( synth_name ) ;
speakup_register_devsynth ( ) ;
2010-12-19 22:50:24 +00:00
/*
* 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 .
*/
2010-10-07 13:20:02 -05:00
2010-12-19 22:50:24 +00:00
err = register_keyboard_notifier ( & keyboard_notifier_block ) ;
if ( err )
goto error_kbdnotifier ;
err = register_vt_notifier ( & vt_notifier_block ) ;
if ( err )
goto error_vtnotifier ;
2010-10-07 13:20:02 -05:00
speakup_task = kthread_create ( speakup_thread , NULL , " speakup " ) ;
2010-12-19 22:50:24 +00:00
2010-12-16 13:26:58 -06:00
if ( IS_ERR ( speakup_task ) ) {
2010-12-19 22:50:24 +00:00
err = PTR_ERR ( speakup_task ) ;
goto error_task ;
2010-12-16 13:26:58 -06:00
}
2010-12-19 22:50:24 +00:00
set_user_nice ( speakup_task , 10 ) ;
2010-12-16 13:26:58 -06:00
wake_up_process ( speakup_task ) ;
2010-12-19 22:50:24 +00:00
pr_info ( " speakup %s: initialized \n " , SPEAKUP_VERSION ) ;
pr_info ( " synth name on entry is: %s \n " , synth_name ) ;
2010-12-16 13:26:58 -06:00
goto out ;
2010-12-19 22:50:24 +00:00
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 ] ) ;
2010-12-16 13:26:58 -06:00
speakup_remove_virtual_keyboard ( ) ;
2010-12-19 22:50:24 +00:00
error_virtkeyboard :
for ( i = 0 ; i < MAXVARS ; i + + )
speakup_unregister_var ( i ) ;
for ( i = 0 ; i < 256 ; i + + ) {
2013-01-02 02:37:40 +01:00
if ( spk_characters [ i ] ! = spk_default_chars [ i ] )
kfree ( spk_characters [ i ] ) ;
2010-12-19 22:50:24 +00:00
}
2013-01-02 02:37:40 +01:00
spk_free_user_msgs ( ) ;
2010-12-19 22:50:24 +00:00
2010-12-16 13:26:58 -06:00
out :
return err ;
2010-10-07 13:20:02 -05:00
}
2022-11-15 15:05:29 +05:00
module_param_named ( bell_pos , spk_vars [ BELL_POS_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( spell_delay , spk_vars [ SPELL_DELAY_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( attrib_bleep , spk_vars [ ATTRIB_BLEEP_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( bleeps , spk_vars [ BLEEPS_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( bleep_time , spk_vars [ BLEEP_TIME_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( punc_level , spk_vars [ PUNC_LEVEL_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( reading_punc , spk_vars [ READING_PUNC_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( cursor_time , spk_vars [ CURSOR_TIME_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( say_control , spk_vars [ SAY_CONTROL_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( say_word_ctl , spk_vars [ SAY_WORD_CTL_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( no_interrupt , spk_vars [ NO_INTERRUPT_ID ] . u . n . default_val , int , 0444 ) ;
module_param_named ( key_echo , spk_vars [ KEY_ECHO_ID ] . u . n . default_val , int , 0444 ) ;
2022-11-15 15:05:30 +05:00
module_param_named ( cur_phonetic , spk_vars [ CUR_PHONETIC_ID ] . u . n . default_val , int , 0444 ) ;
2022-11-15 15:05:29 +05:00
MODULE_PARM_DESC ( bell_pos , " This works much like a typewriter bell. If for example 72 is echoed to bell_pos, it will beep the PC speaker when typing on a line past character 72. " ) ;
MODULE_PARM_DESC ( spell_delay , " This controls how fast a word is spelled when speakup's spell word review command is pressed. " ) ;
MODULE_PARM_DESC ( attrib_bleep , " Beeps the PC speaker when there is an attribute change such as background color when using speakup review commands. One = on, zero = off. " ) ;
MODULE_PARM_DESC ( bleeps , " This controls whether one hears beeps through the PC speaker when using speakup review commands. " ) ;
MODULE_PARM_DESC ( bleep_time , " This controls the duration of the PC speaker beeps speakup produces. " ) ;
MODULE_PARM_DESC ( punc_level , " Controls the level of punctuation spoken as the screen is displayed, not reviewed. " ) ;
MODULE_PARM_DESC ( reading_punc , " It controls the level of punctuation when reviewing the screen with speakup's screen review commands. " ) ;
MODULE_PARM_DESC ( cursor_time , " This controls cursor delay when using arrow keys. " ) ;
MODULE_PARM_DESC ( say_control , " This controls if speakup speaks shift, alt and control when those keys are pressed or not. " ) ;
2022-12-07 09:52:02 +00:00
MODULE_PARM_DESC ( say_word_ctl , " Sets the say_word_ctl on load. " ) ;
2022-11-15 15:05:29 +05:00
MODULE_PARM_DESC ( no_interrupt , " Controls if typing interrupts output from speakup. " ) ;
MODULE_PARM_DESC ( key_echo , " Controls if speakup speaks keys when they are typed. One = on zero = off or don't echo keys. " ) ;
2022-11-15 15:05:30 +05:00
MODULE_PARM_DESC ( cur_phonetic , " Controls if speakup speaks letters phonetically during navigation. One = on zero = off or don't speak phonetically. " ) ;
2022-11-15 15:05:29 +05:00
2010-10-07 13:20:02 -05:00
module_init ( speakup_init ) ;
module_exit ( speakup_exit ) ;