c++passwordscursordev-c++getasync

Cursor movement in password input c++\


I have this c++ program to accept the username and the password(which is masked) and compare them to preset values. If they are same, the program closes, otherwise it loops back to the beginning.
I have had some difficulty with the password input, especially in mimicking a normal input. So far I have managed to put the Enter and Backspace functionality, but I just cant seem to get the arrow keys right.
With the code below, the program does work partly right, and of course, it moves the cursor back two times when the left key is pressed. But in the process, it also replaces the current letter under which it is with the 'alpha' symbol and the previous letter with 'K'. (K and the alpha symbol next to each other seems to be the value which my compiler, dev c++ associates with the left arrow key)
Also, when I remove the extra '\b', the cursor just doesnt move at all, and also replaces the previous letter with 'K'. I don't know what to do now, so I ask you. Thanks in advance!

#include <stdlib.h>
#include <conio.h>
#include <iostream.h>
#include <windows.h>

using namespace std;
int main()
{
  int i=0;string u;char parr[i+1],ch;

  while (1)
  { 
    system("cls");
    cout<<"Enter username."<<endl;
    cin>>u;

    system("cls");
    cout<<"Enter password."<<endl;
    i=0;

    while (1)
    {
      ch=getch();
      if (ch=='\r') break;

      if (GetAsyncKeyState(VK_LEFT)) cout<<'\b'<<'\b';

      if (ch=='\b')
      {
        cout<<'\b';
        while (i!=0) {--i;}
        ch='\0';
        parr[i]='\0';
        cout<<' '<<'\b';
        continue;
      }

      parr[i]=ch;
      ch='*';
      cout<<ch;
      ++i;
    }

    parr[i]='\0';
    string p="password";

    if (u=="username" && parr==p)
    {
      system("cls");
      cout<<"Welcome!";
      break;
    }
    else
    {
      system("cls");
      cout<<"Username and password entered does not match! Please try again.";
    }

    getch();
  }

  getch(); 
}  

Solution

  • When you press a special key (like the arrow keys, delete, home, ...) two bytes are sent to your program. In this particular case, when you press the left key, the bytes 0xe0 and 0x4b are sent. The second value correspond to the K character in the ASCII table and the first one depends on the version of the extended ASCII table is used (it can be α but also à).

    Your problem is that, in your loop, you start by checking if the left key is pressed. If it's the case, you move back the cursor of your output stream twice to the left (by sending \b to std::cout) and you keep executing your program normally, storing the character you got and the next ones (so 0xe0 and 0x47) in your parr array. Graphically, here is what happens :

    Action      BYTE SENT           parr              Comment
    PRESS a          0x61           > a
    PRESS b          0x62           > ab
    PRESS LEFT  0xe0 0x4b           > abα             The first update of parr (0xe0)
                                    > αbαK            You enter directly in the loop
                                                      because there is another byte (0x4b)
                                                      waiting in the input stream
    PRESS c          0x63           > αbαKc
    

    Actually, as your goal is to print stars instead of the password, when you press the left key, you don't need to move the cursor back in the console. Indeed, the number of characters to print remains the same and, as you always print the same character, printing the next starting at the end of your console line will produce the same result.

    However, what you have to do when the left key is pressed, is to move an index to indicate where in your parr array the next entered characters must be inserted.

    Let's consider, for example the two following sequences:

    Pressing       Will display    parr     Pointer to the position
                                            where to insert the new char
                                            0
    a              *               a        1
    b              **              b        2
    c              ***             abc      3
    
                                            0
    a              *               a        1
    LEFT           *               a        0
    b              **              ba       1
    LEFT           **              ba       0
    c              ***             cba      1
    

    Whether you pressed the left key or not do not change the output but do change the index.