LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Bash case with arrow keys (and DEL, BACKSPACE,etc) (https://www.linuxquestions.org/questions/programming-9/bash-case-with-arrow-keys-and-del-backspace-etc-523441/)

sadarax 01-28-2007 05:01 AM

Bash case with arrow keys (and DEL, BACKSPACE,etc)
 
I am trying to write a bash script using 'case' but I cannot figure out what the escape sequence would be for the arrow keys. Also, getting the escape sequence for the delete and backspace keys would be useful too. I know that \d is supposed to be delete, but it is not detecting properly....

unSpawn 01-28-2007 06:29 AM

If you don't mind me asking, is there any specific reason why you (are forced to) focus on using those keys?

sadarax 01-28-2007 06:36 AM

Quote:

Originally Posted by unSpawn
If you don't mind me asking, is there any specific reason why you (are forced to) focus on using those keys?

Sure, I am writing a bash script that grabs a single key, and throws the input to a 'case' select system. It would be nice to be able to assign actions when someone uses the arrow keys, but that is not the real reason I want to know how to accommodate the arrow keys. Currently with my code, either the script crashes or quits (not quite sure) when I use arrow keys, the DEL key. Also I cannot seem to assign control keys like "CTRL+C" to close the script. Without being able to specify an action, the script just keeps running.

unSpawn 01-28-2007 09:05 AM

Hmm. Similar to OSD stuff, right? To start with the last, CTRL+C can't be assigned since it sends a signal. The "best" ways to handle that within a script is to use "trap" since you can assign anything to that like a function to clean up before you go. Crashing is always interesting :-] Did you try to run your script with "set -xe" below the shebang line and look at the output? As far as the keys thing is concerned there are scripts (here on LQ too IIRC) that read single char input but in what way you can use it, I don't know. The problem is you probably will have to intercept settings (maybe using a custom inputrc) to make the keys emit something you can use. To give you an idea see: http://www.ibb.net/~anne/keyboard/troubleshooting.html.

StuartRothrock 12-16-2009 11:30 AM

This is a belated response - but maybe it can help someone else searching for a solution. Here is an example how to capture most keys and map them in the same file.

#!/bin/bash4 #(i copied bashV4 from F11 since it has associative arrays)
while IFS='^B' read -sn1 a # ^B is Control B
do
k=`perl -e "printf('%d',ord('$a'));"`
if (( k == 27 )) ; then
while IFS='' read -sn1 -t1 c
do
l=`perl -e "printf('%d',ord('$c'));"`
k="$k $l"
grep "^$k 0 " $0 > /dev/null
if (( $? == 0 )) ; then
break
fi
done
fi
echo $k
grep "^$k 0 " $0
done
# never gets here
exit

27 79 70 0 end
27 79 72 0 home
27 79 81 0 f2
27 79 82 0 f3
27 79 83 0 f4
27 91 49 53 126 0 f5
27 91 49 55 126 0 f6
27 91 49 56 126 0 f7
27 91 49 57 126 0 f8
27 91 50 48 126 0 f9
27 91 50 49 126 0 f10
27 91 50 52 126 0 f12
27 91 50 126 0 insert
27 91 51 126 0 delete
27 91 49 126 0 home
27 91 52 126 0 end
27 91 53 126 0 pageUp
27 91 54 126 0 pageDown
27 91 65 0 up
27 91 66 0 down
27 91 67 0 right
27 91 68 0 left
27 91 49 59 53 67 0 ctl-right
27 91 49 59 53 68 0 ctl-left
27 91 49 59 53 65 0 ctl-up
27 91 49 59 53 66 0 ctl-down
27 91 69 0 keypad-five
9 0 tab
33 0 bang
35 0 pound
36 0 dollarSign
37 0 percent
38 0 ampersand
40 0 openParen

dethrophes 12-18-2011 05:35 AM

A more complete solution
 
for anybody who like me ended up here looking for this solution.

this solution should manage just about any key combination.
Note alot of the keys may/will be mapped to X, window manager, terminal, etc...

Only real proble is detecting Escape,ctrl-[,ctrl-O as they are part of the sequences of the other keys.
so for example with this implementation pressing Escape 2 within a second will return ctrl-[ instead of Escape.




Code:

       

SpecialKeyCodes="
0027 0000 0;ctrl-alt-Enter
0027 0001 0;ctrl-alt-a
0027 0002 0;ctrl-alt-b
0027 0003 0;ctrl-alt-c
0027 0004 0;ctrl-alt-d
0027 0005 0;ctrl-alt-e
0027 0006 0;ctrl-alt-f
0027 0007 0;ctrl-alt-g
0027 0008 0;ctrl-alt-h
0027 0009 0;ctrl-alt-i
0027 0010 0;ctrl-alt-j
0027 0011 0;ctrl-alt-k
0027 0012 0;ctrl-alt-l
0027 0013 0;ctrl-alt-m
0027 0014 0;ctrl-alt-n
0027 0015 0;ctrl-alt-o
0027 0016 0;ctrl-alt-p
0027 0017 0;ctrl-alt-q
0027 0018 0;ctrl-alt-r
0027 0019 0;ctrl-alt-s
0027 0020 0;ctrl-alt-t
0027 0021 0;ctrl-alt-u
0027 0022 0;ctrl-alt-v
0027 0023 0;ctrl-alt-w
0027 0024 0;ctrl-alt-x
0027 0025 0;ctrl-alt-y
0027 0026 0;ctrl-alt-z
0027 0027 0;ctrl-alt-[; Escape
0027 0029 0;ctrl-alt-]
0027 0029 0;ctrl-alt-}
0027 0030 0;ctrl-alt-^
0027 0031 0;ctrl-alt-_
0027 0032 0;ctrl-alt-space;                        Space

0027 0079 0049 0059 0050 0070 0;shift-end
0027 0079 0049 0059 0050 0072 0;shift-home
0027 0079 0049 0059 0050 0080 0;shift-f1
0027 0079 0049 0059 0050 0081 0;shift-f2
0027 0079 0049 0059 0050 0082 0;shift-f3
0027 0079 0049 0059 0050 0083 0;shift-f4
0027 0079 0049 0059 0051 0070 0;alt-end
0027 0079 0049 0059 0051 0072 0;alt-home
0027 0079 0049 0059 0051 0080 0;alt-f1
0027 0079 0049 0059 0051 0081 0;alt-f2
0027 0079 0049 0059 0051 0082 0;alt-f3
0027 0079 0049 0059 0051 0083 0;alt-f4
0027 0079 0049 0059 0052 0070 0;alt-shift-end
0027 0079 0049 0059 0052 0072 0;alt-shift-home
0027 0079 0049 0059 0052 0080 0;alt-shift-f1
0027 0079 0049 0059 0052 0081 0;alt-shift-f2
0027 0079 0049 0059 0052 0082 0;alt-shift-f3
0027 0079 0049 0059 0052 0083 0;alt-shift-f4
0027 0079 0049 0059 0053 0070 0;ctrl-end
0027 0079 0049 0059 0053 0072 0;ctrl-home
0027 0079 0049 0059 0053 0080 0;ctrl-f1
0027 0079 0049 0059 0053 0081 0;ctrl-f2
0027 0079 0049 0059 0053 0082 0;ctrl-f3
0027 0079 0049 0059 0053 0083 0;ctrl-f4
0027 0079 0049 0059 0054 0070 0;ctrl-shift-end
0027 0079 0049 0059 0054 0072 0;ctrl-shift-home
0027 0079 0049 0059 0054 0080 0;ctrl-shift-f1
0027 0079 0049 0059 0054 0081 0;ctrl-shift-f2
0027 0079 0049 0059 0054 0082 0;ctrl-shift-f3
0027 0079 0049 0059 0054 0083 0;ctrl-shift-f4
0027 0079 0049 0059 0055 0070 0;ctrl-alt-end
0027 0079 0049 0059 0055 0072 0;ctrl-alt-home
0027 0079 0049 0059 0055 0080 0;ctrl-alt-f1
0027 0079 0049 0059 0055 0081 0;ctrl-alt-f2
0027 0079 0049 0059 0055 0082 0;ctrl-alt-f3
0027 0079 0049 0059 0055 0083 0;ctrl-alt-f4
0027 0079 0049 0059 0056 0070 0;ctrl-alt-shift-end
0027 0079 0049 0059 0056 0072 0;ctrl-alt-shift-home
0027 0079 0049 0059 0056 0080 0;ctrl-alt-shift-f1
0027 0079 0049 0059 0056 0081 0;ctrl-alt-shift-f2
0027 0079 0049 0059 0056 0082 0;ctrl-alt-shift-f3
0027 0079 0049 0059 0056 0083 0;ctrl-alt-shift-f4
0027 0079 0070 0;end
0027 0079 0072 0;home
0027 0079 0080 0;f1
0027 0079 0081 0;f2
0027 0079 0082 0;f3
0027 0079 0083 0;f4

0027 0091 0049 0053 0059 0050 0126 0;shift-f5
0027 0091 0049 0053 0059 0051 0126 0;alt-f5
0027 0091 0049 0053 0059 0052 0126 0;alt-shift-f5
0027 0091 0049 0053 0059 0053 0126 0;ctrl-f5
0027 0091 0049 0053 0059 0054 0126 0;ctrl-shift-f5
0027 0091 0049 0053 0059 0055 0126 0;ctrl-alt-f5
0027 0091 0049 0053 0059 0056 0126 0;ctrl-alt-shift-f5
0027 0091 0049 0053 0126 0;f5
0027 0091 0049 0055 0059 0050 0126 0;shift-f6
0027 0091 0049 0055 0059 0051 0126 0;alt-f6
0027 0091 0049 0055 0059 0052 0126 0;alt-shift-f6
0027 0091 0049 0055 0059 0053 0126 0;ctrl-f6
0027 0091 0049 0055 0059 0054 0126 0;ctrl-shift-f6
0027 0091 0049 0055 0059 0055 0126 0;ctrl-alt-f6
0027 0091 0049 0055 0059 0056 0126 0;ctrl-alt-shift-f6
0027 0091 0049 0055 0126 0;f6
0027 0091 0049 0056 0059 0050 0126 0;shift-f7
0027 0091 0049 0056 0059 0051 0126 0;alt-f7
0027 0091 0049 0056 0059 0052 0126 0;alt-shift-f7
0027 0091 0049 0056 0059 0053 0126 0;ctrl-f7
0027 0091 0049 0056 0059 0054 0126 0;ctrl-shift-f7
0027 0091 0049 0056 0059 0055 0126 0;ctrl-alt-f7
0027 0091 0049 0056 0059 0056 0126 0;ctrl-alt-shift-f7
0027 0091 0049 0056 0126 0;f7
0027 0091 0049 0057 0059 0050 0126 0;shift-f8
0027 0091 0049 0057 0059 0051 0126 0;alt-f8
0027 0091 0049 0057 0059 0052 0126 0;alt-shift-f8
0027 0091 0049 0057 0059 0053 0126 0;ctrl-f8
0027 0091 0049 0057 0059 0054 0126 0;ctrl-shift-f8
0027 0091 0049 0057 0059 0055 0126 0;ctrl-alt-f8
0027 0091 0049 0057 0059 0056 0126 0;ctrl-alt-shift-f8
0027 0091 0049 0057 0126 0;f8
0027 0091 0049 0059 0050 0065 0;shift-up
0027 0091 0049 0059 0050 0066 0;shift-down
0027 0091 0049 0059 0050 0067 0;shift-right
0027 0091 0049 0059 0050 0068 0;shift-left
0027 0091 0049 0059 0050 0069 0;shift-keypad-five
#0027 0091 0049 0059 0050 0126 0;shift-home
0027 0091 0049 0059 0051 0065 0;alt-up
0027 0091 0049 0059 0051 0066 0;alt-down
0027 0091 0049 0059 0051 0067 0;alt-right
0027 0091 0049 0059 0051 0068 0;alt-left
0027 0091 0049 0059 0051 0069 0;alt-keypad-five
#0027 0091 0049 0059 0051 0126 0;alt-home
0027 0091 0049 0059 0052 0065 0;alt-shift-up
0027 0091 0049 0059 0052 0066 0;alt-shift-down
0027 0091 0049 0059 0052 0067 0;alt-shift-right
0027 0091 0049 0059 0052 0068 0;alt-shift-left
0027 0091 0049 0059 0052 0069 0;alt-shift-keypad-five
#0027 0091 0049 0059 0052 0126 0;alt-shift-home
0027 0091 0049 0059 0053 0065 0;ctrl-up
0027 0091 0049 0059 0053 0066 0;ctrl-down
0027 0091 0049 0059 0053 0067 0;ctrl-right
0027 0091 0049 0059 0053 0068 0;ctrl-left
0027 0091 0049 0059 0053 0069 0;ctrl-keypad-five
#0027 0091 0049 0059 0053 0126 0;ctrl-home
0027 0091 0049 0059 0054 0065 0;ctrl-shift-up
0027 0091 0049 0059 0054 0066 0;ctrl-shift-down
0027 0091 0049 0059 0054 0067 0;ctrl-shift-right
0027 0091 0049 0059 0054 0068 0;ctrl-shift-left
0027 0091 0049 0059 0054 0069 0;ctrl-shift-keypad-five
#0027 0091 0049 0059 0054 0126 0;ctrl-shift-home
0027 0091 0049 0059 0055 0065 0;ctrl-alt-up
0027 0091 0049 0059 0055 0066 0;ctrl-alt-down
0027 0091 0049 0059 0055 0067 0;ctrl-alt-right
0027 0091 0049 0059 0055 0068 0;ctrl-alt-left
0027 0091 0049 0059 0055 0069 0;ctrl-alt-keypad-five
#0027 0091 0049 0059 0055 0126 0;ctrl-alt-home
0027 0091 0049 0059 0056 0065 0;ctrl-alt-shift-up
0027 0091 0049 0059 0056 0066 0;ctrl-alt-shift-down
0027 0091 0049 0059 0056 0067 0;ctrl-alt-shift-right
0027 0091 0049 0059 0056 0068 0;ctrl-alt-shift-left
0027 0091 0049 0059 0056 0069 0;ctrl-alt-shift-keypad-five
#0027 0091 0049 0059 0056 0126 0;ctrl-alt-shift-home
0027 0091 0049 0126 0;home
0027 0091 0050 0048 0059 0050 0126 0;shift-f9
0027 0091 0050 0048 0059 0051 0126 0;alt-f9
0027 0091 0050 0048 0059 0052 0126 0;alt-shift-f9
0027 0091 0050 0048 0059 0053 0126 0;ctrl-f9
0027 0091 0050 0048 0059 0054 0126 0;ctrl-shift-f9
0027 0091 0050 0048 0059 0055 0126 0;ctrl-alt-f9
0027 0091 0050 0048 0059 0056 0126 0;ctrl-alt-shift-f9
0027 0091 0050 0048 0126 0;f9
0027 0091 0050 0049 0059 0050 0126 0;shift-f10
0027 0091 0050 0049 0059 0051 0126 0;alt-f10
0027 0091 0050 0049 0059 0052 0126 0;alt-shift-f10
0027 0091 0050 0049 0059 0053 0126 0;ctrl-f10
0027 0091 0050 0049 0059 0054 0126 0;ctrl-shift-f10
0027 0091 0050 0049 0059 0055 0126 0;ctrl-alt-f10
0027 0091 0050 0049 0059 0056 0126 0;ctrl-alt-shift-f10
0027 0091 0050 0049 0126 0;f10
0027 0091 0050 0051 0059 0050 0126 0;shift-f11
0027 0091 0050 0051 0059 0051 0126 0;alt-f11
0027 0091 0050 0051 0059 0052 0126 0;alt-shift-f11
0027 0091 0050 0051 0059 0053 0126 0;ctrl-f11
0027 0091 0050 0051 0059 0054 0126 0;ctrl-shift-f11
0027 0091 0050 0051 0059 0055 0126 0;ctrl-alt-f11
0027 0091 0050 0051 0059 0056 0126 0;ctrl-alt-shift-f11
0027 0091 0050 0051 0126 0;f11
0027 0091 0050 0052 0059 0050 0126 0;shift-f12
0027 0091 0050 0052 0059 0051 0126 0;alt-f12
0027 0091 0050 0052 0059 0052 0126 0;alt-shift-f12
0027 0091 0050 0052 0059 0053 0126 0;ctrl-f12
0027 0091 0050 0052 0059 0054 0126 0;ctrl-shift-f12
0027 0091 0050 0052 0059 0055 0126 0;ctrl-alt-f12
0027 0091 0050 0052 0059 0056 0126 0;ctrl-alt-shift-f12
0027 0091 0050 0052 0126 0;f12
0027 0091 0050 0059 0050 0126 0;shift-insert
0027 0091 0050 0059 0051 0126 0;alt-insert
0027 0091 0050 0059 0052 0126 0;alt-shift-insert
0027 0091 0050 0059 0053 0126 0;ctrl-insert
0027 0091 0050 0059 0054 0126 0;ctrl-shift-insert
0027 0091 0050 0059 0055 0126 0;ctrl-alt-insert
0027 0091 0050 0059 0056 0126 0;ctrl-alt-shift-insert
0027 0091 0050 0126 0;insert
0027 0091 0051 0059 0050 0126 0;shift-delete
0027 0091 0051 0059 0051 0126 0;alt-delete
0027 0091 0051 0059 0052 0126 0;alt-shift-delete
0027 0091 0051 0059 0053 0126 0;ctrl-delete
0027 0091 0051 0059 0054 0126 0;ctrl-shift-delete
0027 0091 0051 0059 0055 0126 0;ctrl-alt-delete
0027 0091 0051 0059 0056 0126 0;ctrl-alt-shift-delete
0027 0091 0051 0126 0;delete
#0027 0091 0052 0059 0050 0126 0;shift-end
#0027 0091 0052 0059 0051 0126 0;alt-end
#0027 0091 0052 0059 0052 0126 0;alt-shift-end
#0027 0091 0052 0059 0053 0126 0;ctrl-end
#0027 0091 0052 0059 0054 0126 0;ctrl-shift-end
#0027 0091 0052 0059 0055 0126 0;ctrl-alt-end
#0027 0091 0052 0059 0056 0126 0;ctrl-alt-shift-end
0027 0091 0052 0126 0;end
0027 0091 0053 0059 0050 0126 0;shift-pageUp
0027 0091 0053 0059 0051 0126 0;alt-pageUp
0027 0091 0053 0059 0052 0126 0;alt-shift-pageUp
0027 0091 0053 0059 0053 0126 0;ctrl-pageUp
0027 0091 0053 0059 0054 0126 0;ctrl-shift-pageUp
0027 0091 0053 0059 0055 0126 0;ctrl-alt-pageUp
0027 0091 0053 0059 0056 0126 0;ctrl-alt-shift-pageUp
0027 0091 0053 0126 0;pageUp
0027 0091 0054 0059 0050 0126 0;shift-pageDown
0027 0091 0054 0059 0051 0126 0;alt-pageDown
0027 0091 0054 0059 0052 0126 0;alt-shift-pageDown
0027 0091 0054 0059 0053 0126 0;ctrl-pageDown
0027 0091 0054 0059 0054 0126 0;ctrl-shift-pageDown
0027 0091 0054 0059 0055 0126 0;ctrl-alt-pageDown
0027 0091 0054 0059 0056 0126 0;ctrl-alt-shift-pageDown
0027 0091 0054 0126 0;pageDown
0027 0091 0065 0;up
0027 0091 0066 0;down
0027 0091 0067 0;right
0027 0091 0068 0;left
0027 0091 0069 0;keypad-five
0027 0091 0090 0;shift-Horizontal-Tab

0027 0127 0;alt-delete;        Delete

"

ControlCharacters=(
        [0x00]="Enter"                        # "Null character"
        [0x01]="Start-of-Header"
        [0x02]="Start-of-Text"
        [0x03]="End-of-Text"
        [0x04]="End-of-Transmission"
        [0x05]="Enquiry"
        [0x06]="Acknowledgment"
        [0x07]="Bell"
        [0x08]="Backspace"
        [0x09]="Horizontal-Tab"
        [0x0A]="Line-feed"
        [0x0B]="Vertical-Tab"
        [0x0C]="Form-feed"
        [0x0D]="Carriage-return"
        [0x0E]="Shift-Out"
        [0x0F]="Shift-In"
        [0x10]="Data-Link-Escape"
        [0x11]="XON"
        [0x12]="Device-Control-2"
        [0x13]="XOFF"
        [0x14]="Device-Control-4"
        [0x15]="Negative-Acknowledgement"
        [0x16]="Synchronous-idle"
        [0x17]="End-of-Transmission-Block"
        [0x18]="Cancel"
        [0x19]="End-of-Medium"
        [0x1A]="Substitute"
        [0x1B]="Escape"
        [0x1C]="File-Separator"
        [0x1D]="Group-Separator"
        [0x1E]="Record-Separator"
        [0x1F]="Unit-Separator"
        [0x7F]="Delete"
)

        function read1 {
                IFS='' read  -sn1 "${@}" scancode
        }
        function read2 {
                # Captues Ctrl-C
                stty -echo raw
                scancode=$(dd bs=1 count=1 2>/dev/null || true )
                stty echo -raw
        }
        function ReadKey {
                local scancode
                local scancode_f
                local d
                if read1; then
                        d=$(printf '%04d' "'${scancode}")
                        case "${scancode}" in
                                [^[:cntrl:]])
                                        echo "${scancode}"
                                        ;;
                                $'\e')
                                        local -i icnt=1
                                        local oscancode Match=
                                        scancode_f="${d}"
                                        while read1 -t1 && [ ${icnt} -lt 9 ]; do
                                                let icnt+=1
                                                scancode_f="${scancode_f} $(printf '%04d' "'${scancode}")"
                                                if  [ ${icnt} -eq 2 ] ; then
                                                        case "${scancode}" in
                                                                [[O]) continue;;
                                                                [^[:cntrl:]]) Match="alt-${scancode}"; break ;;
                                                        esac
                                                fi
                                                Match="$(echo "${SpecialKeyCodes}" | grep "^${scancode_f} 0;")"
                                                if [ -n "${Match:-}" ]; then
                                                        Match="${Match#*;}"
                                                        Match="${Match%;*}"
                                                        break
                                                fi
                                                oscancode="${scancode}"
                                        done
                                        if [ -z "${Match}" ]; then
                                                case "${scancode_f}" in
                                                        '0027') Match="Escape" ;;
                                                        '0027 0079') Match="alt-O" ;;
                                                        '0027 0091') Match="alt-[" ;;
                                                esac
                                        fi
                                        if [ -n "${Match}" ]; then
                                                echo "${Match}"
                                        else
                                                # print any unrecognised codes
                                                echo "${scancode_f} 0;"
                                        fi
                                        ;;
                                *)
                                        d=$(printf '%d' "'${scancode}")
                                        if [ -n "${ControlCharacters[${d}]:-}" ]; then
                                                echo "${ControlCharacters[${d}]}"
                                        else
                                                # print any unrecognised control characters
                                                printf 'Unknown %02x\n' "'${scancode}"
                                        fi
                                        ;;
                        esac
                fi
        }
        function HandleKey {
                local Key
                while true; do
                        key="$(ReadKey )"
                        case "${key}" in
                                Carriage-return|Enter)
                                        break
                                        ;;
                                *)
                                        echo "${key}"
                                        ;;
                        esac
                done
        }
HandleKey


StuartRothrock 12-18-2011 08:44 AM

Run it and it exits without a keypress or anything. Some inherent characteristics of this site's HTML may have eaten some of the characters.

dethrophes 12-19-2011 07:11 AM

just call the function at the end of the file. Like this.

Code:

        SpecialKeyCodes="
0027 0000 0;ctrl-alt-Enter
0027 0001 0;ctrl-alt-a
0027 0002 0;ctrl-alt-b
0027 0003 0;ctrl-alt-c
0027 0004 0;ctrl-alt-d
0027 0005 0;ctrl-alt-e
0027 0006 0;ctrl-alt-f
0027 0007 0;ctrl-alt-g
0027 0008 0;ctrl-alt-h
0027 0009 0;ctrl-alt-i
0027 0010 0;ctrl-alt-j
0027 0011 0;ctrl-alt-k
0027 0012 0;ctrl-alt-l
0027 0013 0;ctrl-alt-m
0027 0014 0;ctrl-alt-n
0027 0015 0;ctrl-alt-o
0027 0016 0;ctrl-alt-p
0027 0017 0;ctrl-alt-q
0027 0018 0;ctrl-alt-r
0027 0019 0;ctrl-alt-s
0027 0020 0;ctrl-alt-t
0027 0021 0;ctrl-alt-u
0027 0022 0;ctrl-alt-v
0027 0023 0;ctrl-alt-w
0027 0024 0;ctrl-alt-x
0027 0025 0;ctrl-alt-y
0027 0026 0;ctrl-alt-z
0027 0027 0;ctrl-alt-[; Escape
0027 0029 0;ctrl-alt-]
0027 0029 0;ctrl-alt-}
0027 0030 0;ctrl-alt-^
0027 0031 0;ctrl-alt-_
0027 0032 0;ctrl-alt-space;                        Space

0027 0079 0049 0059 0050 0070 0;shift-end
0027 0079 0049 0059 0050 0072 0;shift-home
0027 0079 0049 0059 0050 0080 0;shift-f1
0027 0079 0049 0059 0050 0081 0;shift-f2
0027 0079 0049 0059 0050 0082 0;shift-f3
0027 0079 0049 0059 0050 0083 0;shift-f4
0027 0079 0049 0059 0051 0070 0;alt-end
0027 0079 0049 0059 0051 0072 0;alt-home
0027 0079 0049 0059 0051 0080 0;alt-f1
0027 0079 0049 0059 0051 0081 0;alt-f2
0027 0079 0049 0059 0051 0082 0;alt-f3
0027 0079 0049 0059 0051 0083 0;alt-f4
0027 0079 0049 0059 0052 0070 0;alt-shift-end
0027 0079 0049 0059 0052 0072 0;alt-shift-home
0027 0079 0049 0059 0052 0080 0;alt-shift-f1
0027 0079 0049 0059 0052 0081 0;alt-shift-f2
0027 0079 0049 0059 0052 0082 0;alt-shift-f3
0027 0079 0049 0059 0052 0083 0;alt-shift-f4
0027 0079 0049 0059 0053 0070 0;ctrl-end
0027 0079 0049 0059 0053 0072 0;ctrl-home
0027 0079 0049 0059 0053 0080 0;ctrl-f1
0027 0079 0049 0059 0053 0081 0;ctrl-f2
0027 0079 0049 0059 0053 0082 0;ctrl-f3
0027 0079 0049 0059 0053 0083 0;ctrl-f4
0027 0079 0049 0059 0054 0070 0;ctrl-shift-end
0027 0079 0049 0059 0054 0072 0;ctrl-shift-home
0027 0079 0049 0059 0054 0080 0;ctrl-shift-f1
0027 0079 0049 0059 0054 0081 0;ctrl-shift-f2
0027 0079 0049 0059 0054 0082 0;ctrl-shift-f3
0027 0079 0049 0059 0054 0083 0;ctrl-shift-f4
0027 0079 0049 0059 0055 0070 0;ctrl-alt-end
0027 0079 0049 0059 0055 0072 0;ctrl-alt-home
0027 0079 0049 0059 0055 0080 0;ctrl-alt-f1
0027 0079 0049 0059 0055 0081 0;ctrl-alt-f2
0027 0079 0049 0059 0055 0082 0;ctrl-alt-f3
0027 0079 0049 0059 0055 0083 0;ctrl-alt-f4
0027 0079 0049 0059 0056 0070 0;ctrl-alt-shift-end
0027 0079 0049 0059 0056 0072 0;ctrl-alt-shift-home
0027 0079 0049 0059 0056 0080 0;ctrl-alt-shift-f1
0027 0079 0049 0059 0056 0081 0;ctrl-alt-shift-f2
0027 0079 0049 0059 0056 0082 0;ctrl-alt-shift-f3
0027 0079 0049 0059 0056 0083 0;ctrl-alt-shift-f4
0027 0079 0070 0;end
0027 0079 0072 0;home
0027 0079 0080 0;f1
0027 0079 0081 0;f2
0027 0079 0082 0;f3
0027 0079 0083 0;f4

0027 0091 0049 0053 0059 0050 0126 0;shift-f5
0027 0091 0049 0053 0059 0051 0126 0;alt-f5
0027 0091 0049 0053 0059 0052 0126 0;alt-shift-f5
0027 0091 0049 0053 0059 0053 0126 0;ctrl-f5
0027 0091 0049 0053 0059 0054 0126 0;ctrl-shift-f5
0027 0091 0049 0053 0059 0055 0126 0;ctrl-alt-f5
0027 0091 0049 0053 0059 0056 0126 0;ctrl-alt-shift-f5
0027 0091 0049 0053 0126 0;f5
0027 0091 0049 0055 0059 0050 0126 0;shift-f6
0027 0091 0049 0055 0059 0051 0126 0;alt-f6
0027 0091 0049 0055 0059 0052 0126 0;alt-shift-f6
0027 0091 0049 0055 0059 0053 0126 0;ctrl-f6
0027 0091 0049 0055 0059 0054 0126 0;ctrl-shift-f6
0027 0091 0049 0055 0059 0055 0126 0;ctrl-alt-f6
0027 0091 0049 0055 0059 0056 0126 0;ctrl-alt-shift-f6
0027 0091 0049 0055 0126 0;f6
0027 0091 0049 0056 0059 0050 0126 0;shift-f7
0027 0091 0049 0056 0059 0051 0126 0;alt-f7
0027 0091 0049 0056 0059 0052 0126 0;alt-shift-f7
0027 0091 0049 0056 0059 0053 0126 0;ctrl-f7
0027 0091 0049 0056 0059 0054 0126 0;ctrl-shift-f7
0027 0091 0049 0056 0059 0055 0126 0;ctrl-alt-f7
0027 0091 0049 0056 0059 0056 0126 0;ctrl-alt-shift-f7
0027 0091 0049 0056 0126 0;f7
0027 0091 0049 0057 0059 0050 0126 0;shift-f8
0027 0091 0049 0057 0059 0051 0126 0;alt-f8
0027 0091 0049 0057 0059 0052 0126 0;alt-shift-f8
0027 0091 0049 0057 0059 0053 0126 0;ctrl-f8
0027 0091 0049 0057 0059 0054 0126 0;ctrl-shift-f8
0027 0091 0049 0057 0059 0055 0126 0;ctrl-alt-f8
0027 0091 0049 0057 0059 0056 0126 0;ctrl-alt-shift-f8
0027 0091 0049 0057 0126 0;f8
0027 0091 0049 0059 0050 0065 0;shift-up
0027 0091 0049 0059 0050 0066 0;shift-down
0027 0091 0049 0059 0050 0067 0;shift-right
0027 0091 0049 0059 0050 0068 0;shift-left
0027 0091 0049 0059 0050 0069 0;shift-keypad-five
#0027 0091 0049 0059 0050 0126 0;shift-home
0027 0091 0049 0059 0051 0065 0;alt-up
0027 0091 0049 0059 0051 0066 0;alt-down
0027 0091 0049 0059 0051 0067 0;alt-right
0027 0091 0049 0059 0051 0068 0;alt-left
0027 0091 0049 0059 0051 0069 0;alt-keypad-five
#0027 0091 0049 0059 0051 0126 0;alt-home
0027 0091 0049 0059 0052 0065 0;alt-shift-up
0027 0091 0049 0059 0052 0066 0;alt-shift-down
0027 0091 0049 0059 0052 0067 0;alt-shift-right
0027 0091 0049 0059 0052 0068 0;alt-shift-left
0027 0091 0049 0059 0052 0069 0;alt-shift-keypad-five
#0027 0091 0049 0059 0052 0126 0;alt-shift-home
0027 0091 0049 0059 0053 0065 0;ctrl-up
0027 0091 0049 0059 0053 0066 0;ctrl-down
0027 0091 0049 0059 0053 0067 0;ctrl-right
0027 0091 0049 0059 0053 0068 0;ctrl-left
0027 0091 0049 0059 0053 0069 0;ctrl-keypad-five
#0027 0091 0049 0059 0053 0126 0;ctrl-home
0027 0091 0049 0059 0054 0065 0;ctrl-shift-up
0027 0091 0049 0059 0054 0066 0;ctrl-shift-down
0027 0091 0049 0059 0054 0067 0;ctrl-shift-right
0027 0091 0049 0059 0054 0068 0;ctrl-shift-left
0027 0091 0049 0059 0054 0069 0;ctrl-shift-keypad-five
#0027 0091 0049 0059 0054 0126 0;ctrl-shift-home
0027 0091 0049 0059 0055 0065 0;ctrl-alt-up
0027 0091 0049 0059 0055 0066 0;ctrl-alt-down
0027 0091 0049 0059 0055 0067 0;ctrl-alt-right
0027 0091 0049 0059 0055 0068 0;ctrl-alt-left
0027 0091 0049 0059 0055 0069 0;ctrl-alt-keypad-five
#0027 0091 0049 0059 0055 0126 0;ctrl-alt-home
0027 0091 0049 0059 0056 0065 0;ctrl-alt-shift-up
0027 0091 0049 0059 0056 0066 0;ctrl-alt-shift-down
0027 0091 0049 0059 0056 0067 0;ctrl-alt-shift-right
0027 0091 0049 0059 0056 0068 0;ctrl-alt-shift-left
0027 0091 0049 0059 0056 0069 0;ctrl-alt-shift-keypad-five
#0027 0091 0049 0059 0056 0126 0;ctrl-alt-shift-home
0027 0091 0049 0126 0;home
0027 0091 0050 0048 0059 0050 0126 0;shift-f9
0027 0091 0050 0048 0059 0051 0126 0;alt-f9
0027 0091 0050 0048 0059 0052 0126 0;alt-shift-f9
0027 0091 0050 0048 0059 0053 0126 0;ctrl-f9
0027 0091 0050 0048 0059 0054 0126 0;ctrl-shift-f9
0027 0091 0050 0048 0059 0055 0126 0;ctrl-alt-f9
0027 0091 0050 0048 0059 0056 0126 0;ctrl-alt-shift-f9
0027 0091 0050 0048 0126 0;f9
0027 0091 0050 0049 0059 0050 0126 0;shift-f10
0027 0091 0050 0049 0059 0051 0126 0;alt-f10
0027 0091 0050 0049 0059 0052 0126 0;alt-shift-f10
0027 0091 0050 0049 0059 0053 0126 0;ctrl-f10
0027 0091 0050 0049 0059 0054 0126 0;ctrl-shift-f10
0027 0091 0050 0049 0059 0055 0126 0;ctrl-alt-f10
0027 0091 0050 0049 0059 0056 0126 0;ctrl-alt-shift-f10
0027 0091 0050 0049 0126 0;f10
0027 0091 0050 0051 0059 0050 0126 0;shift-f11
0027 0091 0050 0051 0059 0051 0126 0;alt-f11
0027 0091 0050 0051 0059 0052 0126 0;alt-shift-f11
0027 0091 0050 0051 0059 0053 0126 0;ctrl-f11
0027 0091 0050 0051 0059 0054 0126 0;ctrl-shift-f11
0027 0091 0050 0051 0059 0055 0126 0;ctrl-alt-f11
0027 0091 0050 0051 0059 0056 0126 0;ctrl-alt-shift-f11
0027 0091 0050 0051 0126 0;f11
0027 0091 0050 0052 0059 0050 0126 0;shift-f12
0027 0091 0050 0052 0059 0051 0126 0;alt-f12
0027 0091 0050 0052 0059 0052 0126 0;alt-shift-f12
0027 0091 0050 0052 0059 0053 0126 0;ctrl-f12
0027 0091 0050 0052 0059 0054 0126 0;ctrl-shift-f12
0027 0091 0050 0052 0059 0055 0126 0;ctrl-alt-f12
0027 0091 0050 0052 0059 0056 0126 0;ctrl-alt-shift-f12
0027 0091 0050 0052 0126 0;f12
0027 0091 0050 0059 0050 0126 0;shift-insert
0027 0091 0050 0059 0051 0126 0;alt-insert
0027 0091 0050 0059 0052 0126 0;alt-shift-insert
0027 0091 0050 0059 0053 0126 0;ctrl-insert
0027 0091 0050 0059 0054 0126 0;ctrl-shift-insert
0027 0091 0050 0059 0055 0126 0;ctrl-alt-insert
0027 0091 0050 0059 0056 0126 0;ctrl-alt-shift-insert
0027 0091 0050 0126 0;insert
0027 0091 0051 0059 0050 0126 0;shift-delete
0027 0091 0051 0059 0051 0126 0;alt-delete
0027 0091 0051 0059 0052 0126 0;alt-shift-delete
0027 0091 0051 0059 0053 0126 0;ctrl-delete
0027 0091 0051 0059 0054 0126 0;ctrl-shift-delete
0027 0091 0051 0059 0055 0126 0;ctrl-alt-delete
0027 0091 0051 0059 0056 0126 0;ctrl-alt-shift-delete
0027 0091 0051 0126 0;delete
#0027 0091 0052 0059 0050 0126 0;shift-end
#0027 0091 0052 0059 0051 0126 0;alt-end
#0027 0091 0052 0059 0052 0126 0;alt-shift-end
#0027 0091 0052 0059 0053 0126 0;ctrl-end
#0027 0091 0052 0059 0054 0126 0;ctrl-shift-end
#0027 0091 0052 0059 0055 0126 0;ctrl-alt-end
#0027 0091 0052 0059 0056 0126 0;ctrl-alt-shift-end
0027 0091 0052 0126 0;end
0027 0091 0053 0059 0050 0126 0;shift-pageUp
0027 0091 0053 0059 0051 0126 0;alt-pageUp
0027 0091 0053 0059 0052 0126 0;alt-shift-pageUp
0027 0091 0053 0059 0053 0126 0;ctrl-pageUp
0027 0091 0053 0059 0054 0126 0;ctrl-shift-pageUp
0027 0091 0053 0059 0055 0126 0;ctrl-alt-pageUp
0027 0091 0053 0059 0056 0126 0;ctrl-alt-shift-pageUp
0027 0091 0053 0126 0;pageUp
0027 0091 0054 0059 0050 0126 0;shift-pageDown
0027 0091 0054 0059 0051 0126 0;alt-pageDown
0027 0091 0054 0059 0052 0126 0;alt-shift-pageDown
0027 0091 0054 0059 0053 0126 0;ctrl-pageDown
0027 0091 0054 0059 0054 0126 0;ctrl-shift-pageDown
0027 0091 0054 0059 0055 0126 0;ctrl-alt-pageDown
0027 0091 0054 0059 0056 0126 0;ctrl-alt-shift-pageDown
0027 0091 0054 0126 0;pageDown
0027 0091 0065 0;up
0027 0091 0066 0;down
0027 0091 0067 0;right
0027 0091 0068 0;left
0027 0091 0069 0;keypad-five
0027 0091 0090 0;shift-Horizontal-Tab

0027 0127 0;alt-delete;        Delete

"

ControlCharacters=(
        [0x00]="Enter"                        # "Null character"
        [0x01]="Start-of-Header"
        [0x02]="Start-of-Text"
        [0x03]="End-of-Text"
        [0x04]="End-of-Transmission"
        [0x05]="Enquiry"
        [0x06]="Acknowledgment"
        [0x07]="Bell"
        [0x08]="Backspace"
        [0x09]="Horizontal-Tab"
        [0x0A]="Line-feed"
        [0x0B]="Vertical-Tab"
        [0x0C]="Form-feed"
        [0x0D]="Carriage-return"
        [0x0E]="Shift-Out"
        [0x0F]="Shift-In"
        [0x10]="Data-Link-Escape"
        [0x11]="XON"
        [0x12]="Device-Control-2"
        [0x13]="XOFF"
        [0x14]="Device-Control-4"
        [0x15]="Negative-Acknowledgement"
        [0x16]="Synchronous-idle"
        [0x17]="End-of-Transmission-Block"
        [0x18]="Cancel"
        [0x19]="End-of-Medium"
        [0x1A]="Substitute"
        [0x1B]="Escape"
        [0x1C]="File-Separator"
        [0x1D]="Group-Separator"
        [0x1E]="Record-Separator"
        [0x1F]="Unit-Separator"
        [0x7F]="Delete"
)

        function read1 {
                IFS='' read  -sn1 "${@}" scancode
        }
        function read2 {
                # Captues Ctrl-C
                local -i ECode=0
                stty -echo raw
                scancode=$(dd bs=1 count=1 2>/dev/null || true )
                stty echo -raw
        }
        function ReadKey {
                local scancode
                local scancode_f
                local d
                if read1 ${1:-}; then
                        d=$(printf '%04d' "'${scancode}")
                        case "${scancode}" in
                                [^[:cntrl:]])
                                        echo "${scancode}"
                                        ;;
                                $'\e')
                                        local -i icnt=1
                                        local oscancode Match=
                                        scancode_f="${d}"
                                        while read1 -t1 && [ ${icnt} -lt 9 ]; do
                                                let icnt+=1
                                                scancode_f="${scancode_f} $(printf '%04d' "'${scancode}")"
                                                if  [ ${icnt} -eq 2 ] ; then
                                                        case "${scancode}" in
                                                                [[O]) continue;;
                                                                [^[:cntrl:]]) Match="alt-${scancode}"; break ;;
                                                        esac
                                                fi
                                                Match="$(echo "${SpecialKeyCodes}" | grep "^${scancode_f} 0;")"
                                                if [ -n "${Match:-}" ]; then
                                                        Match="${Match#*;}"
                                                        Match="${Match%;*}"
                                                        break
                                                fi
                                                oscancode="${scancode}"
                                        done
                                        if [ -z "${Match}" ]; then
                                                case "${scancode_f}" in
                                                        '0027') Match="Escape" ;;
                                                        '0027 0079') Match="alt-O" ;;
                                                        '0027 0091') Match="alt-[" ;;
                                                esac
                                        fi
                                        if [ -n "${Match}" ]; then
                                                echo "${Match}"
                                        else
                                                # print any unrecognised codes
                                                echo "${scancode_f} 0;"
                                        fi
                                        ;;
                                *)
                                        d=$(printf '%d' "'${scancode}")
                                        if [ -n "${ControlCharacters[${d}]:-}" ]; then
                                                echo "${ControlCharacters[${d}]}"
                                        else
                                                # print any unrecognised control characters
                                                printf 'Unknown %02x\n' "'${scancode}"
                                        fi
                                        ;;
                        esac
                fi
        }
        function HandleKey {
                local Key
                while true; do
                        key="$(ReadKey )"
                        case "${key}" in
                                Carriage-return|Enter)
                                        echo "${key}"
                                        break
                                        ;;
                                *)
                                        echo "${key}"
                                        ;;
                        esac
                done
        }
# HandlKey is a simple handler for ReadKey
# to show how I intended to use ReadKey
# it grabs every key you press and prints out
# the Code for the key/key-combination
# It also prints out any key code it doesn't recognise
# to make it simple to add new keys to the list.
HandleKey

when you type something you should see something like

Enter
Escape
alt-A
alt-a
ctrl-alt-shift-left

NevemTeve 12-19-2011 11:14 PM

That's what C+ncurses is good for... (of course you can eat your breakfast with a comb, but a fork is much better.)

dethrophes 12-20-2011 09:52 PM

Last version no, I think unless someone finds a bug in it.
 
I'd have to disagree. for my purposes c and ncurses would be overkill.
I've wanted this sort of functionality in bash for a while now, so I finally got myself to do it.
And while I was at it I wanted a decent solution.

Anyway now fixed the last of the problems and optimized for performance.
takes less than 0.005s for all keys now. most are less than 0.001s.
Also reduced the footprint.

The code should be easier to read now.



Code:


        SpecialKeyCodes2=$'
\e\ca=ctrl-alt-a
\e\cb=ctrl-alt-b
\e\cc=ctrl-alt-c
\e\cd=ctrl-alt-d
\e\ce=ctrl-alt-e
\e\cf=ctrl-alt-f
\e\a=ctrl-alt-g
\e\b=ctrl-alt-h
\e\t=ctrl-alt-i
\e\n=ctrl-alt-j
\e\v=ctrl-alt-k
\e\cl=ctrl-alt-l
\e\r=ctrl-alt-m
\e\cn=ctrl-alt-n
\e\co=ctrl-alt-o
\e\cp=ctrl-alt-p
\e\cq=ctrl-alt-q
\e\cr=ctrl-alt-r
\e\cs=ctrl-alt-s
\e\ct=ctrl-alt-t
\e\cu=ctrl-alt-u
\e\cv=ctrl-alt-v
\e\cw=ctrl-alt-w
\e\cx=ctrl-alt-x
\e\cy=ctrl-alt-y
\e\cz=ctrl-alt-z
\e\c[=ctrl-alt-[
\e\c]=ctrl-alt-]
\e\c}=ctrl-alt-}
\e\c^=ctrl-alt-^
\e\c_=ctrl-alt-_

\eO1;2F=shift-end
\eO1;2H=shift-home
\eO1;2P=shift-f1
\eO1;2Q=shift-f2
\eO1;2R=shift-f3
\eO1;2S=shift-f4
\eO1;3F=alt-end
\eO1;3H=alt-home
\eO1;3P=alt-f1
\eO1;3Q=alt-f2
\eO1;3R=alt-f3
\eO1;3S=alt-f4
\eO1;4F=alt-shift-end
\eO1;4H=alt-shift-home
\eO1;4P=alt-shift-f1
\eO1;4Q=alt-shift-f2
\eO1;4R=alt-shift-f3
\eO1;4S=alt-shift-f4
\eO1;5F=ctrl-end
\eO1;5H=ctrl-home
\eO1;5P=ctrl-f1
\eO1;5Q=ctrl-f2
\eO1;5R=ctrl-f3
\eO1;5S=ctrl-f4
\eO1;6F=ctrl-shift-end
\eO1;6H=ctrl-shift-home
\eO1;6P=ctrl-shift-f1
\eO1;6Q=ctrl-shift-f2
\eO1;6R=ctrl-shift-f3
\eO1;6S=ctrl-shift-f4
\eO1;7F=ctrl-alt-end
\eO1;7H=ctrl-alt-home
\eO1;7P=ctrl-alt-f1
\eO1;7Q=ctrl-alt-f2
\eO1;7R=ctrl-alt-f3
\eO1;7S=ctrl-alt-f4
\eO1;8F=ctrl-alt-shift-end
\eO1;8H=ctrl-alt-shift-home
\eO1;8P=ctrl-alt-shift-f1
\eO1;8Q=ctrl-alt-shift-f2
\eO1;8R=ctrl-alt-shift-f3
\eO1;8S=ctrl-alt-shift-f4
\eOF=end
\eOH=home
\eOP=f1
\eOQ=f2
\eOR=f3
\eOS=f4

\e[15;2~=shift-f5
\e[15;3~=alt-f5
\e[15;4~=alt-shift-f5
\e[15;5~=ctrl-f5
\e[15;6~=ctrl-shift-f5
\e[15;7~=ctrl-alt-f5
\e[15;8~=ctrl-alt-shift-f5
\e[15~=f5
\e[17;2~=shift-f6
\e[17;3~=alt-f6
\e[17;4~=alt-shift-f6
\e[17;5~=ctrl-f6
\e[17;6~=ctrl-shift-f6
\e[17;7~=ctrl-alt-f6
\e[17;8~=ctrl-alt-shift-f6
\e[17~=f6
\e[18;2~=shift-f7
\e[18;3~=alt-f7
\e[18;4~=alt-shift-f7
\e[18;5~=ctrl-f7
\e[18;6~=ctrl-shift-f7
\e[18;7~=ctrl-alt-f7
\e[18;8~=ctrl-alt-shift-f7
\e[18~=f7
\e[19;2~=shift-f8
\e[19;3~=alt-f8
\e[19;4~=alt-shift-f8
\e[19;5~=ctrl-f8
\e[19;6~=ctrl-shift-f8
\e[19;7~=ctrl-alt-f8
\e[19;8~=ctrl-alt-shift-f8
\e[19~=f8
\e[1;2A=shift-up
\e[1;2B=shift-down
\e[1;2C=shift-right
\e[1;2D=shift-left
\e[1;2E=shift-keypad-five
#\e[1;2~=shift-home
\e[1;3A=alt-up
\e[1;3B=alt-down
\e[1;3C=alt-right
\e[1;3D=alt-left
\e[1;3E=alt-keypad-five
#\e[1;3~=alt-home
\e[1;4A=alt-shift-up
\e[1;4B=alt-shift-down
\e[1;4C=alt-shift-right
\e[1;4D=alt-shift-left
\e[1;4E=alt-shift-keypad-five
#\e[1;4~=alt-shift-home
\e[1;5A=ctrl-up
\e[1;5B=ctrl-down
\e[1;5C=ctrl-right
\e[1;5D=ctrl-left
\e[1;5E=ctrl-keypad-five
#\e[1;5~=ctrl-home
\e[1;6A=ctrl-shift-up
\e[1;6B=ctrl-shift-down
\e[1;6C=ctrl-shift-right
\e[1;6D=ctrl-shift-left
\e[1;6E=ctrl-shift-keypad-five
#\e[1;6~=ctrl-shift-home
\e[1;7A=ctrl-alt-up
\e[1;7B=ctrl-alt-down
\e[1;7C=ctrl-alt-right
\e[1;7D=ctrl-alt-left
\e[1;7E=ctrl-alt-keypad-five
#\e[1;7~=ctrl-alt-home
\e[1;8A=ctrl-alt-shift-up
\e[1;8B=ctrl-alt-shift-down
\e[1;8C=ctrl-alt-shift-right
\e[1;8D=ctrl-alt-shift-left
\e[1;8E=ctrl-alt-shift-keypad-five
#\e[1;8~=ctrl-alt-shift-home
\e[1~=home
\e[20;2~=shift-f9
\e[20;3~=alt-f9
\e[20;4~=alt-shift-f9
\e[20;5~=ctrl-f9
\e[20;6~=ctrl-shift-f9
\e[20;7~=ctrl-alt-f9
\e[20;8~=ctrl-alt-shift-f9
\e[20~=f9
\e[21;2~=shift-f10
\e[21;3~=alt-f10
\e[21;4~=alt-shift-f10
\e[21;5~=ctrl-f10
\e[21;6~=ctrl-shift-f10
\e[21;7~=ctrl-alt-f10
\e[21;8~=ctrl-alt-shift-f10
\e[21~=f10
\e[23;2~=shift-f11
\e[23;3~=alt-f11
\e[23;4~=alt-shift-f11
\e[23;5~=ctrl-f11
\e[23;6~=ctrl-shift-f11
\e[23;7~=ctrl-alt-f11
\e[23;8~=ctrl-alt-shift-f11
\e[23~=f11
\e[24;2~=shift-f12
\e[24;3~=alt-f12
\e[24;4~=alt-shift-f12
\e[24;5~=ctrl-f12
\e[24;6~=ctrl-shift-f12
\e[24;7~=ctrl-alt-f12
\e[24;8~=ctrl-alt-shift-f12
\e[24~=f12
\e[2;2~=shift-insert
\e[2;3~=alt-insert
\e[2;4~=alt-shift-insert
\e[2;5~=ctrl-insert
\e[2;6~=ctrl-shift-insert
\e[2;7~=ctrl-alt-insert
\e[2;8~=ctrl-alt-shift-insert
\e[2~=insert
\e[3;2~=shift-delete
\e[3;3~=alt-delete
\e[3;4~=alt-shift-delete
\e[3;5~=ctrl-delete
\e[3;6~=ctrl-shift-delete
\e[3;7~=ctrl-alt-delete
\e[3;8~=ctrl-alt-shift-delete
\e[3~=delete
#\e[4;2~=shift-end
#\e[4;3~=alt-end
#\e[4;4~=alt-shift-end
#\e[4;5~=ctrl-end
#\e[4;6~=ctrl-shift-end
#\e[4;7~=ctrl-alt-end
#\e[4;8~=ctrl-alt-shift-end
\e[4~=end
\e[5;2~=shift-pageUp
\e[5;3~=alt-pageUp
\e[5;4~=alt-shift-pageUp
\e[5;5~=ctrl-pageUp
\e[5;6~=ctrl-shift-pageUp
\e[5;7~=ctrl-alt-pageUp
\e[5;8~=ctrl-alt-shift-pageUp
\e[5~=pageUp
\e[6;2~=shift-pageDown
\e[6;3~=alt-pageDown
\e[6;4~=alt-shift-pageDown
\e[6;5~=ctrl-pageDown
\e[6;6~=ctrl-shift-pageDown
\e[6;7~=ctrl-alt-pageDown
\e[6;8~=ctrl-alt-shift-pageDown
\e[6~=pageDown
\e[A=up
\e[B=down
\e[C=right
\e[D=left
\e[E=keypad-five
\e[Z=shift-Horizontal-Tab

\e\x7f=alt-delete

'

#echo "${#SpecialKeyCodes2}"



ControlCharacters=(
        [0x00]="Enter"                        # "Null character"
        [0x01]="Start-of-Header"
        [0x02]="Start-of-Text"
        [0x03]="End-of-Text"
        [0x04]="End-of-Transmission"
        [0x05]="Enquiry"
        [0x06]="Acknowledgment"
        [0x07]="Bell"
        [0x08]="Backspace"
        [0x09]="Horizontal-Tab"
        [0x0A]="Line-feed"
        [0x0B]="Vertical-Tab"
        [0x0C]="Form-feed"
        [0x0D]="Carriage-return"
        [0x0E]="Shift-Out"
        [0x0F]="Shift-In"
        [0x10]="Data-Link-Escape"
        [0x11]="XON"
        [0x12]="Device-Control-2"
        [0x13]="XOFF"
        [0x14]="Device-Control-4"
        [0x15]="Negative-Acknowledgement"
        [0x16]="Synchronous-idle"
        [0x17]="End-of-Transmission-Block"
        [0x18]="Cancel"
        [0x19]="End-of-Medium"
        [0x1A]="Substitute"
        [0x1B]="Escape"
        [0x1C]="File-Separator"
        [0x1D]="Group-Separator"
        [0x1E]="Record-Separator"
        [0x1F]="Unit-Separator"
        [0x7F]="Delete"
)

        function escapeCtrlCharsString {
                local -i idx=${#1}
                local nString=""
                for (( idx=0; $idx<${#1}; idx++ )) ; do
                        case "${1:${idx}:1}" in
                                [^[:cntrl:]])        nString+="${1:${idx}:1}";;
                                $'\e')                nString+='\e';;
                                $'\a')                nString+='\a';;
                                $'\n')                nString+='\n';;
                                $'\b')                nString+='\b';;
                                $'\v')                nString+='\v';;
                                $'\t')                nString+='\t';;
                                $'\r')                nString+='\r';;
                                *)                nString+="$(printf '\\x%02x' "'${1:${idx}:1}")";;
                        esac
                done
                echo "${nString}"
        }
        function ReadKey {
                local scancode

                if IFS='' read  -sN1 ${1:-} scancode; then
                        case "${scancode}" in
                                [^[:cntrl:]])
                                        #echo -n "$(escapeCtrlCharsString "${scancode}")="
                                        echo -n "${scancode}"
                                        ;;
                                $'\e')
                                        while IFS='' read -srN1 -t0.0001 ; do
                                                scancode+="${REPLY}"
                                        done
                                        #echo -n "$(escapeCtrlCharsString "${scancode}")="
                                        case "${scancode}" in
                                                        $'\e'[^[:cntrl:]]) echo -n "alt-${scancode:1}" ;;
                                                        $'\e\n') echo -n "ctrl-alt-j" ;;
                                                        $'\e\r') echo -n "ctrl-alt-m" ;;
                                                        *)
                                                                local Match="$(echo -n "${SpecialKeyCodes2}" | LC_ALL=C grep -F -m 1 -e "${scancode}=")"
                                                                if [ -n "${Match:-}" ]; then
                                                                        Match="${Match#*=}"
                                                                        echo "${Match%;*}"
                                                                else
                                                                        echo "$(escapeCtrlCharsString ${scancode}")="
                                                                fi
                                                                ;;
                                        esac
                                        ;;
                                *)
                                        local h=$(printf "%x" "'${scancode}")
                                        #echo -n "$(escapeCtrlCharsString "${scancode}")="
                                        echo -n "${ControlCharacters["0x${h}"]:-\x${h}=}"
                                        ;;
                        esac
                fi
        }
        function HandleReadKey {
                local Key
                while true; do
                        key="$(ReadKey )"
                        echo "\"${key}\""
                        case "${key}" in
                                Carriage-return|Enter|q)        break        ;;
                        esac
                done
        }
HandleReadKey


dethrophes 01-07-2012 12:06 AM

Added Mouse support and Sun Function Keys
 
Another rewrite, as I got more comfortable with how it all works.
Added full mouse support at least as much as seems to be supported by my terminal i.e. btn 1-3 scroll up and scroll down & motion tracking.
added the codes for Sun Function keys and Meta key. i.e. Ctrl Alt Shift & Meta.




Code:

#!/bin/bash
#set -o errexit
#set -o errtrace
set -o nounset


  if [ "${S8C1T:-0}" != "1" ] ; then
    declare -gr SS3=$'\eO'      # Single Shift Select of G3 Character Set ( SS3 is 0x8f): affects next character only
    declare -gr CSI=$'\e['      # Control Sequence Introducer ( CSI is 0x9b)
  else
    declare -gr SS3=$'\x8f'    # Single Shift Select of G3 Character Set ( SS3 is 0x8f): affects next character only
    declare -gr CSI=$'\x9b'    # Control Sequence Introducer ( CSI is 0x9b)
  fi


  function  vt100_DECRST { 
    IFS=';' eval 'echo -n "${CSI}?${*?Missing Pm}l"'
  }
  function  vt100_DECSET { 
    IFS=';' eval 'echo -n "${CSI}?${*?Missing Pm}h"'
  }
  mouse_type=(
        [0]=9    ## X10 mouse reporting, for compatibility with X10's xterm, reports on button press.
        [1]=1000  ## X11 mouse reporting, reports on button press and release.
        [2]=1001  ## highlight reporting, useful for reporting mouse highlights
        [3]=1002  ## button movement reporting, reports movement when a button is presse
        [4]=1003  ## all movement reporting, reports all movements.
        [5]=1004  ## FocusIn/FocusOut can be combined with any of the mouse events since it uses a different protocol. When set, it causes xterm to send CSI I when the terminal gains focus, and CSI O when it loses focus.
        [6]=1005  ## Extended mouse mode enables UTF-8 encoding for C x and C y under all tracking modes, expanding the maximum encodable position from 223 to 2015. For positions less than 95, the resulting output is identical under both modes. Under extended mouse mode, positions greater than 95 generate "extra" bytes which will confuse applications which do not treat their input as a UTF-8 stream. Likewise, C b will be UTF-8 encoded, to reduce confusion with wheel mouse events.
    )

  function ord {
    printf -v "${1?Missing Dest Variable}" "${3:-%d}" "'${2?Missing Char}"
  }
  function ord.eascii {
    LC_CTYPE=C ord "${@}"
  }
  function AdjustMousePos {
    local -i _INDEX
    ord.eascii _INDEX "${2}"
    eval ${1}'=$(( ${_INDEX}-32))'
  }

  ###############################
  ##
  ##    READ KEY CRAP
  ##
  ##
  ###############################
  KeyModifiers=(
            [2]="S"  [3]="A"  [4]="AS"  [5]="C"  [6]="CS"  [7]="CA"    [8]="CAS"
    [9]="M" [10]="MS" [11]="MA" [12]="MAS" [13]="MC" [14]="MCS" [15]="MCA" [16]="MCAS"
    )
  KeybFntKeys=(
    [1]="home" [2]="insert" [3]="delete"  [4]="end"  [5]="pageUp" [6]="pageDown"
    [11]="f1"  [12]="f2"    [13]="f3"    [14]="f4"  [15]="f5"
    [17]="f6"  [18]="f7"    [19]="f8"    [20]="f9"  [21]="f10"
    [23]="f11" [24]="f12"  [25]="f13"    [26]="f14"  [28]="f15"
    [29]="f16" [31]="f17"  [32]="f18"    [33]="f19"  [34]="f20"
    )
  SunKeybFntKeys=(
    [214]="home"  [2]="insert" [3]="delete" [4]="end"  [216]="pageUp" [222]="pageDown"
    [224]="f1"  [225]="f2"    [226]="f3"    [227]="f4"  [228]="f5"
    [229]="f6"  [230]="f7"    [231]="f8"    [232]="f9"  [233]="f10"
    [192]="f11" [193]="f12"  [218]="keypad-five" [220]="keypad-delete"
    )
  KeybFntKeysAlt=(
    # A          B              C              D            E                  F            H       
    [0x41]="up" [0x42]="down" [0x43]="right" [0x44]="left" [0x45]="keypad-five" [0x46]="end" [0x48]="home"   
    # I              O
    [0x49]="InFocus" [0x4f]="OutOfFocus"     
    # P          Q          R          S            Z         
    [0x50]="f1" [0x51]="f2" [0x52]="f3" [0x53]="f4"  [0x5a]="S-HT"
    )
  C0CtrlChars=(
    [0x00]="Null" [0x01]="SOH" [0x02]="STX" [0x03]="ETX" [0x04]="EOT" [0x05]="ENQ" [0x06]="ACK"
    [0x07]="BEL"  [0x08]="BS"  [0x09]="HT"  [0x0A]="LF"  [0x0B]="VT"  [0x0C]="FF"  [0x0D]="CR" 
    [0x0E]="SO"  [0x0F]="SI"  [0x10]="DLE" [0x11]="DC1" [0x12]="DC2" [0x13]="DC3" [0x14]="DC4"
    [0x15]="NAK"  [0x16]="SYN" [0x17]="ETB" [0x18]="CAN" [0x19]="EM"  [0x1A]="SUB" [0x1B]="ESC"
    [0x1C]="FS"  [0x1D]="GS"  [0x1E]="RS"  [0x1F]="US"  [0x20]="SP"  [0x7F]="DEL"
  )
  C1CtrlCharsAlt=(
    [0x01]="CA-A" [0x02]="CA-B" [0x03]="CA-C" [0x04]="CA-D"  [0x05]="CA-E" [0x06]="CA-F" [0x07]="CA-G"
    [0x08]="CA-H" [0x09]="CA-I" [0x0a]="CA-J" [0x0b]="CA-K"  [0x0c]="CA-L" [0x0d]="CA-M" [0x0e]="CA-N" 
    [0x0f]="CA-O" [0x10]="CA-P" [0x11]="CA-Q" [0x12]="CA-R"  [0x13]="CA-S" [0x14]="CA-T" [0x15]="CA-U"
    [0x16]="CA-V" [0x17]="CA-W" [0x18]="CA-X" [0x19]="CA-Y"  [0x1a]="CA-Z" [0x1b]="CA-[" [0x1c]="CA-]"
    [0x1d]="CA-}" [0x1e]="CA-^" [0x1f]="CA-_" [0x20]="CA-SP" [0x7F]="A-DEL"
  )
  MouseButtons=(
    [0x00]="MB1-P" [0x01]="MB2-P" [0x02]="MB3-P" [0x03]="MB-R"
    [0x20]="MB1-M" [0x21]="MB2-M" [0x22]="MB3-M" [0x23]="MB-M"
    [0x40]="MB4-P" [0x41]="MB5-P"
  )
  MouseMetaButtons=(
    [0x04]="S-"    [0x08]="A-"    [0x0c]="AS-"
    [0x10]="C-"    [0x14]="CS-"  [0x1c]="CAS-"
  )
  function GetMouseButton {
    local MouseBtn
    AdjustMousePos MouseBtn "${2}"
    MouseBtn="${MouseMetaButtons[$(( ${MouseBtn} & 0x1C))]-}${MouseButtons[$(( ${MouseBtn} & 0xe3))]}"
    eval ${1}='"${MouseBtn}"'
  }
  mouse_on="$(vt100_DECSET ${mouse_type[1]})"
  mouse_off="$(vt100_DECRST "${mouse_type[1]}" )"


  function ReadKey {
    unset UInput[@]
    local escapeSequence
    local REPLY

    echo -n "${mouse_on}"
    if IFS='' read  -srN1 ${1:-} escapeSequence; then
      case "${escapeSequence}" in
        [^[:cntrl:]])
          UInput[0]="${escapeSequence}"
          ;;
        $'\e')
          while IFS='' read -srN1 -t0.0001 ; do
            escapeSequence+="${REPLY}"
          done
          case "${escapeSequence}" in
              $'\e'[^[:cntrl:]]) echo -n "A-${escapeSequence:1}" ;;
              ${CSI}t)
                UInput[0]="MouseTrack"
                AdjustMousePos UInput[1] "${escapeSequence:3:1}"
                AdjustMousePos UInput[2] "${escapeSequence:4:1}"
                ;;
              ${CSI}T)
                UInput[0]="MouseTrack"
                AdjustMousePos UInput[1] "${escapeSequence:3:1}"
                AdjustMousePos UInput[2] "${escapeSequence:4:1}"
                AdjustMousePos UInput[3] "${escapeSequence:5:1}"
                AdjustMousePos UInput[4] "${escapeSequence:6:1}"
                AdjustMousePos UInput[5] "${escapeSequence:7:1}"
                AdjustMousePos UInput[6] "${escapeSequence:8:1}"
                ;;
              ${CSI}M*) 
                GetMouseButton UInput[0] "${escapeSequence:3:1}"
                if [ -n "${UInput[0]}" ]; then 
                  AdjustMousePos UInput[1] "${escapeSequence:4:1}"
                  AdjustMousePos UInput[2] "${escapeSequence:5:1}"
                else
                  UInput[0]=$(printf 'Mouse-\\x%02x %q'  "'${escapeSequence:3:1}" "${escapeSequence:4}")
                fi
                ;;
              ${CSI}[0-9]*[ABCDEFHIOZPQRSz~])
                local CSI_Params=( ${escapeSequence//[!0-9]/ } )
                local CSI_Func="${escapeSequence:${#escapeSequence}-1}"
                case "${CSI_Func}" in
                  z) # Sun Function Keys
                    UInput[0]="${SunKeybFntKeys[${CSI_Params[0]}]-}"
                    if [ -n "${UInput[0]}" ]; then
                      [ ${#CSI_Params[@]} -le 1 ] ||  UInput[0]="${KeyModifiers[${CSI_Params[1]}]}-${UInput[0]}"
                    else
                      UInput[0]="CSI ${CSI_Params[*]} ${CSI_Func}"
                    fi
                    ;;
                  '~') # Function Keys
                    UInput[0]="${KeybFntKeys[${CSI_Params[0]}]-}"
                    if [ -n "${UInput[0]}" ]; then
                      [ ${#CSI_Params[@]} -le 1 ] ||  UInput[0]="${KeyModifiers[${CSI_Params[1]}]}-${UInput[0]}"
                    else
                      UInput[0]="CSI ${CSI_Params[*]} ${CSI_Func}"
                    fi
                    ;;
                  A|B|C|D|E|F|H|I|O|Z|P|Q|R|S)
                    ord.eascii CSI_Func "${CSI_Func}"
                    UInput[0]="${KeybFntKeysAlt[${CSI_Func}]}"
                    if [ -n "${UInput[0]}" ]; then
                      [ ${#CSI_Params[@]} -le 1 ] ||  UInput[0]="${KeyModifiers[${CSI_Params[1]}]}-${UInput[0]}"
                    else
                      UInput[0]="CSI ${CSI_Params[*]} ${CSI_Func}"
                    fi
                    ;;
                  *)
                    UInput[0]="CSI ${CSI_Params[*]} ${CSI_Func}"
                    ;;
                esac
                ;;
              ${SS3}*[ABCDEFHPQRSIO~])
                local SS3_Params=( ${escapeSequence//[!0-9]/ } )
                local SS3_Func="${escapeSequence:${#escapeSequence}-1}"
                case "${SS3_Func}" in
                  A|B|C|D|E|F|H|P|Q|R|S|~)
                    ord.eascii SS3_Func "${SS3_Func}"
                    UInput[0]="${KeybFntKeysAlt[${SS3_Func}]-}"
                    if [ -n "${UInput[0]}" ]; then
                      [ ${#SS3_Params[@]} -lt 1 ] ||  UInput[0]="${KeyModifiers[${SS3_Params[0]}]}-${UInput[0]}"
                    else
                      UInput[0]="SS3 ${SS3_Params[*]-} ${SS3_Func}"
                    fi
                    ;;
                  *)
                    UInput[0]="SS3 ${SS3_Params[*]-} ${SS3_Func}"
                    ;;
                esac
                ;;
              $'\e'[[:cntrl:]])
                ord.eascii UInput[0] "${escapeSequence:1:1}"
                UInput[0]="${C1CtrlCharsAlt[${UInput[0]}]:-}"
                [ -n "${UInput[0]:-}" ] ||  UInput[0]="$(printf "%q" "${escapeSequence}")"
                ;;
              $'\e') UInput[0]="ESC" ;;
              *)
                UInput[0]="$(printf "%q" "${escapeSequence}")"
                ;;
          esac
          ;;
        *)
          ord.eascii UInput[0] "${escapeSequence}"
          UInput[0]="${C0CtrlChars[${UInput[0]}]:-}"
          [ -n "${UInput[0]:-}" ] ||  UInput[0]="$(printf '%q' "'${escapeSequence}")"
          ;;
      esac
    fi
    echo -n "${mouse_off}"
  }
  function HandleKey {
    local -a UInput
    while true; do
      if ReadKey ; then
        case "${UInput[0]:-}" in
          CR|NULL|LF|q)
            echo "\"${UInput[*]-}\""
            break
            ;;
          *)
            echo "\"${UInput[*]-}\""
            ;;
        esac
      fi
    done
  }
HandleKey


dethrophes 02-15-2012 11:15 AM

I moved this to http://mywiki.wooledge.org/ReadingFunctionKeysInBash
Also added a proper bash implemented vt100 parser example.


All times are GMT -5. The time now is 11:28 AM.