gpt4 book ai didi

c - 以非阻塞方式从 ncurses 中的 `getstr` 获取完整字符串

转载 作者:太空宇宙 更新时间:2023-11-04 03:27:03 25 4
gpt4 key购买 nike

我想做的是有一个文本不断更新的聊天窗口,然后是一个输入窗口,用户可以在其中输入一些消息以添加到聊天中。

我想知道是否可以对护士使用 getstr(),这样 getstr() 只会在我点击后返回一个字符串给我回车键。

这将允许我持续监控 TCP 连接以获取新消息,然后在用户输入完整消息后将消息添加到聊天中。

我看到帖子建议使用 timeout(),但这会导致 getstr() 在用户不活动一段时间后返回用户输入的任何内容多少时间。这并不是我真正想要的,因为在这种情况下 getstr() 仍然在用户输入时阻塞,如果用户在消息中途停止思考他们正在写什么,在用户确认这是他/她想要通过按回车键发送的消息之前,该文本由 getstr() 返回。

我特别好奇如何让 getstr() 工作,因为这样我就不必手动处理删除/退格/光标移动操作。考虑到我的项目范围,投资有点太大了。

最佳答案

碰巧,我也在研究具有类似需求的东西(虽然不是聊天应用程序)。

重申一下我之前说过的话:如果你不需要渲染任何东西,你可以只使用第二个线程。 Buf 如果您确实需要在等待输入时呈现,您需要自己进行输入处理。

为什么?因为 ncurses 只是通过 stdin/stdout 与终端对话。这意味着你只有一个光标来处理输入和输出,所以如果你移动光标来打印一些输出,正在进行的输入将变得一团糟。

但是自己解释和呈现输入并不难。这是我的第一遍解决方案的简化版本:

// Compile with -lncurses

#include <ncurses.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

struct input_line {
char *ln;
int length;
int capacity;
int cursor;
int last_rendered;
};

void make_buffer(struct input_line *buf) {
buf->ln = NULL;
buf->length = 0;
buf->capacity = 0;
buf->cursor = 0;
buf->last_rendered = 0;
}

void destroy_buffer(struct input_line *buf) {
free(buf->ln);
make_buffer(buf);
}

void render_line(struct input_line *buf) {
int i = 0;
for(; i < buf->length; i ++) {
chtype c = buf->ln[i];
if(i == buf->cursor) {
c |= A_REVERSE;
}
addch(c);
}
if(buf->cursor == buf->length) {
addch(' ' | A_REVERSE);
i ++;
}
int rendered = i;
// Erase previously rendered characters
for(; i < buf->last_rendered; i ++) {
addch(' ');
}
buf->last_rendered = rendered;
}

int retrieve_content(struct input_line *buf, char *target, int max_len) {
int len = buf->length < (max_len - 1) ? buf->length : (max_len - 1);
memcpy(target, buf->ln, len);
target[len] = '\0';
buf->cursor = 0;
buf->length = 0;
return len + 1;
}

void add_char(struct input_line *buf, char ch) {
// Ensure enough space for new character
if(buf->length == buf->capacity) {
int ncap = buf->capacity + 128;
char *nln = (char*) realloc(buf->ln, ncap);
if(!nln) {
// Out of memory!
return;
}
buf->ln = nln;
buf->capacity = ncap;
}

// Add new character
memmove(
&buf->ln[buf->cursor+1],
&buf->ln[buf->cursor],
buf->length - buf->cursor
);
buf->ln[buf->cursor] = ch;
++ buf->cursor;
++ buf->length;
}

int handle_input(struct input_line *buf, char *target, int max_len, int key) {
if(!(key & KEY_CODE_YES) && isprint(key)) {
add_char(buf, key);
return 0;
}

switch(key) {
case ERR: /* no key pressed */ break;
case KEY_LEFT: if(buf->cursor > 0) { buf->cursor --; } break;
case KEY_RIGHT: if(buf->cursor < buf->length) { buf->cursor ++; } break;
case KEY_HOME: buf->cursor = 0; break;
case KEY_END: buf->cursor = buf->length; break;
case '\t':
add_char(buf, '\t');
break;
case KEY_BACKSPACE:
case 127:
case 8:
if(buf->cursor <= 0) {
break;
}
buf->cursor --;
// Fall-through
case KEY_DC:
if(buf->cursor < buf->length) {
memmove(
&buf->ln[buf->cursor],
&buf->ln[buf->cursor+1],
buf->length - buf->cursor - 1
);
buf->length --;
}
break;
case KEY_ENTER:
case '\r':
case '\n':
return retrieve_content(buf, target, max_len);
}
return 0;
}

int get_line_non_blocking(struct input_line *buf, char *target, int max_len) {
while(1) {
int key = getch();
if(key == ERR) {
// No more input
return 0;
}
int n = handle_input(buf, target, max_len, key);
if(n) {
return n;
}
}
}

int main(void) {
initscr();

cbreak(); // Immediate key input
nonl(); // Get return key
timeout(0); // Non-blocking input
keypad(stdscr, 1); // Fix keypad
noecho(); // No automatic printing
curs_set(0); // Hide real cursor
intrflush(stdscr, 0); // Avoid potential graphical issues
leaveok(stdscr, 1); // Don't care where cursor is left

struct input_line lnbuffer;
make_buffer(&lnbuffer);

int lines_read = 0;
while(1) {
char ln[1024];
int len = get_line_non_blocking(&lnbuffer, ln, sizeof(ln));
if(len > 0) {
if(strcmp(ln, "exit") == 0) {
break;
}
mvaddstr(7 + lines_read, 5, ln);
lines_read ++;
}
move(5, 5);
render_line(&lnbuffer);

// Show that we are active
mvaddch(2, 2, '0' + (rand() % 10));
// (probably a good idea to sleep here)
}

destroy_buffer(&lnbuffer);
delwin(stdscr);
endwin();
refresh();

return 0;
}

有很多控制字符尚未在那里实现(最著名的是 INSERT),但是添加您认为对特定应用程序重要的任何内容应该非常简单。另请注意,如果您需要 unicode(推荐),则需要使用 ncursesw 及其替代函数。

关于c - 以非阻塞方式从 ncurses 中的 `getstr` 获取完整字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40319239/

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