//------------------------------------------------------------------- // seemouse.cpp // // This program illustrates the handling of mouse-events while // executing in a 256-color graphics mode with Linux's General // Purpose Mouse application programming interface ('libgpm'). // // compile via: $ g++ seemouse.cpp int86.cpp -lgpm -o seemouse // // Reference: Pradeep Padala, "Mouse Programming with libgpm" // online at: http://www.cise.ufl.edu/~ppadala/phd/libgpm.pdf // prelininary version of article submitted to Linux Journal. // // programmer: ALLAN CRUSE // date begun: 15 SEP 2005 // completion: 16 SEP 2005 //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for read(), write(), close() #include // for tcgetattr(), tcsetattr() #include // for Gpm_Open(), Gpm_Getc(), etc. #include // for mmap() #include // for inb(), outb(), etc. #include "int86.h" // for init8086(), int86() typedef unsigned char u8; u8 *vram = (u8*)0xA0000000; struct vm86plus_struct vm; int vesa_mode = 0x4105, hres = 1024, vres = 768; /* ** Here we define our 16-by-16 mouse-cursor, where characters signify: ** '0' = transparent, '1' = background-color, '2' = foreground-color */ u8 cross_fgcolor = 14, cross_bgcolor = 0; // yellow on black u8 cross_x_hotspot = 8, cross_y_hotspot = 8; char *cross[ 16 ] = { "0000011111000000", "0000012221000000", "0000012221000000", "0000012221000000", "0000012221000000", "1111112221111110", "1222222222222210", "1222222222222210", "1222222222222210", "1111112222111110", "0000012221000000", "0000012221000000", "0000012221000000", "0000012221000000", "0000011111000000" "0000000000000000" }; /* ** Here is where we describe the mouse's current location and state. */ int mouse_xmin = cross_x_hotspot, mouse_xmax = mouse_xmin + hres-16; int mouse_ymin = cross_y_hotspot, mouse_ymax = mouse_ymin + vres-16; int mouse_xpos = hres/2, mouse_ypos = vres/2, mouse_is_down = 0; int mouse_cache[ 16 ][ 16 ]; // <-- for saving mouse background-area /* ** Here is our description for our rectangular region-of-interest. */ int roi_wide = hres/16, roi_high = vres/16; int roi_xmin = (hres - roi_wide)/2, roi_xmax = roi_xmin + roi_wide; int roi_ymin = roi_high * 4, roi_ymax = roi_ymin + roi_high; int roi_normal_color = 2, roi_active_color = 10; int roi_entered = 0, roi_selected = 0; void fill_area( int x, int y, int h, int v, int color ) { u8 *dstn = vram + y * hres + x; for (y = 0; y < v; y++) for (x = 0; x < h; x++) dstn[ y * hres + x ] = color; } void redraw_roi( void ) { int color = ( roi_entered ) ? roi_active_color : roi_normal_color; fill_area( roi_xmin, roi_ymin, roi_wide, roi_high, color ); } void show_mouse( void ) { u8 *dstn = vram + mouse_ypos * hres + mouse_xpos; // preserve the background for (int j = 0; j < 16; j++) for (int i = 0; i < 16; i++) mouse_cache[ i ][ j ] = dstn[ j * hres + i ]; // superimpose the cursor for (int j = 0; j < 16; j++) for (int i = 0; i < 16; i++) switch ( cross[ j ][ i ] ) { case '2': dstn[ j * hres + i ] = cross_fgcolor; break; case '1': dstn[ j * hres + i ] = cross_bgcolor; break; } } void hide_mouse( void ) { u8 *dstn = vram + mouse_ypos * hres + mouse_xpos; // restore the background for (int j = 0; j < 16; j++) for (int i = 0; i < 16; i++) dstn[ j * hres + i ] = mouse_cache[ i ][ j ]; } int mouse_in_roi( void ) { int x = mouse_xpos + cross_x_hotspot; int y = mouse_ypos + cross_y_hotspot; if (( x < roi_xmin )||( x > roi_xmax )) return 0; if (( y < roi_ymin )||( y > roi_ymax )) return 0; return 1; } int my_event_handler( Gpm_Event *evt, void *data ) { if (( evt->type & GPM_MOVE )||( evt->type & GPM_DRAG )) { hide_mouse(); mouse_xpos += evt->dx * 10; mouse_ypos += evt->dy * 10; if ( mouse_xpos < mouse_xmin ) mouse_xpos = mouse_xmin; if ( mouse_xpos > mouse_xmax ) mouse_xpos = mouse_xmax; if ( mouse_ypos < mouse_ymin ) mouse_ypos = mouse_ymin; if ( mouse_ypos > mouse_ymax ) mouse_ypos = mouse_ymax; roi_entered = mouse_in_roi(); redraw_roi(); show_mouse(); } if ( evt->type & GPM_DRAG ) { roi_active_color = 12; roi_normal_color = 4; hide_mouse(); redraw_roi(); show_mouse(); } if ( evt->type & GPM_DOWN ) { roi_selected = roi_entered; roi_active_color = 11; roi_normal_color = 3; hide_mouse(); redraw_roi(); show_mouse(); } if ( evt->type & GPM_UP ) { roi_selected = roi_entered; roi_active_color = 10; roi_normal_color = 2; hide_mouse(); redraw_roi(); show_mouse(); } return 0; } int main( int argc, char **argv ) { // establish a connection with the gpm server-daemon Gpm_Connect conn; conn.eventMask = ~0; // we want to know about all events conn.defaultMask = 0; // don't handle anything by default conn.minMod = 0; // we want to know about everything conn.maxMod = ~0; // (info on any modifiers included) if ( Gpm_Open( &conn, 0 ) < 0 ) { perror( "cannot connect to mouse server" ); exit(1); } // memory-map the display-memory into user-space int vd = open( "/dev/vram", O_RDWR ); if ( vd < 0 ) { perror( "/dev/vram" ); exit(1); } int size = lseek( vd, 0, SEEK_END ); int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; if ( mmap( (void*)vram, size, prot, flag, vd, 0 ) == MAP_FAILED ) { perror( "mmap" ); exit(1); } // setup keyboard for noncanonical input struct termios origtty; tcgetattr( STDIN_FILENO, &origtty ); struct termios worktty = origtty; worktty.c_lflag &= ~( ECHO | ICANON ); worktty.c_cc[ VMIN ] = 1; worktty.c_cc[ VTIME ] = 0; tcsetattr( STDIN_FILENO, TCSAFLUSH, &worktty ); // enter graphics mode init8086(); vm.regs.eax = 0x4F02; vm.regs.ebx = vesa_mode; int86( 0x10, vm ); // draw screen border int x = 0, y = 0, color = 15; do { vram[ y * hres + x ] = color; ++x; } while ( x < hres-1 ); do { vram[ y * hres + x ] = color; ++y; } while ( y < vres-1 ); do { vram[ y * hres + x ] = color; --x; } while ( x > 0 ); do { vram[ y * hres + x ] = color; --y; } while ( y > 0 ); // draw background pattern for (y = 2; y < vres-2; y++) for (x = 2; x < hres-2; x++) vram[ y * hres + x ] = (( x % 4 )||( y % 4 )) ? 1 : 9; getchar(); // draw the region-of-interest redraw_roi(); getchar(); // install our mouse-event handler gpm_handler = my_event_handler; // draw the mouse-cursor show_mouse(); // main loop (to process any keyboard input) while ( Gpm_Getc( stdin ) != '\e' ); // erase the mouse-cursor hide_mouse(); Gpm_Close(); int inch = 0; read( STDIN_FILENO, &inch, sizeof( inch ) ); // leave graphics mode vm.regs.eax = 0x0003; int86( 0x10, vm ); // restore canonical keyboard input tcsetattr( STDIN_FILENO, TCSAFLUSH, &origtty ); printf( "\n" ); }