gpt4 book ai didi

swift - 如何使用 Swift 在控制台应用程序上进行非阻塞键盘输入?

转载 作者:行者123 更新时间:2023-11-28 07:27:46 24 4
gpt4 key购买 nike

我想使用 Swift 5 制作一个简单的控制台游戏。我需要在不阻止游戏动画(使用表情符号)的情况下读取键盘输入。游戏在没有键盘输入的情况下继续进行,但如果有键盘输入则会做出相应的 react 。

我看过一些如何用其他语言(例如 C 和 Python)执行此操作的示例。我知道 Swift 有提供许多 POSIX 函数的 Darwin 模块。但是,这些 C 代码似乎与 Swift 5 不兼容。

比如下面的C代码如何转换成Swift? Darwin 模块中没有FD_ZEROFD_SET

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <termios.h>

struct termios orig_termios;

void reset_terminal_mode()
{
tcsetattr(0, TCSANOW, &orig_termios);
}

void set_conio_terminal_mode()
{
struct termios new_termios;

/* take two copies - one for now, one for later */
tcgetattr(0, &orig_termios);
memcpy(&new_termios, &orig_termios, sizeof(new_termios));

/* register cleanup handler, and set the new terminal mode */
atexit(reset_terminal_mode);
cfmakeraw(&new_termios);
tcsetattr(0, TCSANOW, &new_termios);
}

int kbhit()
{
struct timeval tv = { 0L, 0L };
fd_set fds;
FD_ZERO(&fds);
FD_SET(0, &fds);
return select(1, &fds, NULL, NULL, &tv);
}

int getch()
{
int r;
unsigned char c;
if ((r = read(0, &c, sizeof(c))) < 0) {
return r;
} else {
return c;
}
}

int main(int argc, char *argv[])
{
int key;

printf("press a key: ");
fflush(stdout);

set_conio_terminal_mode();

while (1) {
if (kbhit()) {
key = getch();

if (key == 13) {
printf("\n\r");
break;
} else if (key >= 20) {
printf("%c, ", key);
fflush(stdout);
}
}
else {
/* do some work */
printf(".");
usleep(10);
printf(".");
usleep(10);
printf(".");
usleep(10);
printf("\e[3D");
usleep(10);
}
}

reset_terminal_mode();
}

我希望 swifty 代码在 Swift 中做同样的事情。

最佳答案

termios 函数几乎一对一地转换为 Swift:

#if os(Linux)
import Glibc
#else
import Darwin
#endif

var orig_termios = termios()

func reset_terminal_mode() {
tcsetattr(0, TCSANOW, &orig_termios)
}

func set_conio_terminal_mode() {
tcgetattr(0, &orig_termios)
var new_termios = orig_termios
atexit(reset_terminal_mode)
cfmakeraw(&new_termios)
tcsetattr(0, TCSANOW, &new_termios)
}

set_conio_terminal_mode()

select() 的问题在于 FD_ZERO 等是“非平凡的”宏,没有导入到 Swift 中。但是您可以改用 poll():

func kbhit() -> Bool {
var fds = [ pollfd(fd: STDIN_FILENO, events: Int16(POLLIN), revents: 0) ]
let res = poll(&fds, 1, 0)
return res > 0
}

另一种方法是使用 Dispatch框架。这是一个可能会帮助您入门的简单示例。 dispatch source用于异步等待可用输入,然后将其附加到数组,从 getch() 函数中检索它的位置。串行队列用于同步对数组的访问。

import Dispatch

let stdinQueue = DispatchQueue(label: "my.serial.queue")
var inputCharacters: [CChar] = []

let stdinSource = DispatchSource.makeReadSource(fileDescriptor: STDIN_FILENO, queue: stdinQueue)
stdinSource.setEventHandler(handler: {
var c = CChar()
if read(STDIN_FILENO, &c, 1) == 1 {
inputCharacters.append(c)
}
})
stdinSource.resume()

// Return next input character, or `nil` if there is none.
func getch() -> CChar? {
return stdinQueue.sync {
inputCharacters.isEmpty ? nil : inputCharacters.remove(at: 0)
}
}

关于swift - 如何使用 Swift 在控制台应用程序上进行非阻塞键盘输入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55906580/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com