18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* speakup_keyhelp.c 38c2ecf20Sopenharmony_ci * help module for speakup 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci *written by David Borowski. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2003 David Borowski. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/keyboard.h> 118c2ecf20Sopenharmony_ci#include "spk_priv.h" 128c2ecf20Sopenharmony_ci#include "speakup.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define MAXFUNCS 130 158c2ecf20Sopenharmony_ci#define MAXKEYS 256 168c2ecf20Sopenharmony_cistatic const int num_key_names = MSG_KEYNAMES_END - MSG_KEYNAMES_START + 1; 178c2ecf20Sopenharmony_cistatic u_short key_offsets[MAXFUNCS], key_data[MAXKEYS]; 188c2ecf20Sopenharmony_cistatic u_short masks[] = { 32, 16, 8, 4, 2, 1 }; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic short letter_offsets[26] = { 218c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 228c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 238c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 248c2ecf20Sopenharmony_ci -1, -1 }; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic u_char funcvals[] = { 278c2ecf20Sopenharmony_ci ATTRIB_BLEEP_DEC, ATTRIB_BLEEP_INC, BLEEPS_DEC, BLEEPS_INC, 288c2ecf20Sopenharmony_ci SAY_FIRST_CHAR, SAY_LAST_CHAR, SAY_CHAR, SAY_CHAR_NUM, 298c2ecf20Sopenharmony_ci SAY_NEXT_CHAR, SAY_PHONETIC_CHAR, SAY_PREV_CHAR, SPEAKUP_PARKED, 308c2ecf20Sopenharmony_ci SPEAKUP_CUT, EDIT_DELIM, EDIT_EXNUM, EDIT_MOST, 318c2ecf20Sopenharmony_ci EDIT_REPEAT, EDIT_SOME, SPEAKUP_GOTO, BOTTOM_EDGE, 328c2ecf20Sopenharmony_ci LEFT_EDGE, RIGHT_EDGE, TOP_EDGE, SPEAKUP_HELP, 338c2ecf20Sopenharmony_ci SAY_LINE, SAY_NEXT_LINE, SAY_PREV_LINE, SAY_LINE_INDENT, 348c2ecf20Sopenharmony_ci SPEAKUP_PASTE, PITCH_DEC, PITCH_INC, PUNCT_DEC, 358c2ecf20Sopenharmony_ci PUNCT_INC, PUNC_LEVEL_DEC, PUNC_LEVEL_INC, SPEAKUP_QUIET, 368c2ecf20Sopenharmony_ci RATE_DEC, RATE_INC, READING_PUNC_DEC, READING_PUNC_INC, 378c2ecf20Sopenharmony_ci SAY_ATTRIBUTES, SAY_FROM_LEFT, SAY_FROM_TOP, SAY_POSITION, 388c2ecf20Sopenharmony_ci SAY_SCREEN, SAY_TO_BOTTOM, SAY_TO_RIGHT, SPK_KEY, 398c2ecf20Sopenharmony_ci SPK_LOCK, SPEAKUP_OFF, SPEECH_KILL, SPELL_DELAY_DEC, 408c2ecf20Sopenharmony_ci SPELL_DELAY_INC, SPELL_WORD, SPELL_PHONETIC, TONE_DEC, 418c2ecf20Sopenharmony_ci TONE_INC, VOICE_DEC, VOICE_INC, VOL_DEC, 428c2ecf20Sopenharmony_ci VOL_INC, CLEAR_WIN, SAY_WIN, SET_WIN, 438c2ecf20Sopenharmony_ci ENABLE_WIN, SAY_WORD, SAY_NEXT_WORD, SAY_PREV_WORD, 0 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic u_char *state_tbl; 478c2ecf20Sopenharmony_cistatic int cur_item, nstates; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic void build_key_data(void) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci u_char *kp, counters[MAXFUNCS], ch, ch1; 528c2ecf20Sopenharmony_ci u_short *p_key, key; 538c2ecf20Sopenharmony_ci int i, offset = 1; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci nstates = (int)(state_tbl[-1]); 568c2ecf20Sopenharmony_ci memset(counters, 0, sizeof(counters)); 578c2ecf20Sopenharmony_ci memset(key_offsets, 0, sizeof(key_offsets)); 588c2ecf20Sopenharmony_ci kp = state_tbl + nstates + 1; 598c2ecf20Sopenharmony_ci while (*kp++) { 608c2ecf20Sopenharmony_ci /* count occurrences of each function */ 618c2ecf20Sopenharmony_ci for (i = 0; i < nstates; i++, kp++) { 628c2ecf20Sopenharmony_ci if (!*kp) 638c2ecf20Sopenharmony_ci continue; 648c2ecf20Sopenharmony_ci if ((state_tbl[i] & 16) != 0 && *kp == SPK_KEY) 658c2ecf20Sopenharmony_ci continue; 668c2ecf20Sopenharmony_ci counters[*kp]++; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci for (i = 0; i < MAXFUNCS; i++) { 708c2ecf20Sopenharmony_ci if (counters[i] == 0) 718c2ecf20Sopenharmony_ci continue; 728c2ecf20Sopenharmony_ci key_offsets[i] = offset; 738c2ecf20Sopenharmony_ci offset += (counters[i] + 1); 748c2ecf20Sopenharmony_ci if (offset >= MAXKEYS) 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci/* leave counters set so high keycodes come first. 788c2ecf20Sopenharmony_ci * this is done so num pad and other extended keys maps are spoken before 798c2ecf20Sopenharmony_ci * the alpha with speakup type mapping. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci kp = state_tbl + nstates + 1; 828c2ecf20Sopenharmony_ci while ((ch = *kp++)) { 838c2ecf20Sopenharmony_ci for (i = 0; i < nstates; i++) { 848c2ecf20Sopenharmony_ci ch1 = *kp++; 858c2ecf20Sopenharmony_ci if (!ch1) 868c2ecf20Sopenharmony_ci continue; 878c2ecf20Sopenharmony_ci if ((state_tbl[i] & 16) != 0 && ch1 == SPK_KEY) 888c2ecf20Sopenharmony_ci continue; 898c2ecf20Sopenharmony_ci key = (state_tbl[i] << 8) + ch; 908c2ecf20Sopenharmony_ci counters[ch1]--; 918c2ecf20Sopenharmony_ci offset = key_offsets[ch1]; 928c2ecf20Sopenharmony_ci if (!offset) 938c2ecf20Sopenharmony_ci continue; 948c2ecf20Sopenharmony_ci p_key = key_data + offset + counters[ch1]; 958c2ecf20Sopenharmony_ci *p_key = key; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic void say_key(int key) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci int i, state = key >> 8; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci key &= 0xff; 1058c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) { 1068c2ecf20Sopenharmony_ci if (state & masks[i]) 1078c2ecf20Sopenharmony_ci synth_printf(" %s", spk_msg_get(MSG_STATES_START + i)); 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci if ((key > 0) && (key <= num_key_names)) 1108c2ecf20Sopenharmony_ci synth_printf(" %s\n", 1118c2ecf20Sopenharmony_ci spk_msg_get(MSG_KEYNAMES_START + (key - 1))); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic int help_init(void) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci char start = SPACE; 1178c2ecf20Sopenharmony_ci int i; 1188c2ecf20Sopenharmony_ci int num_funcs = MSG_FUNCNAMES_END - MSG_FUNCNAMES_START + 1; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci state_tbl = spk_our_keys[0] + SHIFT_TBL_SIZE + 2; 1218c2ecf20Sopenharmony_ci for (i = 0; i < num_funcs; i++) { 1228c2ecf20Sopenharmony_ci char *cur_funcname = spk_msg_get(MSG_FUNCNAMES_START + i); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (start == *cur_funcname) 1258c2ecf20Sopenharmony_ci continue; 1268c2ecf20Sopenharmony_ci start = *cur_funcname; 1278c2ecf20Sopenharmony_ci letter_offsets[(start & 31) - 1] = i; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciint spk_handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci int i, n; 1358c2ecf20Sopenharmony_ci char *name; 1368c2ecf20Sopenharmony_ci u_char func, *kp; 1378c2ecf20Sopenharmony_ci u_short *p_keys, val; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (letter_offsets[0] == -1) 1408c2ecf20Sopenharmony_ci help_init(); 1418c2ecf20Sopenharmony_ci if (type == KT_LATIN) { 1428c2ecf20Sopenharmony_ci if (ch == SPACE) { 1438c2ecf20Sopenharmony_ci spk_special_handler = NULL; 1448c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_LEAVING_HELP)); 1458c2ecf20Sopenharmony_ci return 1; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci ch |= 32; /* lower case */ 1488c2ecf20Sopenharmony_ci if (ch < 'a' || ch > 'z') 1498c2ecf20Sopenharmony_ci return -1; 1508c2ecf20Sopenharmony_ci if (letter_offsets[ch - 'a'] == -1) { 1518c2ecf20Sopenharmony_ci synth_printf(spk_msg_get(MSG_NO_COMMAND), ch); 1528c2ecf20Sopenharmony_ci synth_printf("\n"); 1538c2ecf20Sopenharmony_ci return 1; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci cur_item = letter_offsets[ch - 'a']; 1568c2ecf20Sopenharmony_ci } else if (type == KT_CUR) { 1578c2ecf20Sopenharmony_ci if (ch == 0 && 1588c2ecf20Sopenharmony_ci (MSG_FUNCNAMES_START + cur_item + 1) <= MSG_FUNCNAMES_END) 1598c2ecf20Sopenharmony_ci cur_item++; 1608c2ecf20Sopenharmony_ci else if (ch == 3 && cur_item > 0) 1618c2ecf20Sopenharmony_ci cur_item--; 1628c2ecf20Sopenharmony_ci else 1638c2ecf20Sopenharmony_ci return -1; 1648c2ecf20Sopenharmony_ci } else if (type == KT_SPKUP && ch == SPEAKUP_HELP && 1658c2ecf20Sopenharmony_ci !spk_special_handler) { 1668c2ecf20Sopenharmony_ci spk_special_handler = spk_handle_help; 1678c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_HELP_INFO)); 1688c2ecf20Sopenharmony_ci build_key_data(); /* rebuild each time in case new mapping */ 1698c2ecf20Sopenharmony_ci return 1; 1708c2ecf20Sopenharmony_ci } else { 1718c2ecf20Sopenharmony_ci name = NULL; 1728c2ecf20Sopenharmony_ci if ((type != KT_SPKUP) && (key > 0) && (key <= num_key_names)) { 1738c2ecf20Sopenharmony_ci synth_printf("%s\n", 1748c2ecf20Sopenharmony_ci spk_msg_get(MSG_KEYNAMES_START + key - 1)); 1758c2ecf20Sopenharmony_ci return 1; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci for (i = 0; funcvals[i] != 0 && !name; i++) { 1788c2ecf20Sopenharmony_ci if (ch == funcvals[i]) 1798c2ecf20Sopenharmony_ci name = spk_msg_get(MSG_FUNCNAMES_START + i); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci if (!name) 1828c2ecf20Sopenharmony_ci return -1; 1838c2ecf20Sopenharmony_ci kp = spk_our_keys[key] + 1; 1848c2ecf20Sopenharmony_ci for (i = 0; i < nstates; i++) { 1858c2ecf20Sopenharmony_ci if (ch == kp[i]) 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci key += (state_tbl[i] << 8); 1898c2ecf20Sopenharmony_ci say_key(key); 1908c2ecf20Sopenharmony_ci synth_printf(spk_msg_get(MSG_KEYDESC), name); 1918c2ecf20Sopenharmony_ci synth_printf("\n"); 1928c2ecf20Sopenharmony_ci return 1; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci name = spk_msg_get(MSG_FUNCNAMES_START + cur_item); 1958c2ecf20Sopenharmony_ci func = funcvals[cur_item]; 1968c2ecf20Sopenharmony_ci synth_printf("%s", name); 1978c2ecf20Sopenharmony_ci if (key_offsets[func] == 0) { 1988c2ecf20Sopenharmony_ci synth_printf(" %s\n", spk_msg_get(MSG_IS_UNASSIGNED)); 1998c2ecf20Sopenharmony_ci return 1; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci p_keys = key_data + key_offsets[func]; 2028c2ecf20Sopenharmony_ci for (n = 0; p_keys[n]; n++) { 2038c2ecf20Sopenharmony_ci val = p_keys[n]; 2048c2ecf20Sopenharmony_ci if (n > 0) 2058c2ecf20Sopenharmony_ci synth_printf("%s ", spk_msg_get(MSG_DISJUNCTION)); 2068c2ecf20Sopenharmony_ci say_key(val); 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci return 1; 2098c2ecf20Sopenharmony_ci} 210