У меня есть эта программа C ++, чтобы принять имя пользователя и пароль (который маскируется) и сравнить их с заданными значениями. Если они совпадают, программа закрывается, в противном случае она возвращается к началу.
У меня были некоторые трудности с вводом пароля, особенно при имитации обычного ввода. До сих пор мне удавалось использовать функциональность Enter и Backspace, но я просто не могу понять, как правильно использовать клавиши со стрелками.
С помощью приведенного ниже кода программа работает частично вправо, и, конечно, при нажатии левой клавиши курсор перемещается назад два раза. Но в процессе он также заменяет текущую букву, под которой он находится, символом «альфа», а предыдущую букву буквой «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();
}
Когда вы нажимаете специальный ключ (как клавиши со стрелками, удалять, Главная, …) два байта отправляются в вашу программу. В этом конкретном случае, когда вы нажимаете левую клавишу, байты 0xe0
а также 0x4b
посланы. Второе значение соответствует K
символ в таблице ASCII, и первый зависит от версии расширенной таблицы ASCII (может быть α
но также à
).
Ваша проблема в том, что в вашем цикле вы начинаете с проверки, нажата ли левая клавиша. Если это так, вы перемещаете назад курсор вашего выходного потока дважды влево (отправляя \b
в std::cout
), и вы продолжаете нормально выполнять свою программу, сохраняя полученный символ и следующие (так 0xe0
а также 0x47
) в вашем 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
Независимо от того, нажали вы левую клавишу или нет, вы не меняете выход, а меняете индекс.
Других решений пока нет …