在 macOS 上以 C 语言实现非阻塞键盘读取

问题描述 投票:0回答:1

我正在尝试在

我的 BASIC 解释器
中实现非阻塞键盘输入以支持INKEY$。阅读 SO 上的(很多!)线程,我发现了 POSIX 下的规范解决方案

static int getkey(void)
{
  int c;
  static struct termios oldState, newState;
  if (tcgetattr(STDIN_FILENO, &oldState) == -1)
    return 0;
  newState = oldState;
  newState.c_lflag &= ~ICANON;  // use noncanonical input
  newState.c_lflag &= ~ECHO;    // disable echo
  newState.c_cc[VMIN]  = 1;     // minimum chars to wait for
  newState.c_cc[VTIME] = CTIME; // minimum wait time
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &newState) == -1)
    return 0;
  c = getchar();
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &oldState) == -1)
    return 0;
  return c;
}

当 newState.c_cc[VMIN] = 1 时,它会停止并等待,但否则会按预期工作。将其更改为 0 会阻止其等待,但也会导致 c 永远不会非零。我检查了 tcsetattr 是否失败并且返回 0 - 不,一切都很好。

有人真的可以在任何现代的 macOS 上使用这个功能吗?我使用的是 12.7.1 和 Xcode 14.2,但我怀疑这段代码是否发生了变化,因为按钮仍然是蓝色的并且在跳动。

附注与此相关的是,ECHO 标志似乎在 Xcode 控制台中没有效果,但在终端中按预期工作。我想这并不完全令人惊讶。

c macos posix
1个回答
0
投票

一些问题...

  1. 您只想在初始化期间调用
    tcsetattr
    once(使用
    TCSANOW
    )。
  2. VMIN
    设置为 0,并将
    VTIME
    设置为 0。
  3. 不要使用
    getchar
    。不要将原始 tty 输入与
    stdio
    混合在一起。请使用
    read
    来代替。
  4. 您可以使用
    cfmakeraw
    ,可能需要进行一些额外的调整。

这是一些示例代码:

void
ttyinit(int fd)
{
    struct termios tio;

    tcgetattr(fd,&tio);

    cfmakeraw(&tio);
    tio.c_cc[VMIN] = 0;
    tio.c_cc[VTIME] = 0;

    tcsetattr(fd,TCSANOW,&tio);
}

int
ttyget(int fd)
{
    char buf[1];
    int len;

    len = read(fd,buf,1);

    if (len > 0)
        len = buf[0] & 0xFF;

    return len;
}
© www.soinside.com 2019 - 2024. All rights reserved.