2018-01-11 11:08:40 +01:00
// SPDX-License-Identifier: GPL-2.0+
2010-10-07 13:20:02 -05:00
/* speakup_keyhelp.c
2010-10-12 11:39:29 -05:00
* help module for speakup
*
* written by David Borowski .
*
* Copyright ( C ) 2003 David Borowski .
*/
2010-10-07 13:20:02 -05:00
# include <linux/keyboard.h>
# include "spk_priv.h"
# include "speakup.h"
# define MAXFUNCS 130
# define MAXKEYS 256
static const int num_key_names = MSG_KEYNAMES_END - MSG_KEYNAMES_START + 1 ;
static u_short key_offsets [ MAXFUNCS ] , key_data [ MAXKEYS ] ;
static u_short masks [ ] = { 32 , 16 , 8 , 4 , 2 , 1 } ;
2010-10-12 11:39:29 -05:00
static short letter_offsets [ 26 ] = {
2010-10-08 06:14:45 -04:00
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 } ;
2010-10-07 13:20:02 -05:00
static u_char funcvals [ ] = {
ATTRIB_BLEEP_DEC , ATTRIB_BLEEP_INC , BLEEPS_DEC , BLEEPS_INC ,
SAY_FIRST_CHAR , SAY_LAST_CHAR , SAY_CHAR , SAY_CHAR_NUM ,
SAY_NEXT_CHAR , SAY_PHONETIC_CHAR , SAY_PREV_CHAR , SPEAKUP_PARKED ,
SPEAKUP_CUT , EDIT_DELIM , EDIT_EXNUM , EDIT_MOST ,
EDIT_REPEAT , EDIT_SOME , SPEAKUP_GOTO , BOTTOM_EDGE ,
LEFT_EDGE , RIGHT_EDGE , TOP_EDGE , SPEAKUP_HELP ,
SAY_LINE , SAY_NEXT_LINE , SAY_PREV_LINE , SAY_LINE_INDENT ,
SPEAKUP_PASTE , PITCH_DEC , PITCH_INC , PUNCT_DEC ,
PUNCT_INC , PUNC_LEVEL_DEC , PUNC_LEVEL_INC , SPEAKUP_QUIET ,
RATE_DEC , RATE_INC , READING_PUNC_DEC , READING_PUNC_INC ,
SAY_ATTRIBUTES , SAY_FROM_LEFT , SAY_FROM_TOP , SAY_POSITION ,
SAY_SCREEN , SAY_TO_BOTTOM , SAY_TO_RIGHT , SPK_KEY ,
SPK_LOCK , SPEAKUP_OFF , SPEECH_KILL , SPELL_DELAY_DEC ,
SPELL_DELAY_INC , SPELL_WORD , SPELL_PHONETIC , TONE_DEC ,
TONE_INC , VOICE_DEC , VOICE_INC , VOL_DEC ,
VOL_INC , CLEAR_WIN , SAY_WIN , SET_WIN ,
ENABLE_WIN , SAY_WORD , SAY_NEXT_WORD , SAY_PREV_WORD , 0
} ;
static u_char * state_tbl ;
static int cur_item , nstates ;
static void build_key_data ( void )
{
u_char * kp , counters [ MAXFUNCS ] , ch , ch1 ;
2020-02-23 15:39:54 +00:00
u_short * p_key , key ;
2010-10-07 13:20:02 -05:00
int i , offset = 1 ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
nstates = ( int ) ( state_tbl [ - 1 ] ) ;
memset ( counters , 0 , sizeof ( counters ) ) ;
memset ( key_offsets , 0 , sizeof ( key_offsets ) ) ;
kp = state_tbl + nstates + 1 ;
while ( * kp + + ) {
2011-03-30 22:57:33 -03:00
/* count occurrences of each function */
2010-10-07 13:20:02 -05:00
for ( i = 0 ; i < nstates ; i + + , kp + + ) {
if ( ! * kp )
continue ;
2015-11-19 14:40:59 +01:00
if ( ( state_tbl [ i ] & 16 ) ! = 0 & & * kp = = SPK_KEY )
2010-10-07 13:20:02 -05:00
continue ;
counters [ * kp ] + + ;
}
}
for ( i = 0 ; i < MAXFUNCS ; i + + ) {
if ( counters [ i ] = = 0 )
continue ;
key_offsets [ i ] = offset ;
2015-11-19 14:40:59 +01:00
offset + = ( counters [ i ] + 1 ) ;
2010-10-07 13:20:02 -05:00
if ( offset > = MAXKEYS )
break ;
}
/* leave counters set so high keycodes come first.
2010-10-12 11:39:29 -05:00
* this is done so num pad and other extended keys maps are spoken before
* the alpha with speakup type mapping .
*/
2010-10-07 13:20:02 -05:00
kp = state_tbl + nstates + 1 ;
while ( ( ch = * kp + + ) ) {
for ( i = 0 ; i < nstates ; i + + ) {
ch1 = * kp + + ;
if ( ! ch1 )
continue ;
2015-11-19 14:40:59 +01:00
if ( ( state_tbl [ i ] & 16 ) ! = 0 & & ch1 = = SPK_KEY )
2010-10-07 13:20:02 -05:00
continue ;
key = ( state_tbl [ i ] < < 8 ) + ch ;
counters [ ch1 ] - - ;
offset = key_offsets [ ch1 ] ;
if ( ! offset )
continue ;
p_key = key_data + offset + counters [ ch1 ] ;
* p_key = key ;
}
}
}
static void say_key ( int key )
{
int i , state = key > > 8 ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
key & = 0xff ;
for ( i = 0 ; i < 6 ; i + + ) {
if ( state & masks [ i ] )
2013-01-02 02:37:40 +01:00
synth_printf ( " %s " , spk_msg_get ( MSG_STATES_START + i ) ) ;
2010-10-07 13:20:02 -05:00
}
if ( ( key > 0 ) & & ( key < = num_key_names ) )
2013-01-08 22:39:02 +04:00
synth_printf ( " %s \n " ,
2017-03-01 02:38:12 +05:30
spk_msg_get ( MSG_KEYNAMES_START + ( key - 1 ) ) ) ;
2010-10-07 13:20:02 -05:00
}
static int help_init ( void )
{
char start = SPACE ;
int i ;
int num_funcs = MSG_FUNCNAMES_END - MSG_FUNCNAMES_START + 1 ;
2014-09-09 20:04:33 +02:00
2015-11-19 14:40:59 +01:00
state_tbl = spk_our_keys [ 0 ] + SHIFT_TBL_SIZE + 2 ;
2010-10-07 13:20:02 -05:00
for ( i = 0 ; i < num_funcs ; i + + ) {
2013-01-02 02:37:40 +01:00
char * cur_funcname = spk_msg_get ( MSG_FUNCNAMES_START + i ) ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
if ( start = = * cur_funcname )
continue ;
start = * cur_funcname ;
2015-11-19 14:40:59 +01:00
letter_offsets [ ( start & 31 ) - 1 ] = i ;
2010-10-07 13:20:02 -05:00
}
return 0 ;
}
2013-01-02 02:37:40 +01:00
int spk_handle_help ( struct vc_data * vc , u_char type , u_char ch , u_short key )
2010-10-07 13:20:02 -05:00
{
int i , n ;
char * name ;
u_char func , * kp ;
u_short * p_keys , val ;
2014-09-09 20:04:34 +02:00
2010-10-07 13:20:02 -05:00
if ( letter_offsets [ 0 ] = = - 1 )
help_init ( ) ;
if ( type = = KT_LATIN ) {
if ( ch = = SPACE ) {
2013-01-02 02:37:40 +01:00
spk_special_handler = NULL ;
synth_printf ( " %s \n " , spk_msg_get ( MSG_LEAVING_HELP ) ) ;
2010-10-07 13:20:02 -05:00
return 1 ;
}
ch | = 32 ; /* lower case */
if ( ch < ' a ' | | ch > ' z ' )
return - 1 ;
2015-11-19 14:40:59 +01:00
if ( letter_offsets [ ch - ' a ' ] = = - 1 ) {
2013-01-02 02:37:40 +01:00
synth_printf ( spk_msg_get ( MSG_NO_COMMAND ) , ch ) ;
2010-10-07 13:20:02 -05:00
synth_printf ( " \n " ) ;
return 1 ;
}
2015-11-19 14:40:59 +01:00
cur_item = letter_offsets [ ch - ' a ' ] ;
2010-10-07 13:20:02 -05:00
} else if ( type = = KT_CUR ) {
2017-03-01 02:38:13 +05:30
if ( ch = = 0 & &
( MSG_FUNCNAMES_START + cur_item + 1 ) < = MSG_FUNCNAMES_END )
2010-10-07 13:20:02 -05:00
cur_item + + ;
else if ( ch = = 3 & & cur_item > 0 )
cur_item - - ;
else
return - 1 ;
2017-03-01 02:38:13 +05:30
} else if ( type = = KT_SPKUP & & ch = = SPEAKUP_HELP & &
! spk_special_handler ) {
2013-01-02 02:37:40 +01:00
spk_special_handler = spk_handle_help ;
synth_printf ( " %s \n " , spk_msg_get ( MSG_HELP_INFO ) ) ;
2010-10-07 13:20:02 -05:00
build_key_data ( ) ; /* rebuild each time in case new mapping */
return 1 ;
} else {
name = NULL ;
if ( ( type ! = KT_SPKUP ) & & ( key > 0 ) & & ( key < = num_key_names ) ) {
2010-10-12 11:39:29 -05:00
synth_printf ( " %s \n " ,
2017-03-01 02:38:12 +05:30
spk_msg_get ( MSG_KEYNAMES_START + key - 1 ) ) ;
2010-10-07 13:20:02 -05:00
return 1 ;
}
for ( i = 0 ; funcvals [ i ] ! = 0 & & ! name ; i + + ) {
if ( ch = = funcvals [ i ] )
2013-01-02 02:37:40 +01:00
name = spk_msg_get ( MSG_FUNCNAMES_START + i ) ;
2010-10-07 13:20:02 -05:00
}
if ( ! name )
return - 1 ;
2015-11-19 14:40:59 +01:00
kp = spk_our_keys [ key ] + 1 ;
2010-10-07 13:20:02 -05:00
for ( i = 0 ; i < nstates ; i + + ) {
if ( ch = = kp [ i ] )
break ;
}
key + = ( state_tbl [ i ] < < 8 ) ;
say_key ( key ) ;
2013-01-02 02:37:40 +01:00
synth_printf ( spk_msg_get ( MSG_KEYDESC ) , name ) ;
2010-10-07 13:20:02 -05:00
synth_printf ( " \n " ) ;
return 1 ;
}
2013-01-02 02:37:40 +01:00
name = spk_msg_get ( MSG_FUNCNAMES_START + cur_item ) ;
2010-10-07 13:20:02 -05:00
func = funcvals [ cur_item ] ;
synth_printf ( " %s " , name ) ;
if ( key_offsets [ func ] = = 0 ) {
2013-01-02 02:37:40 +01:00
synth_printf ( " %s \n " , spk_msg_get ( MSG_IS_UNASSIGNED ) ) ;
2010-10-07 13:20:02 -05:00
return 1 ;
}
p_keys = key_data + key_offsets [ func ] ;
for ( n = 0 ; p_keys [ n ] ; n + + ) {
val = p_keys [ n ] ;
if ( n > 0 )
2013-01-02 02:37:40 +01:00
synth_printf ( " %s " , spk_msg_get ( MSG_DISJUNCTION ) ) ;
2010-10-07 13:20:02 -05:00
say_key ( val ) ;
}
return 1 ;
}