Reading keyboard input

Started by IVShilov, October 22, 2023, 07:29:32 AM

Previous topic - Next topic

IVShilov

Hi.
[windows 10, newLISP v.10.7.5 64-bit on Windows IPv4/6 UTF-8 libffi]

Found, that non-blocking mode (read-key true) cannot get F1-F12 keycodes because return 0 when nothing pressed, when, for example, F1 key is (0 59):
> (read-key) (read-key)
0
59
- first call returns 0, second call returns 59. 

Under the hood read-key use kbhit() and getch():

/* thanks to Peter van Eerten for contributing this function */
/* included non-blocking ability 10.7.3, LM */

CELL * p_readKey(CELL * params)
{

#if defined(WINDOWS) || defined(OS2)
if(!isNil(evaluateExpression(params)) )
{
if(kbhit())
return(stuffInteger(getch()));
else
[b][u]return(stuffInteger(0));[/u][/b]
}
else
return(stuffInteger(getch()));
#else
...
 /* not Windows or OS2 */
}

As I understand in this place
 return(stuffInteger(0));
(read-key true) returns 0 when nothing has pressed.
I think it must returns nil in this case .

The questions:
1) Is it right place to change behavior and nil is right solution?
2) How to do it right, which C-code must be there and how to rebuild sources?

IVShilov

Also, UTF8 letter crash newlisp capturing keypress in non-blocking mode :

(while (!= 3 (print (read-key true))) (print ":" (read-key true) "|"))
0:0|0:0| ...
after input "ё" newlisp stuck and cmd window close.

cameyo

This works for me:

(define (keys)
  (local (k)
    (while (!= (setq k (read-key)) 13)
      (setq s (string k))
      (println s))))

(keys)
;-> 1   ; Ctrl-A
;-> 111 ; O
;-> 79  ; o
;-> 0
;-> 59  ; F1
;-> 0
;-> 60  ; F2
;-> 224
;-> 81  ; PageUp
;-> 224
;-> 72  ; Up
;-> 224
;-> 77  ; Right
;-> 224
;-> 80  ; Down
;-> 224
;-> 75  ; Left

IVShilov

#3
Yes, everything is fine with blocking form of read-key: it catch F1, UTF8 two-byte codes, and even CTRL-C (!) returs code 3.

Problems in non-blocking reading:
1) F1 (code 0 59) because 0 is default result of (read-key true) means "no key pressed", and IMHO it must return nil;
2) UTF8 non-onebyte char - leads to infinite loop and crash.
This two problems block for me creating enhanced REPL.
PS Does someone knew how to catch win32 keyboard events  like key-press|key-release ?
I have weak skills in FFI


cameyo

Sorry, I can't help you.
But what do you mean by "enhanced REPL"?
I use Notepad++ connected to a REPL via Autohotkey script.
Far more powerful than only REPL.
Thanks.

IVShilov

AutoHotKey? Can't even imagine this.

Enchanced REPL is like a emacs/readline but for one string:
 - autocompletion by TAB:
     - functions using (filter lambda? (symbols)) 
     - args using (type) and function definitions
 - swapping two elements in line by C-t|C-M-t
 - highlight substrings using xterm esc-sequences and ConEmu's interface
and so on.
For example, look at ipython.

IVShilov

#6
Another bug on this way: timer and read-key can't used together
(setq c nil interval 0,001)
(define (output)
    (if c
        (begin
          (print (char c))
          (setq c nil)
          ))
    (timer 'output interval)
    )
(output)
In console:
      > (setq c 100)
      100
      > d

      > (setq c (read-key))
      13
      0 > ## a context "0" ???

      0 > (context)
      MAIN
      >

IVShilov

Found solutions.

Quote1) F1 (code 0 59) because 0 is default result of (read-key true) means "no key pressed", and IMHO it must return nil;
2) UTF8 non-onebyte char - leads to infinite loop and crash.
This two problems block for me creating enhanced REPL.

Explanation of problem:
(import "msvcrt.dll" "_getch")
(import "msvcrt.dll" "_kbhit")
(exec "chcp 65001")
(setq n 0)
(while (< n 7)
    (if (= 1 (setq k (_kbhit) ))
(println (++ n) ":" k ":" (_getch) ":" (_kbhit))
(setq n 0)
)
    )
  )
1:1:13:0   <----------- ENTER, one catch, code 13, and kbhit returns 0
1:1:224:1  <----------- press UP: two codes: 224 and next 72
2:1:72:0
1:1:0:1    <----------- press F1: two codes: first 0, kbhit still returns 1
2:1:59:0   <-------------------------------- second: 59, after that kbhit returns 0
1:1:145:1  <----------- enter "ё": first code 209 was disappear, getch return second: 145
2:1:145:1  <----------- AND kbhit still returns 1:
3:1:145:1
4:1:145:1
5:1:145:1
6:1:145:1
7:1:145:1
1
> ё        <----------- and ё somehow printed by default newlisp REPL
Solutions is:
1) for catch F1-F12: import kbhit and check if key was pressed;
2) UTF8 in cmd.exe: DO NOT (exec "chcp 65001"), because it enable UTF8 input AND output.
It's hard to even imagine keyboard with button for every char in UTF8 set, so it will be quite enough to enable UTF8-output only:
(import "kernel32.dll" "SetConsoleOutputCP")
(import "kernel32.dll" "GetConsoleOutputCP")
> (SetConsoleOutputCP 866) (GetConsoleOutputCP) (char 937)
1
866
"╬й"          <----------- FAIL
> (SetConsoleOutputCP 65001) (GetConsoleOutputCP) (char 937)
1
65001
"Ω"           <----------- SUCCESS
> (import "kernel32.dll" "GetConsoleCP")
GetConsoleCP@CB3855F0
> (GetConsoleCP)
866           <----------- this is INPUT codepage
> (GetConsoleOutputCP)
65001         <----------- this is OUTPUT codepage
>
More info here
Complete solution is in use "Win32 Console API".