1. About get_key() alternative

The last thread about TAB KEY, makes me think about.

get_key() has a problem long long time ago. On DOS and Linux allways was a good keyboard support. On Win32 there are problems to support some keystrokes. This was never solved and we simply accept it this way.

Source code from ed.ex at Eu 3.1 simply says that some keys (like Ctrl_Left and Ctrl_Rigth) are not supported on exwc interpreter. Is a very old bug that requires a solution.

Also is not nice that special characters codes are not the same on any OS.

Some people tried to fix it and caused the problem with TAB Key discussed on another thread.

My proposal is:

1- Left get_key() as is (as allways has been) to keep compatibility with old code. A text oriented function that return mainly printable characters but not full support for special keys.

2- Create a new alternative keyboard function that provide better keyboard information.

The main problem is that I want to receive the text information (including unicode or regional language characters) and the special keys like F1 in with the same function and be sure not confuse them. Check what other languages do. I inspired on QBASIC that return one byte for printable characters and two byte "0+Other" for special keys http://www.petesqbsite.com/phpBB3/viewtopic.php?t=1105. If your qbasic receives a "0" from keyboard you know that the next byte is an special key, not a printable.

We can explote the power of sequences. A keystroke of several keys like Ctrl+Alt+Insert may become a sequence {CTRL, ALT, INS}. So, if your program receives from the keyboard an atom, is a printable character, but if receives a sequence is an special key that your program can process or discart. We can create a simple table of special key values unified the same for any OS, and left the printable characters as presented by the OS and their locale.

Regards

Marco Achury

new topic     » topic index » view message » categorize

2. Re: About get_key() alternative

Sure. There should be no real need for this to be part of the core interpreter, or wait for the next release.

I started cobbling the following together from some existing phix innards, reworked to run on Eu, before realising
(a) I was quite, quite stumped as to how RDS Eu might invoke kernel calls on linux, and
(b) there is a far easier way (see below), but I got the windows (32-)bit working so here it is:

integer c_init = 0 
 
atom stdin, knl32, xAllocConsole, xGetStdHandle, xSetConsoleMode, stdin_redirected=0, 
                   xPeekConsoleInputA, xReadConsoleInputA, pBuffer, pBytes 
constant STD_INPUT_HANDLE = -10, 
         ENABLE_PROCESSED_INPUT = 1, 
         P = C_POINTER, 
         I = C_INT 
 
procedure init_console() 
    c_init = 1 
    if platform()=WINDOWS then 
        knl32 = open_dll("kernel32.dll") 
        xAllocConsole = define_c_proc(knl32,"AllocConsole",{}) 
        xGetStdHandle = define_c_func(knl32,"GetStdHandle",{P},P) 
        xSetConsoleMode = define_c_func(knl32,"SetConsoleMode",{P,I},I) 
        xPeekConsoleInputA = define_c_proc(knl32,"PeekConsoleInputA",{P,P,I,P}) 
        xReadConsoleInputA = define_c_proc(knl32,"ReadConsoleInputA",{P,P,I,P}) 
        pBuffer = allocate(20)  -- sizeof(INPUT_RECORD[/KEY_EVENT_RECORD]) 
        pBytes = allocate(8)    -- 4 or 8? (DWORD/) 
        c_proc(xAllocConsole,{}) 
        stdin = c_func(xGetStdHandle,{STD_INPUT_HANDLE}) 
        stdin_redirected = c_func(xSetConsoleMode,{stdin,ENABLE_PROCESSED_INPUT}) 
    else 
        pBuffer = allocate(40) -- termios struct (+ 4 bytes padding) 
        stdin = 0 
    end if 
end procedure 
 
global function getKey() 
-- 
-- drop-in replacement for the get_key() builtin 
-- 
    integer keyChar = -1 
    if not c_init then init_console() end if 
    if platform()=WINDOWS then 
        while true do 
            c_proc(xPeekConsoleInputA,{stdin,pBuffer,1,pBytes}) 
            if peek4s(pBytes)=0 then exit end if 
            c_proc(xReadConsoleInputA,{stdin,pBuffer,1,pBytes}) 
            if peek4s(pBuffer)=1            -- KEY_EVENT 
            and peek4s(pBuffer+4)=1 then    -- keyDown(ignore key up events) 
                keyChar = peek(pBuffer+14) 
                if keyChar!=0 then exit end if 
                keyChar = #100+peek(pBuffer+12) -- keyScan 
                if keyChar!=#12A            -- shift key 
                and keyChar!=#11D           -- ctrl key 
                and keyChar!=#138 then      -- alt key 
                    exit 
                end if 
            end if 
        end while 
    else -- LINUX 
        -- sys_ioctl(54/pBuffer/stdin/TCGETS(0x5401))... oh dear 
        -- poke4(pBuffer+12,and_bits(peek4s(pBuffer+12),#FFFFFFF5)) -- not(ICANON or ECHO)  ;turn off echo  
        -- poke(pBuffer+22,0)   -- VMIN                  ;turn off canonical mode  
        -- poke(pBuffer+23,0)   -- VTIME     ;we dont want to wait for keystrokes  
        -- sys_ioctl(54/pBuffer/stdin/TCSETS(0x5402))... oh dear 
        -- keyChar = sys_read(3/stdin/pBuffer/1).. oh dear 
        -- if keyChar=0 then keyChar=-1 end if 
        -- poke4(pBuffer+12,or_bits(peek4s(pBuffer+12),#0000000A)) -- (ICANON or ECHO)  ;turn on echo  
        -- poke(pBuffer+22,1)   -- VMIN                  ;turn on canonical mode  
        --? poke(pBuffer+23,1)  -- VTIME                 ;wait for keystrokes  
        -- sys_ioctl(54/pBuffer/stdin/TCSETS(0x5402))... oh dear 
    end if 
    return keyChar 
end function 

As promised, a far (far) easier way... (DOH)

global function getKey() 
-- 
-- drop-in replacement for the get_key() builtin 
-- 
    integer ch = get_key() 
    if platform()=WINDOWS then 
        if ch=1015936 then ch=9 end if 
    else -- linux 
--      if ch=??????? then ch=? end if 
    end if 
    return ch 
end function 

test either of the above with say

while true do 
    integer ch = getKey() 
    ?ch 
    if ch=#1B then exit end if  -- escape 
    sleep(0.1) 
end while 
new topic     » goto parent     » topic index » view message » categorize

3. Re: About get_key() alternative

Better, declare an override for get_key(), then you don't need to change the name;

----------------------------- 
override function get_key() 
-----------------------------  
-- drop-in replacement for the get_key() builtin   
    integer ch = get_key()  
    if platform()=WINDOWS then  
        if ch=1015936 then ch=9 end if  
    end if  
    return ch  
end function  

Which brings up a bug: override works fine when interpreted - but bound, shrouded or compiled, you get memory allocation errors and eventually lock up when you run out of memory.

new topic     » goto parent     » topic index » view message » categorize

4. Re: About get_key() alternative

achury said...

The last thread about TAB KEY, makes me think about.

get_key() has a problem long long time ago. On DOS and Linux allways was a good keyboard support. On Win32 there are problems to support some keystrokes. This was never solved and we simply accept it this way.

Source code from ed.ex at Eu 3.1 simply says that some keys (like Ctrl_Left and Ctrl_Rigth) are not supported on exwc interpreter. Is a very old bug that requires a solution.

Also is not nice that special characters codes are not the same on any OS.

Some people tried to fix it and caused the problem with TAB Key discussed on another thread.

But there is also a solution provided for the new TAB Key problem, that I just mentioned in the other thread, https://openeuphoria.org/forum/m/135135.wc

achury said...

My proposal is:

1- Left get_key() as is (as allways has been) to keep compatibility with old code. A text oriented function that return mainly printable characters but not full support for special keys.

The view of the dev team back when the fix was put in was that console support and interaction was a vital subsystem of Euphoria on all platforms.

To this end, we saw a difference between getc(0)/gets(0) on one side and get_key()/wait_key() on the other.

getc(0) et all fit the " text oriented function that return mainly printable characters but not full support for special keys" function.

achury said...

2- Create a new alternative keyboard function that provide better keyboard information.

The view of the dev team back then was that get_key() et all was the function that was the "alternative keyboard function that provide better keyboard information" and since these already existed, there wasn't a need to provide new ones.

achury said...

The main problem is that I want to receive the text information (including unicode or regional language characters) and the special keys like F1 in with the same function and be sure not confuse them.

get_key() already supports this, just in some cases you'll need to call console:key_codes() to make sure that some keys return the value that you expect (you can force Tab to be 9, and the numeric keypad to return the same values as their non-keypad counterparts, for example).

achury said...

Check what other languages do. I inspired on QBASIC that return one byte for printable characters and two byte "0+Other" for special keys http://www.petesqbsite.com/phpBB3/viewtopic.php?t=1105. If your qbasic receives a "0" from keyboard you know that the next byte is an special key, not a printable.

We can explote the power of sequences. A keystroke of several keys like Ctrl+Alt+Insert may become a sequence {CTRL, ALT, INS}. So, if your program receives from the keyboard an atom, is a printable character, but if receives a sequence is an special key that your program can process or discart. We can create a simple table of special key values unified the same for any OS, and left the printable characters as presented by the OS and their locale.

Regards

Marco Achury

This is an excellent idea. The current key_codes() implementation requires that replacement key codes be integers, but updating it to support returning a sequence of keys for a special key would actually make it more in-line with the nix world of things (where we can get multi-character escape sequences for certain special keys based on termcap/terminfo settings).

In fact, with your suggestion implemented, we could easily set up the key codes to be the Linux/GNU xterm termcap escape sequences! Same escape codes, multiple platforms.

I'm really liking this idea.

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu