When you say Function-F1, I assume you mean pressing that funny little Fn key in the corner of a laptop followed by the F1 key at the top left of the keyboard. And that your trying to map one of the extra keys like Sleep that some laptop keyboards have. It looks like that key is literally pressing multiple keys for you. First I see Win+L as one combo. On Windows, this shortcut locks the screen, but does not start the screensaver. Next, I see a mapping for XF86ScreenSaver which might mean that X is seeing some kind of sleep keycode. I'm guessing that that key on your laptop keyboard is physically sending out those three keycodes of Win + L + Sleep as a convenience for Windows users to quickly lock the screen and activate the screensaver. I'm not sure of a good way to filter those out. The Fn key on keyboards normally is not seen by the Linux Kernel. Instead, it changes which codes the keyboard tells the kernel. When I was trying to use a USB RF PowerPoint remote with OOo on Linux, I discovered that the button to start/stop the presentation was just a lame control to send out alternating F5 and ESC key codes. Other buttons were just as lame like sending out b to blank the screen.
What you are missing is that most terminal descriptions (linux
is in the minority here, owing to the pervasive use of hard-coded strings in .inputrc
) use application mode for special keys. That makes cursor-keys as shown by tput
and infocmp
differ from what your (uninitialized) terminal sends. curses applications always initialize the terminal, and the terminal data base is used for that purpose.
dialog
has its uses, but does not directly address this question. On the other hand, it is cumbersome (technically doable, rarely done) to provide a bash-only solution. Generally we use other languages to do this.
The problem with reading special keys is that they often are multiple bytes, including awkward characters such as escape and ~. You can do this with bash, but then you have to solve the problem of portably determining what special key this was.
dialog
both handles input of special keys and takes over (temporarily) your display. If you really want a simple command-line program, that isn't dialog
.
Here is a simple program in C which reads a special key and prints it in printable (and portable) form:
#include <curses.h>
int
main(void)
{
int ch;
const char *result;
char buffer[80];
filter();
newterm(NULL, stderr, stdin);
keypad(stdscr, TRUE);
noecho();
cbreak();
ch = getch();
if ((result = keyname(ch)) == 0) {
/* ncurses does the whole thing, other implementations need this */
if ((result = unctrl((chtype)ch)) == 0) {
sprintf(buffer, "%#x", ch);
result = buffer;
}
}
endwin();
printf("%s\n", result);
return 0;
}
Supposing this were called tgetch
, you would use it in your script like this:
case $(tgetch 2>/dev/null) in
KEY_UP)
echo "got cursor-up"
;;
KEY_BACKSPACE|"^H")
echo "got backspace"
;;
esac
Further reading:
Best Answer
You can use
rlwrap
for this, if you don't mind installing software.You'll probably want to keep a separate history file that only maintains history for the particular prompt in your script (ie. avoid mixing with the user's shell command history).
Here's an example that might work for you:
In the above script, the user can use all GNU readline functionality, with history served from — and stored in —
~/.myscript_history
. Tweak as needed.Alternatively, you can use bash's
read -e
, which enables readline forread
invocations, but you will probably find its history functionality too limited (ie. almost nonexistent).