Solved

kbhit(), ioctl() and all those nasty things.

Posted on 1998-02-20
7
384 Views
Last Modified: 2013-12-26
(Sorry for the long drawn out question...)
Does anyone know the best way to create an equivilant for the kbhit() function? (in the good ol' conio.h under DOS)
I am using BSDI3.1 with the latest vers of GCC and G++.

I have looked through all the previous questions under this topic and have found around 5 or 6 questions that are all relatively similar to what I need, and the answer given is always either to use curses and getch(), or use the esoteric ioctl function, etc...
Well, "curses" is just what I did when I tried to use curses... (and besides, I think it still WAITS for some kind of input, and Ive got some wacky things to do while its waiting for input...)
As far as the ioctl stuff goes, someone had answered with this little function for one of the questions:

>>#include <stdio.h>
>>#include <sys/types.h>
>>#include <sys/stat.h>
>>#include <sys/ioctl.h>
>>#include <unistd.h>
>>#include <fcntl.h>
>>
>>int getch()
>>{
>>struct sgttyb tty, tty_org;
>>char key;
>>int retval= EOF;
>>
>>ioctl(fileno(stdin), TIOCGETP, &tty_org);
>>tty = tty_org;
>>tty.sg_flags |= CRMOD;
>>tty.sg_flags &= ~ECHO;
>>tty.sg_flags &= ~XTABS;
>>
>>tty.sg_flags |= RAW;
>>ioctl(0, TIOCSETP, &tty);
>>fcntl(0, F_SETFL, O_NDELAY);
>>
>>if ((retval= read(0, &key, 1)) == 1)
>> retval= key;
>>
>>ioctl(fileno(stdin), TIOCSETP, &tty_org);
>>fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0)&~O_NDELAY);
>>
>>return retval;
>>}

Now, this may work with the Flinstone's compiler, but all of the include files that I have indicate that this code is outdated.
Now I HAVE actually tried to convert it (using termios instead of sgttyb, etc.) and this is what I came up with:
(Directly cut/pasted)

#include<stdio.h>
#include<sys/ioctl.h>
#include<termios.h>
#include<unistd.h>
#include<fcntl.h>

void main(void)
        {
        struct termios New, Old;
        int Value;
        char Key;

        ioctl(STDIN_FILENO, TIOCGETA, &Old);
        New = Old;
        New.c_cc[VMIN] = 0;
        New.c_cc[VTIME] = 0;
        ioctl(STDIN_FILENO, TIOCSETA, New);
        fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);

        while ((Value = read(STDIN_FILENO, &Key, 1)) < 1)
                {
                /* Do some wacky stuff here. */
                }

        printf("[%c]\n", Key);
        ioctl(STDIN_FILENO, TIOCSETA, Old);
        fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);

        printf("\n\n");
        }

Now this ALMOST works... It actually gets a char while doing some wacky stuff, but when the program finishes, my terminal is completely hosed (As if I didnt reset the old flags,etc. properly). It doesnt recognize any characters I type in at all. I have to disconnect completely and reconnect to the server...
I know Im just being an idiot, but if anyone can provide any clues at all, I will kiss the ground you walk on for the rest of my life! Thanks, in advance, and sorry for the long question.
0
Comment
Question by:starlink
  • 3
  • 3
7 Comments
 
LVL 84

Expert Comment

by:ozo
ID: 1296022
Don't you mean
 ioctl(STDIN_FILENO, TIOCSETA, &Old);
?
0
 
LVL 32

Accepted Solution

by:
jhance earned 100 total points
ID: 1296023
Here is the simplest way I know how to do it.  It uses the stty command so if it not in /bin, you should change the path.  If you want to do some other processing while waiting for the character, fork this routine off and set a flag when the character comes in:


#include <stdio.h>
#include <stdlib.h>

main()      
{
        int c;
        printf("Hit any character to continue\n");            
        system("/bin/stty cbreak");
        c = getchar();            
        system("/bin/stty -cbreak");
        printf("Thank you for typing %c.\n", c);
        exit(0);
}
0
 

Author Comment

by:starlink
ID: 1296024
I knew it! Thank you, ozo... I KNEW I was just being an idiot... That was the problem the whole time. Sheesh, I tried everything else BUT that. I guess now I know why I dont program for a living... ;)
I also had to add the line (For anyone else who is interested):

New.c_lflag &= ~ICANON;

after setting the VTIME and VMIN stuff. Now it works perfectly! Thank you very much ozo!
And thank you, too, jhance, but to be honest, I always thought system calls were a little sloppy. =P
But thanks for the quick response!
0
Active Directory Webinar

We all know we need to protect and secure our privileges, but where to start? Join Experts Exchange and ManageEngine on Tuesday, April 11, 2017 10:00 AM PDT to learn how to track and secure privileged users in Active Directory.

 
LVL 32

Expert Comment

by:jhance
ID: 1296025
I guess it depends on your definition of "best".
0
 

Author Comment

by:starlink
ID: 1296026
Well, that may be an _easier_ way to do it, but I dont want to have to rely on another program at all. And if my program is run on many different systems, I'd have to make sure that everyone knew what directory it had to be in, etc.... I dont know about you but I cant STAND when I get a program that is supposed to do a certain thing, and it tells me it needs 20 other different programs or other third party files, and those programs need a few other files each and on and on and on (I know stty is standard, but Im not using that as an example). I suppose I should stop complaining and just be glad it's all free! Hehe. ;>
0
 
LVL 32

Expert Comment

by:jhance
ID: 1296027
BTW, did you really mean to give ME the points for this question?  Based on your comments, ozo seems to have found the problem with your code as posted.
0
 

Author Comment

by:starlink
ID: 1296028
Actually, I wasnt too sure how to do that... Well, I'll definately have other questions... ;)
0

Featured Post

Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
CRON statement to run every 3 minutes except on Monday morning 12am to 2am 7 103
twoTwo  challenge 35 108
firstChar challenge 13 121
moto 4g phone enable finger print 4 28
Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …

830 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question