After much study and searching and playing around, writing and testing code, and learning just how much difference there is between terminal emulators (and I've hardly scratched the surface), I am attaching two files for your testing pleasure. ;-)
The idea is to enable Ncurses keypad mode and utilize the constants that keyname() recognizes as much as possible. The new-onechar.c file is essentially a reworked copy of ui_utils.c that can be compiled with the following command: gcc -o new-onechar -lncurses new-onechar.c When the program runs it will print the decimal ordinal of the pressed key and its name as returned by keyname(). Use Ctl-D exit. In the main() function ncurses is initialized as closely as possible to Tlf to avoid such differences. Of note is the use of the set_escdelay() function to lower the time getch() will wait from the default of 1000 mS to 25 mS. On my machines this is fast enough to process Alt-keys and other keys that have codes beginning with a value of 27 (^[ or Escape). The downside is that someone that must use Escape in place of Alt will not be able to. The small value was chosen to call stoptx() as soon as possible while allowing sufficient time to receive multi value escaped keys. A look at the new onechar() function show several test sections. I found this necessary to assign various Alt-key combinations into the constants that keyname() will return as M-key--M-a, M-b, etc. Also some keys are terminal specific. Thus far I have tested this on Xfce Terminal, Gnome Terminal, Xterm, and the Linux console as found in Debian 8. Other peculiarities likely lurk out there. I was surprised just how much variation there is just between the ones I tested. To determine the sent codes I used 'showkey -a' in each terminal. One oddity I found is that on the Linux console on my ThinkPad T410 laptop is that Shift-F9 through Shift-F12 produced no keystrokes. At this time all keys among the terminals are processed into a definition as found in the other attached file, names.txt. Implementing this will require a fair amount of care and I have not yet begun the process of doing so. For the most part, the work will consist of replacing one numeric constant with another in various places. Sometimes a named constant like KEY_HOME or KEY_BACKSPACE may be substituted. Before that I would like to hear back from others who will test this on various terminals and report back any unrecognized keys and their key codes as shown by 'showkey -a'. Have fun! 73, Nate -- "The optimist proclaims that we live in the best of all possible worlds. The pessimist fears this is true." Ham radio, Linux, bikes, and more: http://www.n0nb.us
Ordinal: 0 Name: ^@ Ordinal: 1 Name: ^A Ordinal: 2 Name: ^B Ordinal: 3 Name: ^C Ordinal: 4 Name: ^D Ordinal: 5 Name: ^E Ordinal: 6 Name: ^F Ordinal: 7 Name: ^G Ordinal: 8 Name: ^H Ordinal: 9 Name: ^I Ordinal: 10 Name: ^J Ordinal: 11 Name: ^K Ordinal: 12 Name: ^L Ordinal: 13 Name: ^M Ordinal: 14 Name: ^N Ordinal: 15 Name: ^O Ordinal: 16 Name: ^P Ordinal: 17 Name: ^Q Ordinal: 18 Name: ^R Ordinal: 19 Name: ^S Ordinal: 20 Name: ^T Ordinal: 21 Name: ^U Ordinal: 22 Name: ^V Ordinal: 23 Name: ^W Ordinal: 24 Name: ^X Ordinal: 25 Name: ^Y Ordinal: 26 Name: ^Z Ordinal: 27 Name: ^[ Ordinal: 28 Name: ^\ Ordinal: 29 Name: ^] Ordinal: 30 Name: ^^ Ordinal: 31 Name: ^_ Ordinal: 32 Name: Ordinal: 33 Name: ! Ordinal: 34 Name: " Ordinal: 35 Name: # Ordinal: 36 Name: $ Ordinal: 37 Name: % Ordinal: 38 Name: & Ordinal: 39 Name: ' Ordinal: 40 Name: ( Ordinal: 41 Name: ) Ordinal: 42 Name: * Ordinal: 43 Name: + Ordinal: 44 Name: , Ordinal: 45 Name: - Ordinal: 46 Name: . Ordinal: 47 Name: / Ordinal: 48 Name: 0 Ordinal: 49 Name: 1 Ordinal: 50 Name: 2 Ordinal: 51 Name: 3 Ordinal: 52 Name: 4 Ordinal: 53 Name: 5 Ordinal: 54 Name: 6 Ordinal: 55 Name: 7 Ordinal: 56 Name: 8 Ordinal: 57 Name: 9 Ordinal: 58 Name: : Ordinal: 59 Name: ; Ordinal: 60 Name: < Ordinal: 61 Name: = Ordinal: 62 Name: > Ordinal: 63 Name: ? Ordinal: 64 Name: @ Ordinal: 65 Name: A Ordinal: 66 Name: B Ordinal: 67 Name: C Ordinal: 68 Name: D Ordinal: 69 Name: E Ordinal: 70 Name: F Ordinal: 71 Name: G Ordinal: 72 Name: H Ordinal: 73 Name: I Ordinal: 74 Name: J Ordinal: 75 Name: K Ordinal: 76 Name: L Ordinal: 77 Name: M Ordinal: 78 Name: N Ordinal: 79 Name: O Ordinal: 80 Name: P Ordinal: 81 Name: Q Ordinal: 82 Name: R Ordinal: 83 Name: S Ordinal: 84 Name: T Ordinal: 85 Name: U Ordinal: 86 Name: V Ordinal: 87 Name: W Ordinal: 88 Name: X Ordinal: 89 Name: Y Ordinal: 90 Name: Z Ordinal: 91 Name: [ Ordinal: 92 Name: \ Ordinal: 93 Name: ] Ordinal: 94 Name: ^ Ordinal: 95 Name: _ Ordinal: 96 Name: ` Ordinal: 97 Name: a Ordinal: 98 Name: b Ordinal: 99 Name: c Ordinal: 100 Name: d Ordinal: 101 Name: e Ordinal: 102 Name: f Ordinal: 103 Name: g Ordinal: 104 Name: h Ordinal: 105 Name: i Ordinal: 106 Name: j Ordinal: 107 Name: k Ordinal: 108 Name: l Ordinal: 109 Name: m Ordinal: 110 Name: n Ordinal: 111 Name: o Ordinal: 112 Name: p Ordinal: 113 Name: q Ordinal: 114 Name: r Ordinal: 115 Name: s Ordinal: 116 Name: t Ordinal: 117 Name: u Ordinal: 118 Name: v Ordinal: 119 Name: w Ordinal: 120 Name: x Ordinal: 121 Name: y Ordinal: 122 Name: z Ordinal: 123 Name: { Ordinal: 124 Name: | Ordinal: 125 Name: } Ordinal: 126 Name: ~ Ordinal: 127 Name: ^? Ordinal: 128 Name: M-^@ Ordinal: 129 Name: M-^A Ordinal: 130 Name: M-^B Ordinal: 131 Name: M-^C Ordinal: 132 Name: M-^D Ordinal: 133 Name: M-^E Ordinal: 134 Name: M-^F Ordinal: 135 Name: M-^G Ordinal: 136 Name: M-^H Ordinal: 137 Name: M-^I Ordinal: 138 Name: M-^J Ordinal: 139 Name: M-^K Ordinal: 140 Name: M-^L Ordinal: 141 Name: M-^M Ordinal: 142 Name: M-^N Ordinal: 143 Name: M-^O Ordinal: 144 Name: M-^P Ordinal: 145 Name: M-^Q Ordinal: 146 Name: M-^R Ordinal: 147 Name: M-^S Ordinal: 148 Name: M-^T Ordinal: 149 Name: M-^U Ordinal: 150 Name: M-^V Ordinal: 151 Name: M-^W Ordinal: 152 Name: M-^X Ordinal: 153 Name: M-^Y Ordinal: 154 Name: M-^Z Ordinal: 155 Name: M-^[ Ordinal: 156 Name: M-^\ Ordinal: 157 Name: M-^] Ordinal: 158 Name: M-^^ Ordinal: 159 Name: M-^_ Ordinal: 160 Name: M- Ordinal: 161 Name: M-! Ordinal: 162 Name: M-" Ordinal: 163 Name: M-# Ordinal: 164 Name: M-$ Ordinal: 165 Name: M-% Ordinal: 166 Name: M-& Ordinal: 167 Name: M-' Ordinal: 168 Name: M-( Ordinal: 169 Name: M-) Ordinal: 170 Name: M-* Ordinal: 171 Name: M-+ Ordinal: 172 Name: M-, Ordinal: 173 Name: M-- Ordinal: 174 Name: M-. Ordinal: 175 Name: M-/ Ordinal: 176 Name: M-0 Ordinal: 177 Name: M-1 Ordinal: 178 Name: M-2 Ordinal: 179 Name: M-3 Ordinal: 180 Name: M-4 Ordinal: 181 Name: M-5 Ordinal: 182 Name: M-6 Ordinal: 183 Name: M-7 Ordinal: 184 Name: M-8 Ordinal: 185 Name: M-9 Ordinal: 186 Name: M-: Ordinal: 187 Name: M-; Ordinal: 188 Name: M-< Ordinal: 189 Name: M-= Ordinal: 190 Name: M-> Ordinal: 191 Name: M-? Ordinal: 192 Name: M-@ Ordinal: 193 Name: M-A Ordinal: 194 Name: M-B Ordinal: 195 Name: M-C Ordinal: 196 Name: M-D Ordinal: 197 Name: M-E Ordinal: 198 Name: M-F Ordinal: 199 Name: M-G Ordinal: 200 Name: M-H Ordinal: 201 Name: M-I Ordinal: 202 Name: M-J Ordinal: 203 Name: M-K Ordinal: 204 Name: M-L Ordinal: 205 Name: M-M Ordinal: 206 Name: M-N Ordinal: 207 Name: M-O Ordinal: 208 Name: M-P Ordinal: 209 Name: M-Q Ordinal: 210 Name: M-R Ordinal: 211 Name: M-S Ordinal: 212 Name: M-T Ordinal: 213 Name: M-U Ordinal: 214 Name: M-V Ordinal: 215 Name: M-W Ordinal: 216 Name: M-X Ordinal: 217 Name: M-Y Ordinal: 218 Name: M-Z Ordinal: 219 Name: M-[ Ordinal: 220 Name: M-\ Ordinal: 221 Name: M-] Ordinal: 222 Name: M-^ Ordinal: 223 Name: M-_ Ordinal: 224 Name: M-` Ordinal: 225 Name: M-a Ordinal: 226 Name: M-b Ordinal: 227 Name: M-c Ordinal: 228 Name: M-d Ordinal: 229 Name: M-e Ordinal: 230 Name: M-f Ordinal: 231 Name: M-g Ordinal: 232 Name: M-h Ordinal: 233 Name: M-i Ordinal: 234 Name: M-j Ordinal: 235 Name: M-k Ordinal: 236 Name: M-l Ordinal: 237 Name: M-m Ordinal: 238 Name: M-n Ordinal: 239 Name: M-o Ordinal: 240 Name: M-p Ordinal: 241 Name: M-q Ordinal: 242 Name: M-r Ordinal: 243 Name: M-s Ordinal: 244 Name: M-t Ordinal: 245 Name: M-u Ordinal: 246 Name: M-v Ordinal: 247 Name: M-w Ordinal: 248 Name: M-x Ordinal: 249 Name: M-y Ordinal: 250 Name: M-z Ordinal: 251 Name: M-{ Ordinal: 252 Name: M-| Ordinal: 253 Name: M-} Ordinal: 254 Name: M-~ Ordinal: 255 Name: M-^? Ordinal: 256 Name: (null) Ordinal: 257 Name: KEY_BREAK Ordinal: 258 Name: KEY_DOWN Ordinal: 259 Name: KEY_UP Ordinal: 260 Name: KEY_LEFT Ordinal: 261 Name: KEY_RIGHT Ordinal: 262 Name: KEY_HOME Ordinal: 263 Name: KEY_BACKSPACE Ordinal: 264 Name: KEY_F(0) Ordinal: 265 Name: KEY_F(1) Ordinal: 266 Name: KEY_F(2) Ordinal: 267 Name: KEY_F(3) Ordinal: 268 Name: KEY_F(4) Ordinal: 269 Name: KEY_F(5) Ordinal: 270 Name: KEY_F(6) Ordinal: 271 Name: KEY_F(7) Ordinal: 272 Name: KEY_F(8) Ordinal: 273 Name: KEY_F(9) Ordinal: 274 Name: KEY_F(10) Ordinal: 275 Name: KEY_F(11) Ordinal: 276 Name: KEY_F(12) Ordinal: 277 Name: KEY_F(13) Ordinal: 278 Name: KEY_F(14) Ordinal: 279 Name: KEY_F(15) Ordinal: 280 Name: KEY_F(16) Ordinal: 281 Name: KEY_F(17) Ordinal: 282 Name: KEY_F(18) Ordinal: 283 Name: KEY_F(19) Ordinal: 284 Name: KEY_F(20) Ordinal: 285 Name: KEY_F(21) Ordinal: 286 Name: KEY_F(22) Ordinal: 287 Name: KEY_F(23) Ordinal: 288 Name: KEY_F(24) Ordinal: 289 Name: KEY_F(25) Ordinal: 290 Name: KEY_F(26) Ordinal: 291 Name: KEY_F(27) Ordinal: 292 Name: KEY_F(28) Ordinal: 293 Name: KEY_F(29) Ordinal: 294 Name: KEY_F(30) Ordinal: 295 Name: KEY_F(31) Ordinal: 296 Name: KEY_F(32) Ordinal: 297 Name: KEY_F(33) Ordinal: 298 Name: KEY_F(34) Ordinal: 299 Name: KEY_F(35) Ordinal: 300 Name: KEY_F(36) Ordinal: 301 Name: KEY_F(37) Ordinal: 302 Name: KEY_F(38) Ordinal: 303 Name: KEY_F(39) Ordinal: 304 Name: KEY_F(40) Ordinal: 305 Name: KEY_F(41) Ordinal: 306 Name: KEY_F(42) Ordinal: 307 Name: KEY_F(43) Ordinal: 308 Name: KEY_F(44) Ordinal: 309 Name: KEY_F(45) Ordinal: 310 Name: KEY_F(46) Ordinal: 311 Name: KEY_F(47) Ordinal: 312 Name: KEY_F(48) Ordinal: 313 Name: KEY_F(49) Ordinal: 314 Name: KEY_F(50) Ordinal: 315 Name: KEY_F(51) Ordinal: 316 Name: KEY_F(52) Ordinal: 317 Name: KEY_F(53) Ordinal: 318 Name: KEY_F(54) Ordinal: 319 Name: KEY_F(55) Ordinal: 320 Name: KEY_F(56) Ordinal: 321 Name: KEY_F(57) Ordinal: 322 Name: KEY_F(58) Ordinal: 323 Name: KEY_F(59) Ordinal: 324 Name: KEY_F(60) Ordinal: 325 Name: KEY_F(61) Ordinal: 326 Name: KEY_F(62) Ordinal: 327 Name: KEY_F(63) Ordinal: 328 Name: KEY_DL Ordinal: 329 Name: KEY_IL Ordinal: 330 Name: KEY_DC Ordinal: 331 Name: KEY_IC Ordinal: 332 Name: KEY_EIC Ordinal: 333 Name: KEY_CLEAR Ordinal: 334 Name: KEY_EOS Ordinal: 335 Name: KEY_EOL Ordinal: 336 Name: KEY_SF Ordinal: 337 Name: KEY_SR Ordinal: 338 Name: KEY_NPAGE Ordinal: 339 Name: KEY_PPAGE Ordinal: 340 Name: KEY_STAB Ordinal: 341 Name: KEY_CTAB Ordinal: 342 Name: KEY_CATAB Ordinal: 343 Name: KEY_ENTER Ordinal: 344 Name: KEY_SRESET Ordinal: 345 Name: KEY_RESET Ordinal: 346 Name: KEY_PRINT Ordinal: 347 Name: KEY_LL Ordinal: 348 Name: KEY_A1 Ordinal: 349 Name: KEY_A3 Ordinal: 350 Name: KEY_B2 Ordinal: 351 Name: KEY_C1 Ordinal: 352 Name: KEY_C3 Ordinal: 353 Name: KEY_BTAB Ordinal: 354 Name: KEY_BEG Ordinal: 355 Name: KEY_CANCEL Ordinal: 356 Name: KEY_CLOSE Ordinal: 357 Name: KEY_COMMAND Ordinal: 358 Name: KEY_COPY Ordinal: 359 Name: KEY_CREATE Ordinal: 360 Name: KEY_END Ordinal: 361 Name: KEY_EXIT Ordinal: 362 Name: KEY_FIND Ordinal: 363 Name: KEY_HELP Ordinal: 364 Name: KEY_MARK Ordinal: 365 Name: KEY_MESSAGE Ordinal: 366 Name: KEY_MOVE Ordinal: 367 Name: KEY_NEXT Ordinal: 368 Name: KEY_OPEN Ordinal: 369 Name: KEY_OPTIONS Ordinal: 370 Name: KEY_PREVIOUS Ordinal: 371 Name: KEY_REDO Ordinal: 372 Name: KEY_REFERENCE Ordinal: 373 Name: KEY_REFRESH Ordinal: 374 Name: KEY_REPLACE Ordinal: 375 Name: KEY_RESTART Ordinal: 376 Name: KEY_RESUME Ordinal: 377 Name: KEY_SAVE Ordinal: 378 Name: KEY_SBEG Ordinal: 379 Name: KEY_SCANCEL Ordinal: 380 Name: KEY_SCOMMAND Ordinal: 381 Name: KEY_SCOPY Ordinal: 382 Name: KEY_SCREATE Ordinal: 383 Name: KEY_SDC Ordinal: 384 Name: KEY_SDL Ordinal: 385 Name: KEY_SELECT Ordinal: 386 Name: KEY_SEND Ordinal: 387 Name: KEY_SEOL Ordinal: 388 Name: KEY_SEXIT Ordinal: 389 Name: KEY_SFIND Ordinal: 390 Name: KEY_SHELP Ordinal: 391 Name: KEY_SHOME Ordinal: 392 Name: KEY_SIC Ordinal: 393 Name: KEY_SLEFT Ordinal: 394 Name: KEY_SMESSAGE Ordinal: 395 Name: KEY_SMOVE Ordinal: 396 Name: KEY_SNEXT Ordinal: 397 Name: KEY_SOPTIONS Ordinal: 398 Name: KEY_SPREVIOUS Ordinal: 399 Name: KEY_SPRINT Ordinal: 400 Name: KEY_SREDO Ordinal: 401 Name: KEY_SREPLACE Ordinal: 402 Name: KEY_SRIGHT Ordinal: 403 Name: KEY_SRSUME Ordinal: 404 Name: KEY_SSAVE Ordinal: 405 Name: KEY_SSUSPEND Ordinal: 406 Name: KEY_SUNDO Ordinal: 407 Name: KEY_SUSPEND Ordinal: 408 Name: KEY_UNDO Ordinal: 409 Name: KEY_MOUSE Ordinal: 410 Name: KEY_RESIZE
/* * Tlf - contest logging program for amateur radio operators * Copyright (C) 2015 Thomas Beierlein <t...@forth-ev.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* User Interface helpers for ncurses based user interface */ #include <stdlib.h> #include <termios.h> #include <unistd.h> #include <ncurses.h> static int getkey(int wait); static int onechar(void); void stoptx(void) { printw("TX stopped.\n"); refresh(); } /** key_get wait for next key from terminal * */ int key_get() { return getkey(1); } /** key_poll return next key from terminal if there is one * */ int key_poll() { return getkey(0); } /* helper function to set 'nodelay' mode according to 'wait' * parameter and then ask for the next character * leaves 'nodelay' afterwards always as FALSE (meaning: wait for * character */ static int getkey(int wait) { int x = 0; nodelay(stdscr, wait ? FALSE : TRUE); x = onechar(); nodelay(stdscr, FALSE); return x; } /* New onechar() that takes advantage of Ncurses keypad mode and processes * certain escaped keys and assigns them to Ncurses values known by * keyname(). Also catches Escape and processes it immediately as well * as calling stoptx() for minimal delay. */ static int onechar(void) { int x = 0; int trash = 0; x = getch(); /* Replace Ctl-H and Backspace with KEY_BACKSPACE */ if (x == 8 || x == 127) x = KEY_BACKSPACE; if (x == 27) { nodelay(stdscr, TRUE); x = getch(); /* Escape pressed, not an escaped key. */ if (x == ERR) { stoptx(); return x = 27; } else if (x != 91) { switch (x) { case 32 ... 57: // Alt-Space to Alt-9, 160 - 185 case 97 ... 122: // Alt-a to alt-z, 225 - 250 x += 128; break; /* Not all terminals support Ctl-Shift-ch so * treat them as Alt-ch */ case 65 ... 78: // alt-A to alt-N, 225 - 238 case 80 ... 90: // alt-P to alt-Z, 240 - 250 x += 160; break; case 79: { x = getch(); /* Catch Alt-O */ if (x == ERR) { x = 239; break; } /* Key codes for Shift-F1 to Shift-F4 in Xfce terminal. */ if (x == 49) { x = getch(); if (x == 59) { x = getch(); if (x == 50) { x = getch(); switch (x) { case 80: { x = KEY_F(13); break; } case 81: { x = KEY_F(14); break; } case 82: { x = KEY_F(15); break; } case 83: { x = KEY_F(16); break; } } } } } } } nodelay(stdscr, FALSE); } else { nodelay(stdscr, FALSE); x = getch(); /* Get next code after 91 */ switch (x) { /* Key codes for this section: * 27 91 49 126 Home * 27 91 52 126 End * * Needed for the keypad Pg-Up and Pg-Dn keys in Xfce terminal. */ case 49: { x = getch(); if (x == 126) { x = KEY_HOME; break; } } case 52: { x = KEY_END; trash = getch(); break; } } } } /* It seems Xterm treats Alt-Space through Alt-9 with a prefix * character of 194 followed by 160 through 185. */ if (x == 194) { nodelay(stdscr, TRUE); trash = getch(); if (trash == ERR) return x; x = trash; // Alt-Space to Alt-9 if (x >= 160 && x <= 185) { nodelay(stdscr, FALSE); return x; } } /* It seems Xterm treats Alt-a to Alt-z with a prefix * character of 195 followed by 161-186 (a-z) or * 129-154 (A-Z). */ if (x == 195) { nodelay(stdscr, TRUE); trash = getch(); if (trash == ERR) return x; x = trash; switch (x) { case 161 ... 186: // Alt-a to Alt-z 225 - 250 x += 64; break; case 129 ... 154: // Alt-A to Alt-Z 225 - 250 x += 96; break; } nodelay(stdscr, FALSE); } return x; } static struct termios oldt, newt; int main(void) { int x; SCREEN *mainscreen; /* modify stdin terminals attributes to allow Ctrl-Q/S key recognition */ tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_iflag &= ~(IXON); tcsetattr(STDIN_FILENO, TCSANOW, &newt); /* activate ncurses terminal control */ if ((mainscreen = newterm(NULL, stdout, stdin)) == NULL) { perror("initscr"); printf("\nSorry, wrong terminal type !!!!! \n" "Try a linux text terminal or set TERM=linux !!!\n"); sleep(2); exit(EXIT_FAILURE); } noecho(); crmode(); keypad(stdscr, TRUE); // Have Ncurses process most special keys scrollok(stdscr, TRUE); set_term(mainscreen); /* Speed up Escape processing, setting the Ncurses Escape * dealy to 25 mS. Should be enough time to catch escaped * key codes. */ set_escdelay(25); printw("Tests escaped keys used in Tlf. Press Ctl-D to exit.\n\n"); printw("Escape delay time is: %d mS\n", get_escdelay()); /* Break out with Ctl-D. */ while (x != 4) { x = key_get(); printw("Ordinal: %d\t\tName: %s\n", x, keyname(x)); refresh(); } endwin(); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); exit(EXIT_SUCCESS); }
_______________________________________________ Tlf-devel mailing list Tlf-devel@nongnu.org https://lists.nongnu.org/mailman/listinfo/tlf-devel