1. About get_key() alternative
- Posted by achury Oct 17, 2020
- 892 views
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
2. Re: About get_key() alternative
- Posted by petelomax Oct 17, 2020
- 867 views
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
3. Re: About get_key() alternative
- Posted by irv Oct 17, 2020
- 872 views
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.
4. Re: About get_key() alternative
- Posted by jimcbrown (admin) Oct 19, 2020
- 988 views
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
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.
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.
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).
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.