/* * $Id$ */ /* * Harbour Project source code: * Mouse subsystem for gtsln * * Copyright 1999-2001 Viktor Szakats * www - http://www.harbour-project.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). * * As a special exception, the Harbour Project gives permission for * additional uses of the text contained in its release of Harbour. * * The exception is that, if you link the Harbour libraries with other * files to produce an executable, this does not by itself cause the * resulting executable to be covered by the GNU General Public License. * Your use of that executable is in no way restricted on account of * linking the Harbour library code into it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public License. * * This exception applies only to the code released by the Harbour * Project under the name Harbour. If you copy code from other * Harbour Project or Free Software Foundation releases into a copy of * Harbour, as the General Public License permits, the exception does * not apply to the code that you add in this way. To avoid misleading * anyone as to the status of such modified files, you must delete * this exception notice from them. * * If you write modifications of your own for Harbour, it is your choice * whether to permit this exception to apply to your modifications. * If you do not wish that, delete this exception notice. * */ /* *********************************************************************** */ #include "gtsln.h" #include #ifdef HAVE_GPM_H #include #include #include #include Gpm_Connect Conn; #endif /* *********************************************************************** */ static int s_iMouseRow = 0; static int s_iMouseCol = 0; static BOOL s_bMousePresent = FALSE; static int s_iMouseButtons = -1; static USHORT s_usMouseState = 0; static USHORT s_usLastMouseState = 0; static struct timeval mLeftDblckTime; static struct timeval mMiddleDblckTime; static struct timeval mRightDblckTime; /* *********************************************************************** */ #ifdef HAVE_GPM_H static BOOL GetGpmEvent( Gpm_Event *Evt ) { if( s_bMousePresent && gpm_fd >= 0 ) { struct timeval tv = { 0, 0 }; fd_set ReadFD; FD_ZERO( &ReadFD ); FD_SET( gpm_fd, &ReadFD ); if( select( gpm_fd+1, &ReadFD, NULL, NULL, &tv ) > 0 ) if( FD_ISSET( gpm_fd, &ReadFD ) ) return Gpm_GetEvent( Evt ) > 0; } return FALSE; } #endif /* *********************************************************************** */ static BOOL GetXtermEvent( int *Btn, int *Col, int *Row ) { /* Xterm mouse event consists of three chars */ if( SLang_input_pending( 0 ) > 0 ) { *Btn = SLang_getkey() - 0x20; if( SLang_input_pending( 0 ) > 0 ) { *Col = SLang_getkey() - 0x21; if( SLang_input_pending( 0 ) > 0 ) { *Row = SLang_getkey() - 0x21; return TRUE; } } } return FALSE; } /* *********************************************************************** */ static void hb_sln_CheckDoubleClick() { USHORT usNewButtons = ( s_usMouseState & ~s_usLastMouseState ) & M_BUTTON_KEYMASK; if( usNewButtons != 0 ) { struct timeval evtTime; TIMEVAL_GET( evtTime ); if( usNewButtons & M_BUTTON_LEFT ) { if ( TIMEVAL_LESS( evtTime, mLeftDblckTime ) ) s_usMouseState |= M_BUTTON_LDBLCK; TIMEVAL_ADD( mLeftDblckTime, evtTime, hb_mouse_GetDoubleClickSpeed() ); } if( usNewButtons & M_BUTTON_MIDDLE ) { if ( TIMEVAL_LESS( evtTime, mMiddleDblckTime ) ) s_usMouseState |= M_BUTTON_MDBLCK; TIMEVAL_ADD( mMiddleDblckTime, evtTime, hb_mouse_GetDoubleClickSpeed() ); } if( usNewButtons & M_BUTTON_RIGHT ) { if ( TIMEVAL_LESS( evtTime, mRightDblckTime ) ) s_usMouseState |= M_BUTTON_RDBLCK; TIMEVAL_ADD( mRightDblckTime, evtTime, hb_mouse_GetDoubleClickSpeed() ); } } } /* *********************************************************************** */ void hb_gt_sln_mouse_ProcessTerminalEvent( void ) { int Btn, Col, Row; if( GetXtermEvent( &Btn, &Col, &Row ) ) { if( s_iMouseRow != Row || s_iMouseCol != Col ) s_usMouseState |= M_CURSOR_MOVE; s_iMouseRow = Row; s_iMouseCol = Col; switch( Btn & 0xE3 ) { case 0: s_usMouseState |= M_BUTTON_LEFT; break; case 1: s_usMouseState |= M_BUTTON_MIDDLE; break; case 2: s_usMouseState |= M_BUTTON_RIGHT; break; case 3: s_usMouseState &= ~M_BUTTON_KEYMASK; break; case 0x40: s_usMouseState |= M_BUTTON_WHEELUP; break; case 0x41: s_usMouseState |= M_BUTTON_WHEELDOWN; break; } hb_sln_CheckDoubleClick(); } } /* *********************************************************************** */ int hb_gt_sln_mouse_Inkey( int iEventMask, BOOL fCheckNew ) { if( s_usMouseState != s_usLastMouseState ) { if( s_usMouseState & M_CURSOR_MOVE ) { s_usMouseState &= ~M_CURSOR_MOVE; return K_MOUSEMOVE; } else if( s_usMouseState & M_BUTTON_WHEELUP ) { s_usMouseState &= ~M_BUTTON_WHEELUP; return K_MWFORWARD; } else if( s_usMouseState & M_BUTTON_WHEELDOWN ) { s_usMouseState &= ~M_BUTTON_WHEELDOWN; return K_MWBACKWARD; } else { USHORT usKeyDiff = ( s_usMouseState ^ s_usLastMouseState ); if( usKeyDiff & M_BUTTON_LEFT ) { s_usLastMouseState ^= M_BUTTON_LEFT; if( s_usMouseState & M_BUTTON_LEFT ) { if( s_usMouseState & M_BUTTON_LDBLCK ) { s_usMouseState &= ~M_BUTTON_LDBLCK; return K_LDBLCLK; } else return K_LBUTTONDOWN; } else return K_LBUTTONUP; } else if( usKeyDiff & M_BUTTON_MIDDLE ) { s_usLastMouseState ^= M_BUTTON_MIDDLE; if( s_usMouseState & M_BUTTON_MIDDLE ) { if( s_usMouseState & M_BUTTON_MDBLCK ) { s_usMouseState &= ~M_BUTTON_MDBLCK; return K_MDBLCLK; } else return K_MBUTTONDOWN; } else return K_MBUTTONUP; } else if( usKeyDiff & M_BUTTON_RIGHT ) { s_usLastMouseState ^= M_BUTTON_RIGHT; if( s_usMouseState & M_BUTTON_RIGHT ) { if( s_usMouseState & M_BUTTON_RDBLCK ) { s_usMouseState &= ~M_BUTTON_RDBLCK; return K_RDBLCLK; } else return K_RBUTTONDOWN; } else return K_RBUTTONUP; } s_usLastMouseState = s_usMouseState; } } #ifdef HAVE_GPM_H #define CHECK_BUTTON_DOWN(Mask,GpmBtn,InkBtn,InkDbl) \ if( ( iEventMask & Mask ) && ( Evt.buttons & GpmBtn ) ) \ { \ if( Evt.type & GPM_SINGLE ) \ return( InkBtn ); \ else if( Evt.type & GPM_DOUBLE || Evt.type & GPM_TRIPLE ) \ return( InkDbl ); \ } else if( hb_sln_UnderLinuxConsole && fCheckNew ) { Gpm_Event Evt; if( GetGpmEvent( &Evt ) ) { /* get the mouse event position */ s_iMouseRow = Evt.y; s_iMouseCol = Evt.x; if( ( Evt.type & GPM_MOVE ) && ( iEventMask & INKEY_MOVE ) ) return( K_MOUSEMOVE ); else if( Evt.type & GPM_DOWN ) { CHECK_BUTTON_DOWN(INKEY_LDOWN,GPM_B_LEFT,K_LBUTTONDOWN,K_LDBLCLK) else CHECK_BUTTON_DOWN(INKEY_RDOWN,GPM_B_RIGHT,K_RBUTTONDOWN,K_RDBLCLK) else CHECK_BUTTON_DOWN(INKEY_MMIDDLE,GPM_B_MIDDLE,K_MBUTTONDOWN,K_MDBLCLK) } else if( Evt.type & GPM_UP ) { if( ( iEventMask & INKEY_LUP ) && ( Evt.buttons & GPM_B_LEFT ) ) return( K_LBUTTONUP ); else if( ( iEventMask & INKEY_RUP ) && ( Evt.buttons & GPM_B_RIGHT ) ) return( K_RBUTTONUP ); else if( ( iEventMask & INKEY_MMIDDLE ) && ( Evt.buttons & GPM_B_MIDDLE ) ) return( K_MBUTTONUP ); } } } #else HB_SYMBOL_UNUSED( fCheckNew ); HB_SYMBOL_UNUSED( iEventMask ); #endif return 0; } /* *********************************************************************** */ void hb_gt_sln_mouse_Init( void ) { if( hb_sln_UnderXterm ) { char * SaveHilit = "\033[?1001s"; /* save old hilit tracking */ char * EnabTrack = "\033[?1000h"; /* enable mouse tracking */ /* force mouse usage under xterm */ (void)SLtt_set_mouse_mode( 1, 1 ); /* initial xterm settings */ SLtt_write_string( SaveHilit ); SLtt_write_string( EnabTrack ); SLtt_flush_output(); s_iMouseButtons = SLtt_tgetnum( "BT" ); /* force two buttons mouse under xterm */ if( s_iMouseButtons == -1 ) s_iMouseButtons = 2; s_bMousePresent = TRUE; } #ifdef HAVE_GPM_H else if( hb_sln_UnderLinuxConsole ) { #ifdef HB_GPM_NOICE_DISABLE int iNull, iErr; iErr = dup( 2 ); iNull = open( "/dev/null", O_RDWR ); dup2( iNull, 2 ); close( iNull ); #endif Conn.eventMask = GPM_MOVE | GPM_UP | GPM_DOWN | GPM_DRAG | GPM_DOUBLE; /* give me move events but handle them anyway */ Conn.defaultMask= GPM_MOVE | GPM_HARD; /* only pure mouse events, no Ctrl,Alt,Shft events */ Conn.minMod = 0; Conn.maxMod = 0; gpm_zerobased = 1; gpm_visiblepointer = 1; if( Gpm_Open( &Conn, 0 ) >= 0 && gpm_fd >= 0 ) { Gpm_Event Evt; s_bMousePresent = TRUE; while( GetGpmEvent( &Evt ) ); { s_iMouseRow = Evt.y; s_iMouseCol = Evt.x; } s_iMouseButtons = Gpm_GetSnapshot( NULL ); hb_gt_sln_mouse_FixTrash(); } #ifdef HB_GPM_NOICE_DISABLE dup2( iErr, 2 ); close( iErr ); #endif } #endif } /* *********************************************************************** */ void hb_gt_sln_mouse_Exit( void ) { if( s_bMousePresent ) { if( hb_sln_UnderXterm ) { char * DisabTrack = "\033[?1000l"; /* disable mouse tracking */ char * RestoHilit = "\033[?1001r"; /* restore old hilittracking */ /* restore xterm settings */ SLtt_write_string( DisabTrack ); SLtt_write_string( RestoHilit ); SLtt_flush_output(); /* force mouse usage under xterm */ (void)SLtt_set_mouse_mode( 0, 1 ); } #ifdef HAVE_GPM_H else if( hb_sln_UnderLinuxConsole ) { if( gpm_fd >= 0 ) Gpm_Close(); } #endif s_bMousePresent = FALSE; } } /* *********************************************************************** */ BOOL hb_gt_sln_mouse_IsPresent( void ) { return s_bMousePresent; } /* *********************************************************************** */ void hb_gt_sln_mouse_Show( void ) { #ifdef HAVE_GPM_H gpm_visiblepointer = 1; if( hb_sln_UnderLinuxConsole && s_bMousePresent ) Gpm_DrawPointer( s_iMouseCol, s_iMouseRow, gpm_consolefd ); #endif ; } /* *********************************************************************** */ void hb_gt_sln_mouse_Hide( void ) { #ifdef HAVE_GPM_H gpm_visiblepointer = 0; #endif ; } /* *********************************************************************** */ void hb_gt_sln_mouse_GetPos( int * piRow, int * piCol ) { *piRow = s_iMouseRow; *piCol = s_iMouseCol; } /* *********************************************************************** */ void hb_gt_sln_mouse_SetPos( int iRow, int iCol ) { /* it does really nothing */ s_iMouseRow = iRow; s_iMouseCol = iCol; #ifdef HAVE_GPM_H if( hb_sln_UnderLinuxConsole ) if( s_bMousePresent && gpm_visiblepointer ) Gpm_DrawPointer( iCol, iRow, gpm_consolefd ); #endif } /* *********************************************************************** */ BOOL hb_gt_sln_mouse_ButtonState( int iButton ) { switch( iButton ) { case 0: return ( s_usMouseState & M_BUTTON_LEFT ) != 0; case 1: return ( s_usMouseState & M_BUTTON_RIGHT ) != 0; case 2: return ( s_usMouseState & M_BUTTON_MIDDLE ) != 0; } return FALSE; } /* *********************************************************************** */ int hb_gt_sln_mouse_CountButton( void ) { return( s_iMouseButtons ); } /* *********************************************************************** */ void hb_gt_sln_mouse_FixTrash() { #ifdef HAVE_GPM_H if( hb_sln_UnderLinuxConsole ) if( s_bMousePresent && gpm_visiblepointer ) Gpm_DrawPointer( s_iMouseCol, s_iMouseRow, gpm_consolefd ); #endif } /* *********************************************************************** */