2012-10-28 68 views
3

我有一個聊天客戶端,它以原始終端模式接收輸入,但我不知道如何在此模式下處理輸入。我需要知道兩件事:原始終端模式 - 如何接受輸入?

  • 我該如何讀取逐字符輸入並顯示它?我是否必須有某種讀取循環,每次讀取一個字符並將其存儲在緩衝區中?
  • 如果我想要我的服務器處理新行輸入的輸入,是否必須掃描每個字符進入我的緩衝區並查找\n

此外,在\n上刷新的示例逐個字符的讀取循環將非常棒。謝謝!

+1

如果只在接收到''\ n''時刷新輸出,那麼使用原始模式沒有多大意義,是嗎? –

+0

客戶端需要能夠在用戶打字時打印來自聊天室中其他客戶端的傳入消息,因此需要打印一些背景空間以將新聊天添加到用戶正在輸入的內容之上。 – theeggman85

回答

6

我爲此推薦GNU readline library。它負責獲取輸入行的繁瑣工作,並允許用戶使用退格鍵,左右箭頭等編輯他的行,並使用向上箭頭調用較舊的命令,甚至使用^ R搜索較舊的命令,等的Readline自帶安裝了典型的類Unix分佈,如Linux,但如果你沒有它,你可以找到它here

編輯:這是一個最小的readline例如:

#include <stdio.h> 
#include <readline/readline.h> 
#include <readline/history.h> 

int main(int argc, char ** argv) 
{ 
    while(1) 
    { 
     char * line = readline("> "); 
     if(!line) break; 
     if(*line) add_history(line); 
     /* Do something with the line here */ 
    } 
} 

編譯gcc -o test test.c -lreadline -lncurses。

如果你不能使用的ReadLine,函數getline是一個另類:

#include <stdio.h> 
int main() 
{ 
    char * line = NULL; 
    size_t len; 
    while(getline(&line, &len, stdin) >= 0) 
     printf("I got: %s", line); 
} 

如果連函數getline是不可接受的,你可以用fgets。它不會動態分配合適大小的緩衝區,所以太長的行會被截斷。但至少它是標準的C:

#include <stdio.h> 
int main() 
{ 
    char buf[1000]; 
    while(fgets(buf, sizeof(buf), stdin) 
     printf("I got: %s, line);  
} 
+0

我實際上正在做一個沒有圖書館的作業。這個圖書館看起來很整潔,但我會在業餘時間檢查一下。手動操作難嗎? – theeggman85

+0

如果你不能使用readline,getline是一個不太強大的選擇。它可以在找到,但它不是標準的C - 它是一個POSIX擴展,所以它不會在任何地方都可用。我會用這個例子更新答案。 – amaurea

+0

謝謝! getline將只能得到該行,但對嗎?因此,如果我處於原始模式,如何在鍵入字符時顯示字符? – theeggman85

4

在Windows中有一個非常有用的功能的kbhit(),但不存在在linux不幸。可以有多種方法。我們將爲linux創建自己的kbhit()方法。當輸入緩衝區中檢測到某些東西時,kbhit()將返回非零值,否則它將返回0並傳遞。簡而言之,它是非阻塞的。只要結果爲真,然後調用getch()方法來獲取該按鍵。

#include <stdio.h> 
#include <termios.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/time.h> 

void changemode(int); 
int kbhit(void); 
int main(void) 
{ 
    int ch; 
    changemode(1); 
    while (!kbhit());  // Waiting for some keyboard input. 

    // something has been detected. now get that. 
    ch = getchar(); 

    printf("\nGot %c\n", ch); 

    changemode(0); 
    return 0; 
} 

void changemode(int dir) 
{ 
    static struct termios oldt, newt; 

    if (dir == 1) 
    { 
    tcgetattr(STDIN_FILENO, &oldt); 
    newt = oldt; 
    newt.c_lflag &= ~(ICANON | ECHO); 
    tcsetattr(STDIN_FILENO, TCSANOW, &newt); 
    } 
    else 
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 
} 

int kbhit (void) 
{ 
    struct timeval tv; 
    fd_set rdfs; 

    tv.tv_sec = 0; 
    tv.tv_usec = 0; 

    FD_ZERO(&rdfs); 
    FD_SET (STDIN_FILENO, &rdfs); 

    select(STDIN_FILENO+1, &rdfs, NULL, NULL, &tv); 
    return FD_ISSET(STDIN_FILENO, &rdfs); 

}