🎨 fix a bug in module/keyboard.cpp that if program exited with an error, the terminal may not echo the text you input

This commit is contained in:
ValKmjolnir 2022-05-20 21:42:28 +08:00
parent 07eeaadf96
commit dcad554eba
5 changed files with 74 additions and 103 deletions

View File

@ -7,68 +7,77 @@
#include <termios.h>
#endif
class noecho_input{
private:
#ifndef _WIN32
static struct termios init_termios;
static struct termios new_termios;
static int peek_char=-1;
int kbhit(){
unsigned char ch=0;
int nread=0;
if(peek_char!=-1)
return 1;
int flag=fcntl(0,F_GETFL);
fcntl(0,F_SETFL,flag|O_NONBLOCK);
nread=read(0,&ch,1);
fcntl(0,F_SETFL,flag);
if(nread==1){
peek_char=ch;
return 1;
}
return 0;
}
int getch(){
int ch=0;
if(peek_char!=-1){
ch=peek_char;
peek_char=-1;
return ch;
}
read(0,&ch,1);
return ch;
}
struct termios init_termios;
struct termios new_termios;
int peek_char=-1;
#endif
public:
noecho_input(){
#ifndef _WIN32
tcflush(0,TCIOFLUSH);
tcgetattr(0,&init_termios);
new_termios=init_termios;
new_termios.c_lflag&=~(ICANON|ECHO|ECHONL|ECHOE);
// vmin=0 is nonblock input, but in wsl there is a bug that will block input
// so we use fcntl to write the nonblock input
new_termios.c_cc[VMIN]=1;
new_termios.c_cc[VTIME]=0;
tcsetattr(0,TCSANOW,&new_termios);
#endif
}
~noecho_input(){
#ifndef _WIN32
tcflush(0,TCIOFLUSH);
tcsetattr(0,TCSANOW,&init_termios);
#endif
}
int noecho_kbhit(){
#ifndef _WIN32
unsigned char ch=0;
int nread=0;
if(peek_char!=-1)
return 1;
int flag=fcntl(0,F_GETFL);
fcntl(0,F_SETFL,flag|O_NONBLOCK);
nread=read(0,&ch,1);
fcntl(0,F_SETFL,flag);
if(nread==1){
peek_char=ch;
return 1;
}
return 0;
#else
return kbhit();
#endif
}
int noecho_getch(){
#ifndef _WIN32
int ch=0;
if(peek_char!=-1){
ch=peek_char;
peek_char=-1;
return ch;
}
read(0,&ch,1);
return ch;
#else
return getch();
#endif
}
};
noecho_input this_window;
extern "C" nasal_ref nas_getch(std::vector<nasal_ref>& args,nasal_gc& gc){
return {vm_num,(double)getch()};
return {vm_num,(double)this_window.noecho_getch()};
}
extern "C" nasal_ref nas_kbhit(std::vector<nasal_ref>& args,nasal_gc& gc){
return {vm_num,(double)kbhit()};
return {vm_num,(double)this_window.noecho_kbhit()};
}
extern "C" nasal_ref nas_noblock(std::vector<nasal_ref>& args,nasal_gc& gc){
if(kbhit())
return {vm_num,(double)getch()};
return nil;
}
extern "C" nasal_ref nas_init(std::vector<nasal_ref>& args,nasal_gc& gc){
#ifndef _WIN32
tcflush(0,TCIOFLUSH);
tcgetattr(0,&init_termios);
new_termios=init_termios;
new_termios.c_lflag&=~(ICANON|ECHO|ECHONL|ECHOE);
// vmin=0 is nonblock input, but in wsl there is a bug that will block input
// so we use fcntl to write the nonblock input
new_termios.c_cc[VMIN]=1;
new_termios.c_cc[VTIME]=0;
tcsetattr(0,TCSANOW,&new_termios);
#endif
return nil;
}
extern "C" nasal_ref nas_close(std::vector<nasal_ref>& args,nasal_gc& gc){
#ifndef _WIN32
tcflush(0,TCIOFLUSH);
tcsetattr(0,TCSANOW,&init_termios);
#endif
if(this_window.noecho_kbhit())
return {vm_num,(double)this_window.noecho_getch()};
return nil;
}

View File

@ -1,5 +1,3 @@
import("lib.nas");
var libfib=func(){
var dl=dylib.dlopen("./module/libfib."~(os.platform()=="windows"?"dll":"so"));
var fib=dylib.dlsym(dl,"fib");

View File

@ -1,47 +1,12 @@
import("lib.nas");
var libkey=func(){
var lib=dylib.dlopen("./module/libkey"~(os.platform()=="windows"?".dll":".so"));
var kb=dylib.dlsym(lib,"nas_kbhit");
var gt=dylib.dlsym(lib,"nas_getch");
var nb=dylib.dlsym(lib,"nas_noblock");
var init=dylib.dlsym(lib,"nas_init");
var cls=dylib.dlsym(lib,"nas_close");
var call=dylib.dlcall;
var is_init=0;
return {
init:func(){
# change io mode to no echo
call(init);
is_init=1;
},
kbhit:func(){
# check if kerboard is hit
# if keyboard is hit this function will return 1
# until getch() gets all the input characters
# and the input flow becomes empty
if(!is_init)
me.init();
return call(kb);
},
getch:func(){
# get input one character without echo
# block until get one input
if(!is_init)
me.init();
return call(gt);
},
nonblock:func(){
# nonblock input without echo
if(!is_init)
me.init();
return call(nb);
},
close:func(){
# must call this function before exiting the program
# this will change terminal mode to normal io mode
call(cls);
dylib.dlclose(lib);
}
kbhit:func(){return call(kb);},
getch:func(){return call(gt);},
nonblock:func(){return call(nb);}
}
}();

View File

@ -178,7 +178,7 @@ var main=func(){
if(os.platform()=="windows")
system("chcp 65001");
print("\ec");
libkey.init();
var g=game(15,10);
g.print();
print("\rpress any key to start...");
@ -207,10 +207,10 @@ var main=func(){
g.print();
}
}
libkey.close();
println(g.gameover()<=1?"game over.":"you win!");
println("enter anything to quit.");
input();
println("press 'q' to quit.");
while(libkey.getch()!='q'[0]);
}
main();

View File

@ -275,7 +275,6 @@ var main=func(){
if(os.platform()=="windows")
system("chcp 65001");
libkey.init();
print(
"\ec\e[1:1H",
"╔═════════════════════════╗\n",
@ -331,7 +330,7 @@ var main=func(){
unix.sleep(0.02);
counter-=1;
}
libkey.close();
print(
map.gameover()?
"\e[31mg\e[32ma\e[33mm\e[34me \e[35mo\e[36mv\e[94me\e[31mr \e[32m~\e[0m\n":
@ -339,10 +338,10 @@ var main=func(){
);
print(
"\e[31me\e[32mn\e[33mt\e[34me\e[35mr ",
"\e[36ma\e[94mn\e[95my\e[96mt\e[31mh\e[32mi\e[33mn\e[34mg ",
"\e[36m'\e[94mq\e[95m' ",
"\e[35mt\e[36mo \e[94mq\e[95mu\e[91mi\e[92mt\e[0m\n"
);
input();
while(libkey.getch()!='q'[0]);
};
main();