Yoni,你有两个很好的答案,但为了完整起见,我将在 cmets 中提供你有问题的其余信息。
首先,在接受您想要显示的任何输入并允许最少的用户编辑时,您需要将您的键盘置于非规范模式,以便您的程序可以使用每个按键作为键已键入 -- 无需等待用户按 Enter。您可以使用tcgetattr(终端获取属性)和tcsetattr(终端设置属性)来处理这个问题。 *非规范模式是 windows getch() 提供的。
基本上,您将读取循环设置为使用getchar 或fgetc 读取(如果您希望能够从stdin 或文件中读取值。)您可以通过以下方式控制读取循环:
#define MAXPW 32 /* constant for max input length */
int main (int argc, char **argv) {
int c,
idx = 0; /* buf index */
char pw[MAXPW] = "", /* buf for passwd */
mask = argc > 1 ? *argv[1] : 0; /* mask off by default */
FILE *fp = stdin;
...
/* read chars from fp, mask w/mask char */
while ((idx + 1 < MAXPW && (c = fgetc (fp)) != '\n' && c != EOF) ||
(idx == MAXPW - 1 && c == 127))
{
请注意,当 (1) (space_remains AND c 不是 '\n' 或 @ 987654330@) OR (2) (space_remains AND backspace_key_pressed)
即使您处理这两种情况 (1) 是否是普通字符 - 添加它;或 (2) 是退格字符,然后备份,用space 覆盖字符并再次备份,例如
if (c != 127) { /* not the backspace characters */
if (' ' - 1 < mask && mask < 127) /* if mask valid ASCII */
fputc (mask, stdout); /* output mask char */
else
fputc (c, stdout); /* output normal char */
pw[idx++] = c; /* store char, adv index */
}
else if (idx > 0) { /* handle backspace (del) */
fputc (0x8, stdout); /* backup */
fputc (' ', stdout); /* overwrite with space */
fputc (0x8, stdout); /* backup again */
pw[--idx] = 0; /* nul-termiante after current */
}
注意:如果您的mask 字符是可打印字符,则输出mask 字符,例如
enter passwd: ********
如果桅杆不可打印(默认为nul),则输出文本。您可以将掩码字符设置为程序的第一个参数(用引号括起来),例如
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <termios.h>
#include <errno.h> /* for errno */
#include <unistd.h> /* for EINTR */
#define MAXPW 32 /* constant for max input length */
int main (int argc, char **argv) {
int c,
idx = 0; /* buf index */
char pw[MAXPW] = "", /* buf for passwd */
mask = argc > 1 ? *argv[1] : 0; /* mask off by default */
FILE *fp = stdin;
struct termios old_kbd_mode; /* orig keyboard settings */
struct termios new_kbd_mode;
if (tcgetattr (0, &old_kbd_mode)) { /* save orig settings */
fprintf (stderr, "%s() error: tcgetattr failed.\n", __func__);
return -1;
} /* copy old to new */
memcpy (&new_kbd_mode, &old_kbd_mode, sizeof(struct termios));
/* put keyboard in non-canonical/no echo mode */
new_kbd_mode.c_lflag &= ~(ICANON | ECHO); /* new kbd flags */
new_kbd_mode.c_cc[VTIME] = 0;
new_kbd_mode.c_cc[VMIN] = 1;
if (tcsetattr (0, TCSANOW, &new_kbd_mode)) {
fputs ("error: tcsetattr failed.\n", stderr);
return -1;
}
fputs ("enter passwd : ", stdout); /* set passwd prompt */
/* read chars from fp, mask w/mask char */
while ((idx + 1 < MAXPW && (c = fgetc (fp)) != '\n' && c != EOF) ||
(idx == MAXPW - 1 && c == 127))
{
if (c != 127) { /* not the backspace characters */
if (' ' - 1 < mask && mask < 127) /* if mask valid ASCII */
fputc (mask, stdout); /* output mask char */
else
fputc (c, stdout); /* output normal char */
pw[idx++] = c; /* store char, adv index */
}
else if (idx > 0) { /* handle backspace (del) */
fputc (0x8, stdout); /* backup */
fputc (' ', stdout); /* overwrite with space */
fputc (0x8, stdout); /* backup again */
pw[--idx] = 0; /* nul-termiante after current */
}
}
pw[idx] = 0; /* null-terminate final string */
/* restore original keyboard mode */
if (tcsetattr (0, TCSANOW, &old_kbd_mode)) {
fputs ("error: tcsetattr failed.\n", stderr);
return -1;
}
printf ("\nstored passwd: %s\n", pw);
}
可编辑输入
不带掩码运行程序,假设用户输入:
$ ./bin/backspace
enter passwd : my_password_is_bad
(用户想了想并说“哦,那不好”,现在可以按退格键 3 次让她看着:
$ ./bin/backspace
enter passwd : my_password_is_
现在她完成了她的输入:
$ ./bin/backspace
enter passwd : my_password_is_good
stored passwd: my_password_is_good
操作与显示的掩码字符完全相同。显示所有掩码字符并且用户忘记了她输入的内容,她可以简单地在所有字符显示上退格(如果她愿意,请继续按下退格键,然后再次继续输入正确的密码(姓名,等等)。 mask 字符为 '*' 的示例,例如
$ ./bin/backspace '*'
enter passwd : *******************
stored passwd: my_password_is_good
在某些情况下,这是一种为用户提供最少编辑功能的便捷方式。如果您不需要屏蔽用户输入,那么您可以完全取消更改键盘模式。
检查一下,如果您有任何问题,请告诉我。