/** \file input_common.c Implementation file for the low level input library */ #include "config.h" #include #include #include #include #include #include #include #include #include "fallback.h" #include "util.h" #include "common.h" #include "wutil.h" #include "input_common.h" #include "env_universal.h" /** Time in milliseconds to wait for another byte to be available for reading after \e is read before assuming that escape key was pressed, and not an escape sequence. */ #define WAIT_ON_ESCAPE 10 /** Characters that have been read and returned by the sequence matching code */ static wint_t lookahead_arr[32]; /** Number of entries in lookahead_arr */ static int lookahead_count = 0; /** Callback function for handling interrupts on reading */ static int (*interrupt_handler)(); void input_common_init( int (*ih)() ) { interrupt_handler = ih; } void input_common_destroy() { } /** Internal function used by input_common_readch to read one byte from fd 1. This function should only be called by input_common_readch(). */ static wint_t readb() { unsigned char arr[1]; int do_loop = 0; do { fd_set fd; int fd_max=1; int res; FD_ZERO( &fd ); FD_SET( 0, &fd ); if( env_universal_server.fd > 0 ) { FD_SET( env_universal_server.fd, &fd ); fd_max = env_universal_server.fd+1; } do_loop = 0; res = select( fd_max, &fd, 0, 0, 0 ); if( res==-1 ) { switch( errno ) { case EINTR: case EAGAIN: { if( interrupt_handler ) { int res = interrupt_handler(); if( res ) return res; } do_loop = 1; break; } default: { debug( 0, L"Error while reading input from keyboard, shutting down" ); wperror(L"read"); exit(1); } } } else { if( env_universal_server.fd > 0 ) { if( FD_ISSET( env_universal_server.fd, &fd ) ) { debug( 3, L"Wake up on universal variable event" ); env_universal_read_all(); do_loop = 1; } } if( FD_ISSET( 0, &fd ) ) { if( read_blocked( 0, arr, 1 ) == -1 ) { debug( 0, L"Error while reading input from keyboard, shutting down" ); wperror(L"read"); exit(1); } do_loop = 0; } } } while( do_loop ); return arr[0]; } wchar_t input_common_readch( int timed ) { if( lookahead_count == 0 ) { if( timed ) { int count; fd_set fds; struct timeval tm= { 0, 1000 * WAIT_ON_ESCAPE } ; FD_ZERO( &fds ); FD_SET( 0, &fds ); count = select(1, &fds, 0, 0, &tm); switch( count ) { case 0: return WEOF; case -1: return WEOF; break; default: break; } } wchar_t res; static mbstate_t state; while(1) { wint_t b = readb(); char bb; int sz; if( b == R_NULL ) return R_NULL; bb=b; sz = mbrtowc( &res, &bb, 1, &state ); switch( sz ) { case -1: memset (&state, '\0', sizeof (state)); debug( 2, L"Illegal input" ); return R_NULL; case -2: break; case 0: return 0; default: return res; } } } else { if( !timed ) { while( (lookahead_count >= 0) && (lookahead_arr[lookahead_count-1] == WEOF) ) lookahead_count--; if( lookahead_count == 0 ) return input_common_readch(0); } return lookahead_arr[--lookahead_count]; } } void input_common_unreadch( wint_t ch ) { lookahead_arr[lookahead_count++] = ch; }