1

我有这个 c++ 程序来接受用户名和密码(被屏蔽)并将它们与预设值进行比较。如果它们相同,则程序关闭,否则循环回到开头。
我在输入密码时遇到了一些困难,尤其是在模仿正常输入时。到目前为止,我已经设法放置了 Enter 和 Backspace 功能,但我似乎无法正确使用箭头键。
使用下面的代码,程序确实部分正确地工作,当然,当按下左键时,它会将光标向后移动两次。但在此过程中,它还会用“alpha”符号替换它所在的当前字母,用“K”替换前一个字母。(K 和相邻的字母符号似乎是我的编译器 dev c++ 与左箭头键关联的值)
此外,当我删除额外的“\ b”时,光标根本不会移动,并且还会用“K”替换前一个字母。我现在不知道该怎么办,所以我问你。提前致谢!

#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(); 
}  
4

1 回答 1

1

当您按下一个特殊键(如箭头键、deletehome等)时,两个字节将发送到您的程序。在这种特殊情况下,当您按下左键时,字节0xe00x4b被发送。第二个值对应KASCII 表中的字符,第一个值取决于使用的扩展 ASCII 表的版本(可以是α也可以à)。

您的问题是,在您的循环中,您首先检查是否按下了左键。如果是这种情况,您将输出流的光标向左移动两次(通过发送\bto std::cout)并继续正常执行程序,将您获得的字符和下一个字符(so0xe00x47)存储在parr数组中。从图形上看,发生了什么:

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

实际上,由于您的目标是打印星星而不是密码,所以当您按下左键时,您无需将光标移回控制台。实际上,要打印的字符数保持不变,并且由于您总是打印相同的字符,因此从控制台行末尾开始打印下一个字符将产生相同的结果。

但是,当按下左键时,您需要做的是移动索引以指示parr必须在数组中插入下一个输入字符的位置。

例如,让我们考虑以下两个序列:

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

无论您是否按下左键,都不会更改输出,但会更改索引。

于 2016-09-26T14:00:21.453 回答