Link to home
Start Free TrialLog in
Avatar of yahelb
yahelb

asked on

_getch kbhit in linux

i'm trying to make a little software in linux, which ask for password.

i want that each single character that pressed to output '*'.

Avatar of sunnycoder
sunnycoder
Flag of India image

getpass()
SOLUTION
Avatar of sunnycoder
sunnycoder
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of yahelb
yahelb

ASKER

Hi  sunnycoder:
1. getpass block the echo output &&  qoute: "This function is obsolete. Do not use it.".
2. there is nothing good for me in that link _getch is not ansi function.

3. i'm trying to avoid the curses library, but if there is no ather solution...

        maybe i should ask that diffrently.

i want to react for each single character that have been pressed.
you should not think about that as a password attempts (i just thout this would help).

Given your constraints I cannot think of anything but curses... the way I listed in my second post
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of yahelb

ASKER

explain:
this answers is not solve my problem i'm moving on to look how to do that the curses way.

so i gave points to you all.

g0rath was the closest to what i looking for, but the problem is that getchar only breaks on '\n'.


thanks/

You can break on any character that you want by changing these lines in main():

        while ((ch = getchar()) != '\n')
        {
                if (i > 127)
                        break;
                else
                        buf[i++] = ch;
        }

to:

while (1)
{
  ch == getchar();
  /*
      break on Carriage Return, Line Feed, ESC, or '*'.
      '*' is simply to demonstrate that you can break on any character(s) that you choose
  */
  if (ch == '\n' || ch == '\r' || ch == 27 || ch == '*' || ch > 127)
    break;
  buf[i++] = ch;
}


Kent
the getchar() is setup so that you can use any char, I gave code as example, you can modify it to whatever you need...the real meat of the issue was turning off the echo at the tty...everything else is up to you
well your line
ch == getchar();
should be
ch = getchar();

and your the last arg of your if()

ch > 127
should be
i > 127

there is only 128 bytes in that buffer, and with you logic you could have a buffer over run
it's > 127 since it's zero based counting.

Sorry g0rath,

I was trying to point out to the original poster that your solution could, in fact, break on any character the he chose.

It's certainly not the first time that my head and fingers were going in opposite directions.  ;)'


Kent
oh no problem, it just appeard that the poster was just cut and pasting code rather then attempting to modify.... :)
Avatar of yahelb

ASKER

maybe i just dont undestand you.

here is a source code.

#include <stdio.h>

int main(){

        char ch;

        puts("enter somthing: ");
        ch = getchar();

        printf("char is: %c", ch);
        return 0;
}

now what i am saying is that getchar() wont return until the user will press <enter>.

Kent: i pasted your code. it acts really wierd infinit loop.
         did you tested it ?


g0rath: i took your code and replaced the char '\n' with 'a' and it just dont work for me.
           its not stops at 'a'.
           it always stops at '\n'.

did you tested it ?


if you 2 tested the code and it works for you what can cause it not to work here ?


first all of this I/O is buffered and these functions work on NEWLINES, so it blocks until the char '\n' is sent, then the whole block is sent through this section, and it'll repeat until the buffer has been emptied.

You said this was for a password box, so on enter is usually what happens...if you want it to stop on the 'a' then you must go to unbuffered I/O...

So that getch never blocks and it aways goes throught he check.

If you want this, then the whole newline buffering doesn't work since the terminal is in raw mode rather then normal...then your at the mercy of the emulator your working with, etc....

basically at this point you're rewriting curses and should have been using it in the first place.

if you want to go down this route, you'll have to do this:

struct termios orig_term;
struct termios raw_term;

if (tcgetattr(0, &orig_term) != 0) return 1; //save terminal settings
if (tcsetattr(0, TCSANOW, &raw_term) != 0) return 1; //set to raw
fcntl(0, F_SETFL, O_NONBLOCK);

// do the old while loop
while (1)
{
        ch = getc(stdin);
        // in unbuffered mode 255 gets sent, and for sanity
        // 3 is equal to CTRL-C
        if (ch == 255 || ch == 3)
                continue;
        // maybe you'll recognize CR and LF, which my terminal
        // doesn't map correctly in raw mode
        if (ch == 'a' || ch == 13 || ch == 10)
                break;
        printf("(%c) (%d) (0x%x)\n", ch, ch, ch);
        if (!isalpha(ch))
                continue;
        if (i > 127)
                break;
        else
                buf[i++] = ch;
}

if (tcsetattr(0, TCSANOW, &orig_term) != 0) return 1; //restore

Now this will work as unbuffered I/O, but Enter no longer maps in my terminal, only CTRL-ENTER....

None of the answers here are 'C' Grade level since they are all far above the simple "Just use curses answer"
all of my code works and was tested except the Raw Terminal I/O code
Avatar of yahelb

ASKER

1. thanks you g0raph and Kent.
2. i will use the curses way. i just thout ANSI have a function that do that(apperenly not).
3. g0raph: when i gave you 'C' grade i did that cause none of the answers was helpful for me (in fact but the curses way nothing was new! ).
which means: "Avarage".

now i do think you and kent should get more then 'C' grade or more points.
Can I do that ?

thanks again
yahel.