/* curses skel for A04, by Felipe MP, based on example 7, curses HOWTO */ #include #include // ... mais includes aqui ... typedef struct sockaddr SA; #define PORT (30000 + (RA%10000)) #define MIN(x,y) ((x)>(y)?(y):(x)) /* macro para mínimo entre 2 vals. */ #define CTRL(x) (((x)-'A'+1)) #define K_ENTER CTRL('J') #define K_BACKSPACE (CTRL('G')|0x100) // dado empírico :-) #define K_CTRL_U CTRL('U') #define K_CTRL_D CTRL('D') WINDOW *remote_win, *local_win, *line_win; #ifdef DEBUG WINDOW *debug_win; #endif int remote_height, local_height, width; void init_curses() { initscr(); /* Start curses mode */ cbreak(); /* Line buffering disabled, Pass on * everything to me */ // se DEBUG estiver habilitado, vc pode usar // debug_win para mensagens de debug // código ficou sujo mas achei melhor deixar // caso queiram usar na depuração #ifdef DEBUG remote_height = LINES / 2 - 1; /* half window is remote */ local_height = LINES - remote_height - 2; /* last line for typing, remainder for local */ width = COLS; /* whole width */ /* fazemos uma linha horizontal no centro de stdscr */ mvhline(remote_height+1, 0, 0, COLS); mvprintw(remote_height+1, 2, " conversando com %s ", remote_user); refresh(); debug_win = newwin(1,width,0,0); remote_win = newwin(remote_height, width, 1, 0); local_win = newwin(local_height, width, remote_height+2, 0); #else remote_height = LINES / 2 - 1; /* half window is remote */ local_height = LINES - remote_height - 1; /* last line for typing, remainder for local */ width = COLS; /* whole width */ /* fazemos uma linha horizontal no centro de stdscr */ mvhline(remote_height, 0, 0, COLS); mvprintw(remote_height, 2, " conversando com %s ", remote_user); refresh(); remote_win = newwin(remote_height, width, 0, 0); local_win = newwin(local_height, width, remote_height+1, 0); #endif // linha de entrada do usuário line_win = newwin(1, COLS, LINES-1, 0); keypad(line_win, TRUE); /* habilita rolagem nas janelas, v. man scrollok() */ idlok(local_win, 1); idlok(remote_win, 1); scrollok(local_win, 1); scrollok(remote_win, 1); /* desabilita echo; se deixarmos habilitado, curses pode interpretar diferente e nossa string vai acabar diferente do que aparece na tela -- ex.: usuário pressiona seta para a esquerda, curses entende, mas nosso programa não. Anyway, podem testar pra ver se dá certo :-) */ noecho(); // apenas um incentivo a criatividade, há também as cores... wattron(local_win, A_BOLD); wattron(remote_win, A_BOLD); /* neste exemplo, escreve sempre no fim da janela (height-1,0) */ mvwprintw(local_win, local_height-1, 0, "local\n"); mvwprintw(remote_win, remote_height-1, 0, "remoto\n"); // note que se o terminal mudar de tamanho (ex. ao maximizar xterm), // nossas janelas continuam do mesmo tamanho // ideal seria tratar sinal SIGWINCH } void end_error(const char *s) { perror(s); exit(1); } void end_curses_error(const char *s) { endwin(); end_error(s); } void init_sockets(const char *remote_name) { // codigo de conexao } int main(int argc, char *argv[]) { init_curses(); init_sockets(argv[1]); /* se inicializamos curses antes de conexao, mensagens de conexao deverao ser impressas via printw porem, note que exit() vai executar endwin() apagando a tela por isso mensagens de erro deverão ser exibidas depois de endwin() para que o usuário as veja (para isso serve end_curses_error()) obs: para facilitar depuração do código da conexão, melhor seria inicializar curses depois dos sockets (na verdade programas exemplo fazem isso) na verdade mesmo, para facilitar depuração o ideal seria encapsular chamadas curses em chamadas genéricas por exemplo: void my_print(...) { #ifdef DEBUG printw(...) #else printf(...) #endif obs.: note q vc teria que usar stdarg.h (printf e printw têm argumentos variáveis (v. man stdarg) */ // a idéia era deixar em bold apenas as mensagens de inicialização wattroff(local_win, A_BOLD); wattroff(remote_win, A_BOLD); do { FD_ZERO(&rset); ... if (select(...) < 0) end_curses_error("select"); if (FD_ISSET(sockfd, &rset)) { // chegou mensagem } if (FD_ISSET(0, &rset)) { // usuário pressionou uma tecla // pega um caractere com uma função própria (seja my_getch()) ch = my_getch(); // my_getch() vai chamar wgetch() mas já faz outras coisas também // p.ex., constrói a string a ser enviada, cozinha entrada, etc. // para constar: programa exemplo compreende CTRL+U, CTRL+D, ENTER, BACKSPACE // e além disso só aceita caracteres (ch < 255 && !iscntrl(ch)) } } while (TRUE); endwin(); return 0; } /* author: Gustavo Sverzut Barbieri (http://www.gustavobarbieri.com.br) */