162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* speakup_keyhelp.c 362306a36Sopenharmony_ci * help module for speakup 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci *written by David Borowski. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2003 David Borowski. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/keyboard.h> 1162306a36Sopenharmony_ci#include "spk_priv.h" 1262306a36Sopenharmony_ci#include "speakup.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define MAXFUNCS 130 1562306a36Sopenharmony_ci#define MAXKEYS 256 1662306a36Sopenharmony_cistatic const int num_key_names = MSG_KEYNAMES_END - MSG_KEYNAMES_START + 1; 1762306a36Sopenharmony_cistatic u_short key_offsets[MAXFUNCS], key_data[MAXKEYS]; 1862306a36Sopenharmony_cistatic u_short masks[] = { 32, 16, 8, 4, 2, 1 }; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic short letter_offsets[26] = { 2162306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 2262306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 2362306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 2462306a36Sopenharmony_ci -1, -1 }; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic u_char funcvals[] = { 2762306a36Sopenharmony_ci ATTRIB_BLEEP_DEC, ATTRIB_BLEEP_INC, BLEEPS_DEC, BLEEPS_INC, 2862306a36Sopenharmony_ci SAY_FIRST_CHAR, SAY_LAST_CHAR, SAY_CHAR, SAY_CHAR_NUM, 2962306a36Sopenharmony_ci SAY_NEXT_CHAR, SAY_PHONETIC_CHAR, SAY_PREV_CHAR, SPEAKUP_PARKED, 3062306a36Sopenharmony_ci SPEAKUP_CUT, EDIT_DELIM, EDIT_EXNUM, EDIT_MOST, 3162306a36Sopenharmony_ci EDIT_REPEAT, EDIT_SOME, SPEAKUP_GOTO, BOTTOM_EDGE, 3262306a36Sopenharmony_ci LEFT_EDGE, RIGHT_EDGE, TOP_EDGE, SPEAKUP_HELP, 3362306a36Sopenharmony_ci SAY_LINE, SAY_NEXT_LINE, SAY_PREV_LINE, SAY_LINE_INDENT, 3462306a36Sopenharmony_ci SPEAKUP_PASTE, PITCH_DEC, PITCH_INC, PUNCT_DEC, 3562306a36Sopenharmony_ci PUNCT_INC, PUNC_LEVEL_DEC, PUNC_LEVEL_INC, SPEAKUP_QUIET, 3662306a36Sopenharmony_ci RATE_DEC, RATE_INC, READING_PUNC_DEC, READING_PUNC_INC, 3762306a36Sopenharmony_ci SAY_ATTRIBUTES, SAY_FROM_LEFT, SAY_FROM_TOP, SAY_POSITION, 3862306a36Sopenharmony_ci SAY_SCREEN, SAY_TO_BOTTOM, SAY_TO_RIGHT, SPK_KEY, 3962306a36Sopenharmony_ci SPK_LOCK, SPEAKUP_OFF, SPEECH_KILL, SPELL_DELAY_DEC, 4062306a36Sopenharmony_ci SPELL_DELAY_INC, SPELL_WORD, SPELL_PHONETIC, TONE_DEC, 4162306a36Sopenharmony_ci TONE_INC, VOICE_DEC, VOICE_INC, VOL_DEC, 4262306a36Sopenharmony_ci VOL_INC, CLEAR_WIN, SAY_WIN, SET_WIN, 4362306a36Sopenharmony_ci ENABLE_WIN, SAY_WORD, SAY_NEXT_WORD, SAY_PREV_WORD, 0 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic u_char *state_tbl; 4762306a36Sopenharmony_cistatic int cur_item, nstates; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic void build_key_data(void) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci u_char *kp, counters[MAXFUNCS], ch, ch1; 5262306a36Sopenharmony_ci u_short *p_key, key; 5362306a36Sopenharmony_ci int i, offset = 1; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci nstates = (int)(state_tbl[-1]); 5662306a36Sopenharmony_ci memset(counters, 0, sizeof(counters)); 5762306a36Sopenharmony_ci memset(key_offsets, 0, sizeof(key_offsets)); 5862306a36Sopenharmony_ci kp = state_tbl + nstates + 1; 5962306a36Sopenharmony_ci while (*kp++) { 6062306a36Sopenharmony_ci /* count occurrences of each function */ 6162306a36Sopenharmony_ci for (i = 0; i < nstates; i++, kp++) { 6262306a36Sopenharmony_ci if (!*kp) 6362306a36Sopenharmony_ci continue; 6462306a36Sopenharmony_ci if ((state_tbl[i] & 16) != 0 && *kp == SPK_KEY) 6562306a36Sopenharmony_ci continue; 6662306a36Sopenharmony_ci counters[*kp]++; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci for (i = 0; i < MAXFUNCS; i++) { 7062306a36Sopenharmony_ci if (counters[i] == 0) 7162306a36Sopenharmony_ci continue; 7262306a36Sopenharmony_ci key_offsets[i] = offset; 7362306a36Sopenharmony_ci offset += (counters[i] + 1); 7462306a36Sopenharmony_ci if (offset >= MAXKEYS) 7562306a36Sopenharmony_ci break; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci/* leave counters set so high keycodes come first. 7862306a36Sopenharmony_ci * this is done so num pad and other extended keys maps are spoken before 7962306a36Sopenharmony_ci * the alpha with speakup type mapping. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci kp = state_tbl + nstates + 1; 8262306a36Sopenharmony_ci while ((ch = *kp++)) { 8362306a36Sopenharmony_ci for (i = 0; i < nstates; i++) { 8462306a36Sopenharmony_ci ch1 = *kp++; 8562306a36Sopenharmony_ci if (!ch1) 8662306a36Sopenharmony_ci continue; 8762306a36Sopenharmony_ci if ((state_tbl[i] & 16) != 0 && ch1 == SPK_KEY) 8862306a36Sopenharmony_ci continue; 8962306a36Sopenharmony_ci key = (state_tbl[i] << 8) + ch; 9062306a36Sopenharmony_ci counters[ch1]--; 9162306a36Sopenharmony_ci offset = key_offsets[ch1]; 9262306a36Sopenharmony_ci if (!offset) 9362306a36Sopenharmony_ci continue; 9462306a36Sopenharmony_ci p_key = key_data + offset + counters[ch1]; 9562306a36Sopenharmony_ci *p_key = key; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic void say_key(int key) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci int i, state = key >> 8; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci key &= 0xff; 10562306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 10662306a36Sopenharmony_ci if (state & masks[i]) 10762306a36Sopenharmony_ci synth_printf(" %s", spk_msg_get(MSG_STATES_START + i)); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci if ((key > 0) && (key <= num_key_names)) 11062306a36Sopenharmony_ci synth_printf(" %s\n", 11162306a36Sopenharmony_ci spk_msg_get(MSG_KEYNAMES_START + (key - 1))); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int help_init(void) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci char start = SPACE; 11762306a36Sopenharmony_ci int i; 11862306a36Sopenharmony_ci int num_funcs = MSG_FUNCNAMES_END - MSG_FUNCNAMES_START + 1; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci state_tbl = spk_our_keys[0] + SHIFT_TBL_SIZE + 2; 12162306a36Sopenharmony_ci for (i = 0; i < num_funcs; i++) { 12262306a36Sopenharmony_ci char *cur_funcname = spk_msg_get(MSG_FUNCNAMES_START + i); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (start == *cur_funcname) 12562306a36Sopenharmony_ci continue; 12662306a36Sopenharmony_ci start = *cur_funcname; 12762306a36Sopenharmony_ci letter_offsets[(start & 31) - 1] = i; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci return 0; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ciint spk_handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci int i, n; 13562306a36Sopenharmony_ci char *name; 13662306a36Sopenharmony_ci u_char func, *kp; 13762306a36Sopenharmony_ci u_short *p_keys, val; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (letter_offsets[0] == -1) 14062306a36Sopenharmony_ci help_init(); 14162306a36Sopenharmony_ci if (type == KT_LATIN) { 14262306a36Sopenharmony_ci if (ch == SPACE) { 14362306a36Sopenharmony_ci spk_special_handler = NULL; 14462306a36Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_LEAVING_HELP)); 14562306a36Sopenharmony_ci return 1; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci ch |= 32; /* lower case */ 14862306a36Sopenharmony_ci if (ch < 'a' || ch > 'z') 14962306a36Sopenharmony_ci return -1; 15062306a36Sopenharmony_ci if (letter_offsets[ch - 'a'] == -1) { 15162306a36Sopenharmony_ci synth_printf(spk_msg_get(MSG_NO_COMMAND), ch); 15262306a36Sopenharmony_ci synth_printf("\n"); 15362306a36Sopenharmony_ci return 1; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci cur_item = letter_offsets[ch - 'a']; 15662306a36Sopenharmony_ci } else if (type == KT_CUR) { 15762306a36Sopenharmony_ci if (ch == 0 && 15862306a36Sopenharmony_ci (MSG_FUNCNAMES_START + cur_item + 1) <= MSG_FUNCNAMES_END) 15962306a36Sopenharmony_ci cur_item++; 16062306a36Sopenharmony_ci else if (ch == 3 && cur_item > 0) 16162306a36Sopenharmony_ci cur_item--; 16262306a36Sopenharmony_ci else 16362306a36Sopenharmony_ci return -1; 16462306a36Sopenharmony_ci } else if (type == KT_SPKUP && ch == SPEAKUP_HELP && 16562306a36Sopenharmony_ci !spk_special_handler) { 16662306a36Sopenharmony_ci spk_special_handler = spk_handle_help; 16762306a36Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_HELP_INFO)); 16862306a36Sopenharmony_ci build_key_data(); /* rebuild each time in case new mapping */ 16962306a36Sopenharmony_ci return 1; 17062306a36Sopenharmony_ci } else { 17162306a36Sopenharmony_ci name = NULL; 17262306a36Sopenharmony_ci if ((type != KT_SPKUP) && (key > 0) && (key <= num_key_names)) { 17362306a36Sopenharmony_ci synth_printf("%s\n", 17462306a36Sopenharmony_ci spk_msg_get(MSG_KEYNAMES_START + key - 1)); 17562306a36Sopenharmony_ci return 1; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci for (i = 0; funcvals[i] != 0 && !name; i++) { 17862306a36Sopenharmony_ci if (ch == funcvals[i]) 17962306a36Sopenharmony_ci name = spk_msg_get(MSG_FUNCNAMES_START + i); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci if (!name) 18262306a36Sopenharmony_ci return -1; 18362306a36Sopenharmony_ci kp = spk_our_keys[key] + 1; 18462306a36Sopenharmony_ci for (i = 0; i < nstates; i++) { 18562306a36Sopenharmony_ci if (ch == kp[i]) 18662306a36Sopenharmony_ci break; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci key += (state_tbl[i] << 8); 18962306a36Sopenharmony_ci say_key(key); 19062306a36Sopenharmony_ci synth_printf(spk_msg_get(MSG_KEYDESC), name); 19162306a36Sopenharmony_ci synth_printf("\n"); 19262306a36Sopenharmony_ci return 1; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci name = spk_msg_get(MSG_FUNCNAMES_START + cur_item); 19562306a36Sopenharmony_ci func = funcvals[cur_item]; 19662306a36Sopenharmony_ci synth_printf("%s", name); 19762306a36Sopenharmony_ci if (key_offsets[func] == 0) { 19862306a36Sopenharmony_ci synth_printf(" %s\n", spk_msg_get(MSG_IS_UNASSIGNED)); 19962306a36Sopenharmony_ci return 1; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci p_keys = key_data + key_offsets[func]; 20262306a36Sopenharmony_ci for (n = 0; p_keys[n]; n++) { 20362306a36Sopenharmony_ci val = p_keys[n]; 20462306a36Sopenharmony_ci if (n > 0) 20562306a36Sopenharmony_ci synth_printf("%s ", spk_msg_get(MSG_DISJUNCTION)); 20662306a36Sopenharmony_ci say_key(val); 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci return 1; 20962306a36Sopenharmony_ci} 210