2011-12-12 42 views
40

Không, tôi không muốn sử dụng ncurses, bởi vì tôi muốn học cách công trình thiết bị đầu cuối và tự mình lập trình vui vẻ. :) Nó không phải được di động, nó phải làm việc trên bộ mô phỏng thiết bị đầu cuối dựa trên xterm linux chỉ.Viết một "thực" chương trình thiết bị đầu cuối tương tác như vim, htop, ... trong C/C++ mà không ncurses

Điều tôi muốn làm là lập trình một ứng dụng đầu cuối tương tác như htop và vim. Những gì tôi có nghĩa là không phải là đầu ra của các nhân vật trông giống như hộp hoặc thiết lập màu sắc, điều này là tầm thường; cũng để làm cho nội dung phù hợp với kích thước cửa sổ. Những gì tôi cần là

  1. làm thế nào để có được tương tác chuột như cách nhấp vào một nhân vật và di chuyển bánh xe chuột (khi chuột là một nhân vật cụ thể) để thực hiện di chuyển [EDIT: trong một giả lập thiết bị đầu cuối của Tất nhiên], và

  2. làm thế nào để hoàn toàn lưu và khôi phục đầu ra của quá trình cha mẹ và tách in của tôi từ đầu ra của nó, vì vậy sau khi rời khỏi ứng dụng gì của tôi, nhưng lệnh tôi bước vào trong vỏ nên có mặt ở đó, như khi chạy htop và bỏ nó aga in: không có gì hiển thị từ ứng dụng này nữa.

Tôi thực sự không muốn sử dụng ncurses. Nhưng tất nhiên, nếu bạn biết phần nào của ncurses chịu trách nhiệm cho những nhiệm vụ này, bạn được phép cho tôi biết nơi nào trong mã nguồn tôi có thể tìm thấy nó, vì vậy tôi sẽ nghiên cứu nó.

+2

kiểm tra mã nguồn 'ncurses' –

+4

" bạn có thể cho tôi biết mã nguồn tôi có thể tìm thấy ở đâu " – leemes

+1

Tôi đã nói điều này vì tôi chắc chắn tôi không biết mã nguồn ncurses tốt như ai đó đang sử dụng cả ngày. :) – leemes

Trả lời

4

Tôi hơi bối rối. Bạn nói về một ứng dụng thiết bị đầu cuối “ ”, như vim; các ứng dụng đầu cuối không nhận được các sự kiện chuột và không trả lời số .

Nếu bạn đang nói về các ứng dụng thiết bị đầu cuối thực, chạy trong một số xterm, điều quan trọng cần lưu ý là nhiều sự cố di chuyển vấn đề liên quan đến thiết bị đầu cuối chứ không phải HĐH. Thiết bị đầu cuối được điều khiển bằng cách gửi các chuỗi thoát khác nhau. Mà những người làm những gì phụ thuộc vào thiết bị đầu cuối; các mã thoát ANSI hiện nay khá phổ biến, tuy nhiên, xem http://en.wikipedia.org/wiki/ANSI_escape_code. Chúng thường được hiểu bởi xterm, ví dụ.

Bạn có thể phải xuất ra một chuỗi bổ sung ở đầu và cuối cùng để vào và thoát khỏi chế độ toàn màn hình ”; điều này là cần thiết cho xterm. Cuối cùng, bạn sẽ phải làm điều gì đó đặc biệt ở cấp độ đầu vào/đầu ra để đảm bảo rằng trình điều khiển đầu ra của bạn không thêm bất kỳ ký tự nào (ví dụ: chuyển đổi một LF đơn giản thành một CRLF) và đảm bảo rằng đầu vào không echo, trong suốt và trả về ngay lập tức. Trong Linux, điều này được thực hiện bằng cách sử dụng ioctl. (Một lần nữa, đừng quên khôi phục nó khi bạn hoàn thành.)

+1

Có GPM cho các sự kiện chuột trong các ứng dụng đầu cuối, không? – Antoine

+13

Sự khởi đầu của câu trả lời này là hoàn toàn không có thật. Có một giao thức để thông báo cho thiết bị đầu cuối bạn muốn các sự kiện nhấp chuột và một giao thức cho chúng được gửi từ thiết bị đầu cuối đến ứng dụng, tất cả như là các chuỗi thoát. Bàn điều khiển Linux không hỗ trợ điều này và thay vào đó sử dụng cách tiếp cận GPM ghê gớm, nhưng 'xterm' và những người khác hỗ trợ nó một cách chính xác. –

+0

Với sự kiện chuột, tôi có nghĩa là trong giả lập thiết bị đầu cuối. Tôi đã vô hiệu hóa echo của đầu vào người dùng và bộ đệm đầu vào, vì vậy tôi sử dụng stdin như một loại 'sự kiện quan trọng' dòng chứ không phải là dòng văn bản. Tôi có thể tìm thấy những chuỗi bổ sung nào mà tôi cần đặt ở đầu/cuối cho chế độ "toàn màn hình"? Không có mã thoát ANSI nào không? – leemes

16

Để thao tác với thiết bị đầu cuối, bạn phải sử dụng các dãy điều khiển . Thật không may, những mã này phụ thuộc vào thiết bị đầu cuối cụ thể mà bạn đang sử dụng. Đó là lý do tại sao terminfo (trước đây là termcap) tồn tại ở nơi đầu tiên.

Bạn không nói nếu bạn muốn sử dụng terminfo hay không.Vì vậy:

  • Nếu bạn sử dụng terminfo, nó sẽ cung cấp cho bạn chuỗi điều khiển chính xác cho từng hành động mà thiết bị của bạn hỗ trợ.
  • Nếu bạn không sử dụng terminfo ... tốt, bạn phải tự mã hóa mọi hành động trong mọi loại thiết bị đầu cuối bạn muốn hỗ trợ.

Vì bạn muốn điều này cho mục đích học tập, tôi sẽ giải thích ở phần thứ hai.

Bạn có thể khám phá loại thiết bị đầu cuối bạn đang sử dụng từ biến môi trường $TERM. Trong linux, thông thường nhất là xterm cho các trình mô phỏng đầu cuối (XTerm, gnome-terminal, konsole) và linux cho các thiết bị đầu cuối ảo (các thiết bị khi X không chạy).

Bạn có thể khám phá chuỗi điều khiển dễ dàng bằng lệnh tput. Nhưng khi tput in chúng trên giao diện điều khiển, họ sẽ áp dụng ngay lập tức, vì vậy nếu bạn muốn thực sự nhìn thấy chúng, sử dụng:

$ TERM=xterm tput clear | hd 
00000000 1b 5b 48 1b 5b 32 4a        |.[H.[2J| 

$ TERM=linux tput clear | hd 
00000000 1b 5b 48 1b 5b 4a         |.[H.[J| 

Đó là, để xóa màn hình trong một xterm bạn phải đầu ra ESC [ H ESC [ 2J trong một xterm nhưng ESC [ H ESC [ J trong một thiết bị đầu cuối Linux.

Giới thiệu về các lệnh cụ thể mà bạn hỏi, bạn nên đọc kỹ man 5 terminfo. Có rất nhiều thông tin ở đó.

+0

Vâng, đối với tôi, 'ESC [2J' hoạt động ở cả hai đầu cuối xterm và linux ... – leemes

+0

_Có nhiều cách để làm da mèo._ Và có rất nhiều cách để xóa màn hình. Đặc biệt, IIRC, 'ESC [2J' xóa toàn bộ màn hình trong khi' ESC [J' xóa từ con trỏ đến cuối màn hình. Nhưng vì 'ESC [H' di chuyển con trỏ tới HOME, những con số này phải tương đương. Không có gì ngạc nhiên khi các thiết bị đầu cuối 'xterm' và' linux' có xu hướng tương tự nhau. – rodrigo

+0

@leemes: Đó là vì thiết bị đầu cuối bạn đang sử dụng dường như hỗ trợ cả hai. –

6

Mặc dù đây là câu hỏi hơi cũ, tôi nghĩ rằng tôi nên chia sẻ một ví dụ ngắn về cách làm điều này mà không cần sử dụng ncurses, nó không khó nhưng tôi chắc chắn nó sẽ không được di động.

Mã này đặt stdin ở chế độ thô, chuyển sang màn hình đệm thay thế (lưu trạng thái của thiết bị đầu cuối trước khi khởi chạy), cho phép theo dõi chuột và in nút và tọa độ khi người dùng nhấp vào một nơi nào đó. Sau khi thoát với Ctrl + C chương trình sẽ hoàn nguyên cấu hình đầu cuối.

#include <stdio.h> 
#include <unistd.h> 
#include <termios.h> 

int main (void) 
{ 
    unsigned char buff [6]; 
    unsigned int x, y, btn; 
    struct termios original, raw; 

    // Save original serial communication configuration for stdin 
    tcgetattr(STDIN_FILENO, &original); 

    // Put stdin in raw mode so keys get through directly without 
    // requiring pressing enter. 
    cfmakeraw (&raw); 
    tcsetattr (STDIN_FILENO, TCSANOW, &raw); 

    // Switch to the alternate buffer screen 
    write (STDOUT_FILENO, "\e[?47h", 6); 

    // Enable mouse tracking 
    write (STDOUT_FILENO, "\e[?9h", 5); 
    while (1) { 
     read (STDIN_FILENO, &buff, 1); 
     if (buff[0] == 3) { 
      // User pressd Ctr+C 
      break; 
     } else if (buff[0] == '\x1B') { 
      // We assume all escape sequences received 
      // are mouse coordinates 
      read (STDIN_FILENO, &buff, 5); 
      btn = buff[2] - 32; 
      x = buff[3] - 32; 
      y = buff[4] - 32; 
      printf ("button:%u\n\rx:%u\n\ry:%u\n\n\r", btn, x, y); 
     } 
    } 

    // Revert the terminal back to its original state 
    write (STDOUT_FILENO, "\e[?9l", 5); 
    write (STDOUT_FILENO, "\e[?47l", 6); 
    tcsetattr (STDIN_FILENO, TCSANOW, &original); 
    return 0; 
} 

Lưu ý: Điều này sẽ không hoạt động đúng cho các đầu cuối có hơn 255 cột.

Các tham chiếu tốt nhất cho chuỗi thoát mà tôi đã tìm thấy là thisthis một.

+0

Đối với bất cứ ai tự hỏi tại sao buff [0] == 3 có nghĩa là Ctrl + C đã được nhấn, đó là bởi vì trong ASCII 0x03 là biểu tượng ETX, viết tắt của "End of Text". – santileortiz

Các vấn đề liên quan