You are not logged in.

#1 2008-10-14 08:05:26

dav7
Member
From: Australia
Registered: 2008-02-08
Posts: 674

Getting a character's ASCII code in "native bash" - can it be done?

I've currently enjoyed exploring bash's more interesting capabilities, such as (mis?)using read to handle function keys, arrow keys, control-key combinations, etc, and I've now got it to work with X11 mouse reporting.

The thing is, X11 mouse reporting returns an ASCII character plus 32 to indicate the mouse position, so "!", ASCII code 33, means "1" when 32 is subtracted off. So when the mouse is at the top left of the terminal I'll get "!!" indicating 33, 33, or 1, 1.

This is all good and all, except I know no way to have bash internally "know" what a character's ASCII code is - I have to pipe it to "od", with "od -An -vtu1", which does work, but since I'm running od at every single mouse move the script lags up and uses 100% CPU on my system very, very easily.

So, is there any way I could make bash somehow "know" this information? I briefly thought of using an array mapping characters to numbers, but if you have a gigantic terminal (it's possible...) you might use 100MB or more RAM. hmm

Any thoughts/suggestions? neutral

-dav7

Last edited by dav7 (2008-10-14 08:06:09)


Windows was made for looking at success from a distance through a wall of oversimplicity. Linux removes the wall, so you can just walk up to success and make it your own.
--
Reinventing the wheel is fun. You get to redefine pi.

Offline

#2 2008-10-14 09:01:18

moljac024
Member
From: Serbia
Registered: 2008-01-29
Posts: 2,676

Re: Getting a character's ASCII code in "native bash" - can it be done?

Use a window manager that can return mouse co-ordinates on its own ? smile
FVWM comes to mind...


The day Microsoft makes a product that doesn't suck, is the day they make a vacuum cleaner.
--------------------------------------------------------------------------------------------------------------
But if they tell you that I've lost my mind, maybe it's not gone just a little hard to find...

Offline

#3 2008-10-14 11:45:33

dav7
Member
From: Australia
Registered: 2008-02-08
Posts: 674

Re: Getting a character's ASCII code in "native bash" - can it be done?

No no no no no. I'm not talking about X here, I'm talking about terminal emulators that run in X... and how the mouse position can be reported to terminal apps in realtime...


Windows was made for looking at success from a distance through a wall of oversimplicity. Linux removes the wall, so you can just walk up to success and make it your own.
--
Reinventing the wheel is fun. You get to redefine pi.

Offline

#4 2008-10-14 16:59:42

Dieter@be
Forum Fellow
From: Belgium
Registered: 2006-11-05
Posts: 2,001
Website

Re: Getting a character's ASCII code in "native bash" - can it be done?

I don't understand. ascii contains only 92 characters (int range 32-126), how can you reflect a screen more then 126 pixels wide?


< Daenyth> and he works prolifically
4 8 15 16 23 42

Offline

#5 2008-10-14 17:18:14

wuischke
Member
From: Suisse Romande
Registered: 2007-01-06
Posts: 630

Re: Getting a character's ASCII code in "native bash" - can it be done?

dav7: Could you post some example code? This is interesting.

Dieter@be: I assume we're talking about the character positions and not pixel positions, i.e. on a 80x25 terminal we have 80 horizontal and 25 vertical positions. At least this makes sense to me. wink

Offline

#6 2008-10-14 17:22:43

dav7
Member
From: Australia
Registered: 2008-02-08
Posts: 674

Re: Getting a character's ASCII code in "native bash" - can it be done?

Dieter@be:

I don't think that's actually possible. I did a bit of tinkering, and I think that the characters sail out of the ASCII range over and up to character 255 and then stop, but I'm not too sure. At any rate, a 100+ character wide terminal in a business-ey environment where this would likely be used just doesn't sound like a probable possibility to me, which is probably why mouse reporting was [accepted and allowed to be] designed the way it was.

wuischke:

Here you go. This is my actual mouse demo, the target script and the reason for this thread's existence, so don't forget, it will be slow. tongue

Also note that I did a few little things here and there to make it run on [Free]BSD so a friend could run it.

Comment out the "pos=($(echo -n "${input:7:1} ${input:9:1}" | od -An -vtu1))" line to disable the 'od' call. This will speed everything up by a marginal amount (but not overly marginal) at the loss of cursor position updates.

#!/bin/bash

export TERM=linux

echo -ne '\ec'

width=$(tput cols)
height=$(tput lines)

for ((x=0; $x < $width; x++)); do space="$space "; done
echo -ne '\e[37;44m'

echo -ne "$space"
echo -ne "$space"
echo -ne "$space"
echo -ne "$space"
echo -ne "$space"

echo -ne '\e[38m\e[2;3fPosition:       X: ----  Y: ----'
echo -ne '\e[3;3fButtons:     \e[3;19f\e[30;42m Up \e[3;24f Up \e[3;29f Up \e[3;34f ^ Scroll v \e[0;37;44m'
echo -ne '\e[4;3fInternal data:  b1: 0  b2: 0  b3: 0  mdown: 0  drag: 0  lift: 0:  scroll: 0'

echo -ne '\e[0m\n\n\e[s\e[?1003h'

c=0
overruns=0
overrun=0

stty -echo
stty intr ''
stty eof ^C

while true; do
    
    read -sn 1 data
    
    if [ "${data:0:1}" = "$(echo -e '\03')" ]; then
        
        echo -ne '\e[?1003l'
        stty intr ^C
        stty eof ^D
        stty echo
        echo -ne '\e[25h'
        exit
        
    elif [ "${data:0:1}" = "$(echo -e '\e')" ]; then
        
        input=
        c=0
        
    else
        
        echo -ne '\e[?25l'
        
        c=$((c+1))
        
        input="$input~$data"
        
        if [ $c -eq 5 ]; then
            
            c=0
            
            btn1=0; btn2=0; btn3=0; drag=0; lift=0; mousedown=0
            
            if [ "${input:7:1}" != "~" ]; then
                
                pos=($(echo -n "${input:7:1} ${input:9:1}" | od -An -vtu1))
                
                oldx=${pos[0]}
                oldy=${pos[2]}
                
            fi
            
            printf '\e[2;22f\e[37;44m%4d\e[0m' $oldx
            printf '\e[2;31f\e[37;44m%4d\e[0m' $oldy
            
            case ${input:5:1} in
                
                "~") btn1=1; mousedown=1 ;;
                
                "!") btn2=1; mousedown=1 ;;
                
                "\"") btn3=1; mousedown=1 ;;
                
                "@") btn1=1; drag=1 ;;
                
                "A") btn2=1; drag=1 ;;
                
                "B") btn3=1; drag=1 ;;
                
                "\`") scroll=1 ;;
                
                "a") scroll=2 ;;
                
                "#") lift=1 ;;
                
            esac
            
            if [ "$btn1" != "$btn1_old" ] || [ "$btn2" != "$btn3_old" ] || [ "$btn3" != "$btn3_old" ] || [ "$drag" != "$drag_old" ] || [ "$lift" != "$lift_old" ] || [ "$mousedown" != "$mousedown_old" ] || [ "$scroll" != "$scroll_old" ]; then
                
                if [ "$scroll" != "$scroll_old" ]; then
                    
                    if [ "$scroll" = "1" ]; then
                        
                        if [ "$scroll_old" = "2" ]; then
                            
                            echo -ne '\e[3;43f\e[30;42m v \e[0;37;44m'
                            
                        fi
                        
                        echo -ne '\e[3;34f\e[37;45m ^ \e[0;37;44m'
                        
                    elif [ "$scroll" = "2" ]; then
                        
                        if [ "$scroll_old" = "1" ]; then
                            
                            echo -ne '\e[3;34f\e[30;42m ^ \e[0;37;44m'
                            
                        fi
                        
                        echo -ne '\e[3;43f\e[37;45m v \e[0;37;44m'
                        
                    fi
                    
                    echo -ne '\e[37;44m\e[4;77f'$scroll'\e[0m'
                    
                elif [ "$btn1" != "$btn1_old" ] || [ "$btn2" != "$btn3_old" ] || [ "$btn3" != "$btn3_old" ]; then
                    
                    if [ "$scroll_old" = "2" ]; then
                        
                        echo -ne '\e[3;43f\e[30;42m v \e[0;37;44m'
                        
                    elif [ "$scroll_old" = "1" ]; then
                        
                        echo -ne '\e[3;34f\e[30;42m ^ \e[0;37;44m'
                        
                    fi
                    
                    echo -ne '\e[37;44m\e[4;77f0\e[0m'
                    
                fi
                
                if [ "$btn1" != "$btn1_old" ]; then
                    
                    if [ "$btn1" = "0" ]; then
                        
                        echo -ne '\e[3;19f\e[30;42m Up '
                        
                        
                    elif [ "$btn1" = "1" ]; then
                        
                        echo -ne '\e[3;19f\e[37;45mDown\e[0;37;44m';
                        
                    fi
                    
                    echo -ne '\e[37;44m\e[4;23f'$btn1'\e[0m'
                    
                fi
                
                if [ "$btn2" != "$btn2_old" ]; then
                    
                    if [ "$btn2" = "0" ]; then
                        
                        echo -ne '\e[3;24f\e[30;42m Up '
                        
                    elif [ "$btn2" = "1" ]; then
                        
                        echo -ne '\e[3;24f\e[37;45mDown\e[0;37;44m'
                        
                    fi
                    
                    echo -ne '\e[37;44m\e[4;30f'$btn2'\e[0m'
                    
                fi
                
                if [ "$btn3" != "$btn3_old" ]; then
                    
                    if [ "$btn3" = "0" ]; then
                        
                        echo -ne '\e[3;29f\e[30;42m Up '
                        
                    elif [ "$btn3" = "1" ]; then
                        
                        echo -ne '\e[3;29f\e[37;45mDown\e[0;37;44m'
                        
                    fi
                    
                    echo -ne '\e[37;44m\e[4;37f'$btn3'\e[0m'
                    
                fi
                
                if [ "$mousedown" != "$mousedown_old" ]; then
                    
                    echo -ne '\e[37;44m\e[4;47f'$mousedown'\e[0m'
                    
                fi
                
                if [ "$drag" != "$drag_old" ]; then
                    
                    echo -ne '\e[37;44m\e[4;56f'$drag'\e[0m'
                    
                    if [ "$btn1" = "1" ]; then
                        
                        echo -ne '\e[3;19f\e[37;45mDrag\e[0;37;44m';
                        
                    elif [ "$btn2" = "1" ]; then
                        
                        echo -ne '\e[3;24f\e[37;45mDrag\e[0;37;44m';
                        
                    elif [ "$btn3" = "1" ]; then
                        
                        echo -ne '\e[3;29f\e[37;45mDrag\e[0;37;44m';
                        
                    fi
                    
                fi
                
                if [ "$lift" != "$lift_old" ]; then
                    
                    echo -ne '\e[37;44m\e[4;65f'$lift'\e[0m'
                    
                fi
                
                btn1_old="$btn1"
                btn2_old="$btn2"
                btn3_old="$btn3"
                drag_old="$drag"
                lift_old="$lift"
                mousedown_old="$mousedown"
                scroll_old="$scroll"
                
            fi
            
            echo -e '\n\e[?25h\e[6;'$height'r\e[uRecieved Input: ^['${input:3:1}${input:5:1}${input:7:1}${input:9:1} | tr '~' '?'
            echo -ne '\e[s\e[0r\e['$height';1f'
            
            input=
            
        fi
        
    fi
    
done

-dav7

Last edited by dav7 (2008-10-14 17:48:25)


Windows was made for looking at success from a distance through a wall of oversimplicity. Linux removes the wall, so you can just walk up to success and make it your own.
--
Reinventing the wheel is fun. You get to redefine pi.

Offline

#7 2008-10-14 20:08:29

Profjim
Member
From: NYC
Registered: 2008-03-24
Posts: 658

Re: Getting a character's ASCII code in "native bash" - can it be done?

I may be wrong, but I don't think it's possible to convert from characters to their ASCII codes in pure Bash. You may find a way to do it that's faster than od, but I think one way or another, you'll have to start a separate process to do this. That's probably where most of your overhead is coming from.

Offline

#8 2008-10-14 20:21:01

Dieter@be
Forum Fellow
From: Belgium
Registered: 2006-11-05
Posts: 2,001
Website

Re: Getting a character's ASCII code in "native bash" - can it be done?

wuischke wrote:

Dieter@be: I assume we're talking about the character positions and not pixel positions, i.e. on a 80x25 terminal we have 80 horizontal and 25 vertical positions. At least this makes sense to me. wink

Of course.. /me feels silly tongue

But if we're talking about character positions, dav7 how do you come up with "100MB or more RAM" for an in-memory map? 92 characters, a key is a character, so that's 1 byte (even if your terminal uses unicode), and a key for the value (a number <=126), let's say that's another byte.
That would give 92*2=184 bytes.  OK I probably oversimplified/forgot some stuff, but still the memory usage should be negligable I think, or am I (again tongue) missing something?

I also highly recommend the channel #bash on freenode.  There are some real experts there.  I learned a lot from them (they have a great faq too: http://wooledge.org:8000/BashFAQ )


As a last resort here's another idea. Probably very tricky to implement though.. create 1 od process and keep it open.  Use named pipes or whatever to send stuff to it's stdin and read stdout accordingly, keeping the process open for all your calls.


< Daenyth> and he works prolifically
4 8 15 16 23 42

Offline

#9 2008-10-16 12:04:21

dav7
Member
From: Australia
Registered: 2008-02-08
Posts: 674

Re: Getting a character's ASCII code in "native bash" - can it be done?

Profjim: Yeah hmm

Dieter@be: Try opening an xterm or urxvt window, and get its memory usage. Then make it as big as your screen, and get its usage again. It takes a heap of memory because of all the character cells it has to remap tongue

Dieter@be wrote:

As a last resort here's another idea. Probably very tricky to implement though.. create 1 od process and keep it open.  Use named pipes or whatever to send stuff to it's stdin and read stdout accordingly, keeping the process open for all your calls.

I actually thought of that as my eyes moved from Profjim's to your post... hah.

-dav7


Windows was made for looking at success from a distance through a wall of oversimplicity. Linux removes the wall, so you can just walk up to success and make it your own.
--
Reinventing the wheel is fun. You get to redefine pi.

Offline

Board footer

Powered by FluxBB