Reading characters from STDIN

Started by pjot, December 01, 2004, 05:22:13 AM

Previous topic - Next topic

pjot

Hi,



In my current program I try to read a character from the input prompt:



(set 'tmp (read-char 0))


This works, however, I need to press the <enter>-key in order to continue the program. So, if I send a message to the console like "Do you want to continue (Y/N)", and the user presses "Y", he also have to press <enter> after that to continue.



Actually I want *just* to press "Y" after which program continues. How can I do that in newLisp?



Peter

Lutz

#1
Norman has an example on his site how to use the ncurses library to do this:



http://www.nodep.nl/downloads/newlisp/ncurses.lsp">http://www.nodep.nl/downloads/newlisp/ncurses.lsp



On Win32 MinGW has a getch(), which you could import somehow.



Whe you are done writing the newMACS editor, let us know :)



Lutz

Lutz

#2
here is a solution for making a library with MinGW on Win32.

The 'C' file:



/* getchar.c - library getchar.dll to get character from keyboard */

#include <stdio.h>
#include <conio.h>

int GetChar(void)
{
return(getch());
}


The 'getchar.def' file:



LIBRARY    getchar.dll

EXPORTS
    GetChar         @1 GetChar


The 'Makefile':



# makefile for getchar.dll for MinGW compiler
#

OBJS = getchar.o

CFLAGS = -Wall -pedantic -c -O3 -DMINGW

CC = c:/MinGW/bin/gcc
STRIP = c:/MinGW/bin/strip
WRAP = c:/MinGW/bin/dllwrap

VERSION = 0.0.2

default: $(OBJS)
$(WRAP) *.o --enable-stdcall-fixup --def getchar.def -o getchar.dll -lws2_32
$(STRIP) getchar.dll

.c.o:
$(CC) $(CFLAGS) $<

$(OBJS): getchar.c getchar.def Makefile


The just do:



(import "getchar.dll" "GetChar")



(GetChar)



Lutz

pjot

#3
Hmm... I thought of that (e.g. importing a C-function), but it is not possible within newLisp itself?



(Actually, I am not creating an editor but I was trying to create the smallest interpreter on earth using newLisp... really!)

Lutz

#4
I have not found a way to do this on Linux/UNIX using standard 'libc' calls (not curses !). If someone can show me how, I will put a keyboard function in the next release.



Lutz

pjot

#5
Isn't "int getchar(void)" part of the STDIO library? I can't remember; I will look into it tonight.

pjot

#6
Looking into my old personal sources I found this:



int kb_hit(void)
{
#ifdef WIN32
char c;
while(!kbhit()){};     //wait for user to press a key
return(int)getch();
#else       // Should work for most Unices
struct termios term, oterm;
int fd = 0;
int c = 0;

/* get the terminal settings */
tcgetattr(fd, &oterm);

/* get a copy of the settings, which we modify */
memcpy(&term, &oterm, sizeof(term));

/* put the terminal in non-canonical mode, any
reads timeout after 0.1 seconds or when a
single character is read */
term.c_lflag = term.c_lflag & (!ICANON);
term.c_cc[VMIN] = 0;
term.c_cc[VTIME] = 1;
tcsetattr(fd, TCSANOW, &term);

/* get input - timeout after 0.1 seconds or
when one character is read. If timed out
getchar() returns -1, otherwise it returns
the character */
c=getchar();

/* reset the terminal to original state */
tcsetattr(fd, TCSANOW, &oterm);

/* return character */
return c;
#endif
}


This code I ripped from a webpage which does not exist anymore... I have adjusted it a little bit to fit my needs at the time, but I think it is suitable for a generic GETCHAR, also on most unices. I have tested it only with Linux.

Lutz

#7
>>>  Isn't "int getchar(void)" part of the STDIO library?



Yes it is, but it sits in the functions until you hit <enter>, just like (read-char 0) does. 'C' getchar() is really a macro around the 'C' read(int handle ...) function newLISP is using.



Lutz

Lutz

#8
Thanks for 'C' code, I will experiment with this.



Lutz

pjot

#9
One addition: I see I have included <termios.h> to get this code working... I hope Solaris has this header file.

Lutz

#10
Have it working on Linux/Solaris/MinGW/CYGWIN/Win32-Borland, but cannot get it to work on BSD. Anybody out there who can help with BSD (I tried on freeBSD 4.7) ???



This is what I have so far on UNIX:



struct termios term, oterm;
int c = 0;

tcgetattr(0, &oterm);

memcpy(&term, &oterm, sizeof(term));

/* put the terminal in non-canonical mode, any
reads timeout after 0.1 seconds or when a
single character is read */
term.c_lflag &= ~(ICANON | ECHO);
term.c_cc[VMIN] = 0;
term.c_cc[VTIME] = 1;
tcsetattr(0, TCSANOW, &term);

while((c=getchar()) == -1);

/* reset the terminal to original state */
tcsetattr(0, TCSANOW, &oterm);


Lutz

pjot

#11
I just tested the code on OpenBSD 3.4 and it seems to work fine. Unfortunately I can not have a FreeBSD machine available...