Files
harbour-core/harbour/source/rtl/gtwin/gtwin.c
2001-11-06 08:22:37 +00:00

1386 lines
42 KiB
C

/*
* $Id$
*/
/*
* Harbour Project source code:
* Video subsystem for Win32 compilers
*
* Copyright 1999-2000 Paul Tucker <ptucker@sympatico.ca>
* (for functions marked ptucker)
* 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.
*
*/
/*
* The following parts are Copyright of the individual authors.
* www - http://www.harbour-project.org
*
* Copyright 1999-2001 Viktor Szakats <viktor.szakats@syenar.hu>
* hb_gt_CtrlHandler()
*
* Copyright 1999 David G. Holm <dholm@jsd-llc.com>
* hb_gt_Tone()
* hb_gt_ReadKey()
*
* See doc/license.txt for licensing terms.
*
*/
/*
* Portions of this module are based (somewhat) on VIDMGR by
* Andrew Clarke and modified for the Harbour project
*/
/* NOTE: User programs should never call this layer directly! */
/* #define HB_DEBUG_KEYBOARD */
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define HB_OS_WIN_32_USED
#include <hbapigt.h>
#include <hbset.h> /* For Ctrl+Break handling */
#include <hbvm.h> /* For Ctrl+Break handling */
#include <hbinkey.ch>
#include <inkey.ch>
#if defined(__IBMCPP__)
#undef WORD /* 2 bytes unsigned */
typedef unsigned short int WORD;
#else
#if ! defined(HB_DONT_DEFINE_BASIC_TYPES)
#undef WORD /* 2 bytes unsigned */
typedef unsigned short int WORD;
#undef DWORD /* 4 bytes unsigned */
typedef unsigned long DWORD;
#endif
#endif
#if ! defined(__GNUC__) && defined(__CYGWIN__)
typedef WORD far * LPWORD;
#endif
#if defined(__RSXNT__)
#ifndef FROM_LEFT_1ST_BUTTON_PRESSED
#define FROM_LEFT_1ST_BUTTON_PRESSED 0x0001
#endif
#ifndef RIGHTMOST_BUTTON_PRESSED
#define RIGHTMOST_BUTTON_PRESSED 0x0002
#endif
#ifndef MOUSE_MOVED
#define MOUSE_MOVED 0x0001
#endif
#ifndef DOUBLE_CLICK
#define DOUBLE_CLICK 0x0002
#endif
#endif
#if 0
static HANDLE s_HOsave; /* work in progress */
static HANDLE s_HDOutput;
#endif
static HANDLE s_HOriginal;
static HANDLE s_HOutput;
static HANDLE s_HActive;
static HANDLE s_HInactive;
static HANDLE s_HInput;
static BOOL s_bOldCursor;
static BOOL s_bBreak;
static USHORT s_uiDispCount;
static CONSOLE_SCREEN_BUFFER_INFO s_csbi; /* to restore screen mode on exit */
#define INPUT_BUFFER_LEN 128
static DWORD s_cNumRead; /* Ok to use DWORD here, because this is specific... */
static DWORD s_cNumIndex; /* ...to the Windows API, which defines DWORD, etc. */
static INPUT_RECORD s_irInBuf[ INPUT_BUFFER_LEN ];
static int s_mouseLast; /* Last mouse button to be pressed */
extern int hb_mouse_iCol;
extern int hb_mouse_iRow;
static BOOL WINAPI hb_gt_CtrlHandler( DWORD dwCtrlType )
{
BOOL bHandled;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_CtrlHandler(%lu)", (unsigned long) dwCtrlType));
switch( dwCtrlType )
{
case CTRL_C_EVENT:
bHandled = FALSE;
break;
case CTRL_BREAK_EVENT:
s_bBreak = TRUE;
bHandled = TRUE;
break;
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
default:
bHandled = FALSE;
}
return bHandled;
}
void hb_gt_Init( int iFilenoStdin, int iFilenoStdout, int iFilenoStderr )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Init(): %d, %d, %d", iFilenoStdin, iFilenoStdout, iFilenoStderr));
HB_SYMBOL_UNUSED( iFilenoStdin );
HB_SYMBOL_UNUSED( iFilenoStdout );
HB_SYMBOL_UNUSED( iFilenoStderr );
#if 0
s_HOsave =
s_HDOutput = INVALID_HANDLE_VALUE;
#endif
s_cNumRead = 0;
s_cNumIndex = 0;
s_uiDispCount = 0;
s_bOldCursor = TRUE;
s_bBreak = FALSE;
/* Add Ctrl+Break handler [vszakats] */
SetConsoleCtrlHandler( hb_gt_CtrlHandler, TRUE );
if( ( s_HInput = GetStdHandle( STD_INPUT_HANDLE ) ) == INVALID_HANDLE_VALUE )
{
if( hb_dynsymFindName( "__DBGENTRY" ) ) /* the debugger is linked */
{
AllocConsole(); /* It is a Windows app without a console, so we create one */
s_HInput = GetStdHandle( STD_INPUT_HANDLE );
}
}
if( s_HInput != INVALID_HANDLE_VALUE )
SetConsoleMode( s_HInput, ENABLE_MOUSE_INPUT );
/* ptucker */
s_HOriginal = CreateFile( "CONOUT$", /* filename */
GENERIC_READ | GENERIC_WRITE, /* Access flag */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* share mode */
NULL, /* security attributes */
OPEN_EXISTING, /* create mode */
0, 0 );
s_HOutput = s_HOriginal;
s_HActive = s_HOutput;
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo( s_HOriginal, &csbi );
/* save screen info to restore on exit */
memcpy( &s_csbi, &csbi, sizeof( csbi ) );
csbi.srWindow.Right = HB_MIN( csbi.srWindow.Right, csbi.dwSize.X-1 );
csbi.srWindow.Bottom = HB_MIN( csbi.srWindow.Bottom, csbi.dwSize.Y-1 );
csbi.srWindow.Top = csbi.srWindow.Left = 0;
SetConsoleWindowInfo( s_HOriginal, TRUE, &csbi.srWindow );
SetConsoleScreenBufferSize( s_HOriginal, csbi.dwSize );
s_HInactive = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE, /* Access flag */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* Buffer share mode */
NULL, /* Security attribute */
CONSOLE_TEXTMODE_BUFFER, /* Type of buffer */
NULL ); /* reserved */
SetConsoleWindowInfo( s_HInactive, TRUE, &csbi.srWindow );
SetConsoleScreenBufferSize( s_HInactive, csbi.dwSize );
}
hb_mouse_Init();
/*
SetConsoleActiveScreenBuffer( s_HActive );
*/
}
void hb_gt_Exit( void )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Exit()"));
hb_mouse_Exit();
if( s_HOutput != s_HOriginal )
{
/* ptucker */
/* because the current screen may not be the one that was active
when the app started, we need to restore that screen and update
it with the current image before quitting.
*/
/* easy fix ;-) */
hb_gt_DispBegin();
hb_gt_DispEnd();
}
/* NOTE: There's no need to close these explicitly, moreover if we close them
functions using stdout will not show anything.
CloseHandle( s_HInput );
s_HInput = INVALID_HANDLE_VALUE;
CloseHandle( s_HOutput );
s_HOutput = INVALID_HANDLE_VALUE;
*/
SetConsoleScreenBufferSize( s_HOriginal, s_csbi.dwSize );
SetConsoleWindowInfo( s_HOriginal, FALSE, &s_csbi.srWindow );
/* detected using NuMega BoundsChecker */
CloseHandle( s_HOriginal );
s_HOriginal = INVALID_HANDLE_VALUE;
CloseHandle( s_HInactive );
s_HInactive = INVALID_HANDLE_VALUE;
/* Remove Ctrl+Break handler [vszakats] */
SetConsoleCtrlHandler( hb_gt_CtrlHandler, FALSE );
}
static int StdFnKeys( WORD wKey, BOOL bEnhanced )
{
int ch;
/* Normal function key */
ch = wKey + HB_INKEY_NONE;
if( bEnhanced ) ch += HB_INKEY_ENHANCED;
return ch;
}
static int IgnoreKeyCodes( int wKey )
{
int ignore = 0;
switch( wKey )
{
/* Virtual scan codes to ignore */
case 29: /* Ctrl */
case 40: /* Circle Accent */
case 41: /* Tick Accent */
case 42: /* Left Shift */
case 43: /* Reverse Tick Accent */
case 54: /* Right Shift */
case 56: /* Alt */
case 58: /* Caps Lock */
case 69: /* Num Lock */
case 70: /* Pause or Scroll Lock */
ignore = -1;
}
return ignore;
}
int hb_gt_ExtendedKeySupport()
{
return 1;
}
int hb_gt_ReadKey( HB_inkey_enum eventmask )
{
int ch = 0, extended = 0;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_ReadKey(%d)", (int) eventmask));
/* First check for Ctrl+Break, which is handled by gt/gtwin.c */
if( s_bBreak )
{
/* Reset the global Ctrl+Break flag */
s_bBreak = FALSE;
ch = HB_BREAK_FLAG; /* Indicate that Ctrl+Break was pressed */
}
/* Check for events only when the event buffer is exhausted. */
else if( s_cNumRead <= s_cNumIndex )
{
/* Check for keyboard input */
s_cNumRead = 0;
GetNumberOfConsoleInputEvents( s_HInput, &s_cNumRead );
if( s_cNumRead )
{
/* Read keyboard input */
ReadConsoleInput(
s_HInput, /* input buffer handle */
s_irInBuf, /* buffer to read into */
INPUT_BUFFER_LEN, /* size of read buffer */
&s_cNumRead); /* number of records read */
/* Set up to process the first input event */
s_cNumIndex = 0;
}
}
/* Only process one keyboard event at a time. */
if( s_cNumRead > s_cNumIndex )
{
if( s_irInBuf[ s_cNumIndex ].EventType == KEY_EVENT )
{
/* Only process key down events */
if( s_irInBuf[ s_cNumIndex ].Event.KeyEvent.bKeyDown )
{
/* Save the keyboard state and ASCII key code */
DWORD dwState = s_irInBuf[ s_cNumIndex ].Event.KeyEvent.dwControlKeyState;
WORD wChar = s_irInBuf[ s_cNumIndex ].Event.KeyEvent.wVirtualKeyCode;
WORD wKey = s_irInBuf[ s_cNumIndex ].Event.KeyEvent.wVirtualScanCode;
ch = s_irInBuf[ s_cNumIndex ].Event.KeyEvent.uChar.AsciiChar;
#ifdef HB_DEBUG_KEYBOARD
/* if( dwState & ENHANCED_KEY ) ch = -32; */
fprintf( stdout, "\n\nhb_gt_ReadKey(): dwState is %ld, wChar is %d, wKey is %d, ch is %d", dwState, wChar, wKey, ch );
if( dwState & CAPSLOCK_ON ) fprintf( stdout, " CL" );
if( dwState & ENHANCED_KEY ) fprintf( stdout, " EK" );
if( dwState & LEFT_ALT_PRESSED ) fprintf( stdout, " LA" );
if( dwState & RIGHT_ALT_PRESSED ) fprintf( stdout, " RA" );
if( dwState & LEFT_CTRL_PRESSED ) fprintf( stdout, " LC" );
if( dwState & RIGHT_CTRL_PRESSED ) fprintf( stdout, " RC" );
if( dwState & NUMLOCK_ON ) fprintf( stdout, " NL" );
if( dwState & SCROLLLOCK_ON ) fprintf( stdout, " SL" );
if( dwState & SHIFT_PRESSED ) fprintf( stdout, " SH" );
fprintf( stdout, " " );
#endif
if( ch == 224 )
{
/* Strip extended key lead-in codes */
ch = 0;
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "-" );
#endif
}
else if( ch < 0 && ch != -32 && ch != -16 && !IgnoreKeyCodes( wKey ) )
{
/* Process international key codes */
ch += 256;
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "+" );
#endif
}
else if( ch < 0 && ch != -32 && ch != -16 )
{
/* Ignore any negative character codes that didn't get handled
by the international keyboard processing and don't signify
extended key codes */
ch = 0;
}
else
{
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "0" );
#endif
if( ( ( ch == 0 || ch == -32 || ch == -16 ) && ( dwState & ( SHIFT_PRESSED | LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED ) ) )
|| ( ( dwState & ( ENHANCED_KEY | LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED ) ) ) )
{
extended = 1;
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "1" );
#endif
}
else if( ch == 0 )
{
if( eventmask & INKEY_RAW )
{
extended = 1;
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "2" );
#endif
}
else if( IgnoreKeyCodes( wKey ) )
{
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "!" );
#endif
}
else
{
ch = StdFnKeys( wKey, 0 );
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "3" );
#endif
}
}
}
if( extended )
{
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "4" );
#endif
/* Process non-ASCII key codes */
if( eventmask & INKEY_RAW ) wKey = wChar;
/* Discard standalone state key presses for normal mode only */
if( ( eventmask & INKEY_RAW ) == 0 && IgnoreKeyCodes( wKey ) )
{
wKey = 0;
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "5" );
#endif
}
if( wKey == 0 ) ch = 0;
else
{
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "6" );
#endif
if( eventmask & INKEY_RAW )
{
/* Pass along all virtual key codes with all
enhanced and state indicators accounted for */
wKey += 256;
if( dwState & ENHANCED_KEY ) wKey += 512;
if( dwState & SHIFT_PRESSED ) wKey += 1024;
if( dwState & LEFT_CTRL_PRESSED ) wKey += 2048;
if( dwState & RIGHT_CTRL_PRESSED ) wKey += 4096;
if( dwState & LEFT_ALT_PRESSED ) wKey += 8192;
if( dwState & RIGHT_ALT_PRESSED ) wKey += 16384;
ch = wKey;
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "7" );
#endif
}
else
{
/* Translate virtual scan codes to Clipper codes */
BOOL bAlt = dwState & ( LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED );
BOOL bCtrl = dwState & ( LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED );
BOOL bShift = dwState & SHIFT_PRESSED;
BOOL bAltGr = ( dwState & ( LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED ) ) == ( LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED );
BOOL bEnhanced = dwState & ENHANCED_KEY;
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "8" );
#endif
HB_TRACE(HB_TR_INFO, ("hb_gt_ReadKey(): wKey is %d, dwState is %d, ch is %d", wKey, dwState, ch));
if( bAlt )
{
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "9" );
#endif
/* Alt key held */
if( bAltGr && ch ) { /* It's actually Alt+Gr */ }
else
{
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "a" );
#endif
ch = wKey + HB_INKEY_ALT;
if( bEnhanced ) ch += HB_INKEY_ENHANCED;
}
}
else if( bCtrl )
{
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "b" );
#endif
/* Ctrl key held */
if( ch == 0 || bEnhanced ) ch = wKey + HB_INKEY_CTRL;
if( bEnhanced ) ch += HB_INKEY_ENHANCED;
}
else if( bShift )
{
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "c" );
#endif
/* Shift key held */
if( ch == 0 || bEnhanced ) ch = wKey + HB_INKEY_SHIFT;
if( bEnhanced ) ch += HB_INKEY_ENHANCED;
}
else
{
#ifdef HB_DEBUG_KEYBOARD
fprintf( stdout, "d" );
#endif
ch = StdFnKeys( wKey, bEnhanced );
}
}
}
}
#if 0
/* Debug code: */
else
{
WORD wKey;
if( eventmask & INKEY_RAW )
wKey = s_irInBuf[ s_cNumIndex ].Event.KeyEvent.wVirtualKeyCode;
else
wKey = s_irInBuf[ s_cNumIndex ].Event.KeyEvent.wVirtualScanCode;
HB_TRACE(HB_TR_INFO, ("hb_gt_ReadKey(): wKey is %d", wKey));
}
#endif
}
}
else if( eventmask & ~( INKEY_KEYBOARD | INKEY_RAW )
&& s_irInBuf[ s_cNumIndex ].EventType == MOUSE_EVENT )
{
hb_mouse_iCol = s_irInBuf[ s_cNumIndex ].Event.MouseEvent.dwMousePosition.X;
hb_mouse_iRow = s_irInBuf[ s_cNumIndex ].Event.MouseEvent.dwMousePosition.Y;
if( eventmask & INKEY_MOVE && s_irInBuf[ s_cNumIndex ].Event.MouseEvent.dwEventFlags == MOUSE_MOVED )
ch = K_MOUSEMOVE;
else if( eventmask & INKEY_LDOWN && s_irInBuf[ s_cNumIndex ].Event.MouseEvent.dwButtonState &
FROM_LEFT_1ST_BUTTON_PRESSED )
{
if( s_irInBuf[ s_cNumIndex ].Event.MouseEvent.dwEventFlags == DOUBLE_CLICK )
ch = K_LDBLCLK;
else
ch = K_LBUTTONDOWN;
s_mouseLast = K_LBUTTONDOWN;
}
else if( eventmask & INKEY_RDOWN && s_irInBuf[ s_cNumIndex ].Event.MouseEvent.dwButtonState &
RIGHTMOST_BUTTON_PRESSED )
{
if( s_irInBuf[ s_cNumIndex ].Event.MouseEvent.dwEventFlags == DOUBLE_CLICK )
ch = K_RDBLCLK;
else
ch = K_RBUTTONDOWN;
s_mouseLast = K_RBUTTONDOWN;
}
else if( s_irInBuf[ s_cNumIndex ].Event.MouseEvent.dwEventFlags == 0 &&
s_irInBuf[ s_cNumIndex ].Event.MouseEvent.dwButtonState == 0 )
{
if( eventmask & INKEY_LUP && s_mouseLast == K_LBUTTONDOWN )
ch = K_LBUTTONUP;
else if( eventmask & INKEY_RUP && s_mouseLast == K_RBUTTONDOWN )
ch = K_RBUTTONUP;
}
}
/* Set up to process the next input event (if any) */
s_cNumIndex++;
}
return ch;
}
BOOL hb_gt_AdjustPos( BYTE * pStr, ULONG ulLen )
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_AdjustPos(%s, %lu)", pStr, ulLen ));
HB_SYMBOL_UNUSED( pStr );
HB_SYMBOL_UNUSED( ulLen );
GetConsoleScreenBufferInfo( s_HActive, &csbi );
hb_gt_SetPos( csbi.dwCursorPosition.Y, csbi.dwCursorPosition.X, HB_GT_SET_POS_AFTER );
return TRUE;
}
BOOL hb_gt_IsColor( void )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_IsColor()"));
/* TODO: need to call something to do this instead of returning TRUE */
return TRUE;
}
USHORT hb_gt_GetScreenWidth( void )
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_GetScreenWidth()"));
GetConsoleScreenBufferInfo( s_HOutput, &csbi );
/* return csbi.dwMaximumWindowSize.X; */
/* return HB_MAX( csbi.srWindow.Right - csbi.srWindow.Left + 1, 40 ); */
return HB_MAX( csbi.dwSize.X, 40 );
}
USHORT hb_gt_GetScreenHeight( void )
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_GetScreenHeight()"));
GetConsoleScreenBufferInfo( s_HOutput, &csbi );
/* return csbi.dwMaximumWindowSize.Y; */
/* return HB_MAX( csbi.srWindow.Bottom - csbi.srWindow.Top + 1, 25 ); */
return HB_MAX( csbi.dwSize.Y, 25 );
}
void hb_gt_SetPos( SHORT iRow, SHORT iCol, SHORT iMethod )
{
COORD dwCursorPosition;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_SetPos(%hd, %hd, %hd)", iRow, iCol, iMethod));
HB_SYMBOL_UNUSED( iMethod );
dwCursorPosition.X = iCol;
dwCursorPosition.Y = iRow;
SetConsoleCursorPosition( s_HActive, dwCursorPosition );
}
USHORT hb_gt_GetCursorStyle( void )
{
CONSOLE_CURSOR_INFO cci;
USHORT uiCursorShape;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_GetCursorStyle()"));
GetConsoleCursorInfo( s_HActive, &cci );
if( ! cci.bVisible )
{
uiCursorShape = SC_NONE;
}
else
{
switch( cci.dwSize )
{
case 50:
uiCursorShape = SC_INSERT; /* half block in clipper */
break;
case 99:
uiCursorShape = SC_SPECIAL1; /* full block in clipper */
break;
case 66:
uiCursorShape = SC_SPECIAL2; /* upper half block in clipper */
break;
/* TODO: cannot tell if the block is upper or lower for cursor */
/* Answer: Supposed to be upper third, but ms don't support it. */
default:
uiCursorShape = SC_NORMAL; /* anything else, we'll call it normal */
break;
}
}
return uiCursorShape;
}
void hb_gt_SetCursorStyle( USHORT style )
{
CONSOLE_CURSOR_INFO cci;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_SetCursorStyle(%hu)", style));
GetConsoleCursorInfo( s_HActive, &cci );
switch( style )
{
case SC_NONE:
cci.bVisible = FALSE;
break;
case SC_INSERT:
cci.bVisible = TRUE;
cci.dwSize = 50;
break;
case SC_SPECIAL1:
cci.bVisible = TRUE;
cci.dwSize = 99;
break;
case SC_SPECIAL2:
cci.bVisible = TRUE;
cci.dwSize = 66;
/* In their infinite wisdom, MS doesn't support cursors that
don't start at the bottom of the cell */
break;
case SC_NORMAL:
default: /* traps for invalid values */
cci.bVisible = TRUE;
cci.dwSize = 25; /* this was 12, but when used in full screen dos window
cursor state is erratic - doesn't turn off, etc. */
break;
}
s_bOldCursor = cci.bVisible;
SetConsoleCursorInfo( s_HActive, &cci );
}
static void hb_gt_xPutch( USHORT uiRow, USHORT uiCol, BYTE attr, BYTE byChar )
{
DWORD dwWritten;
COORD coord;
char tmp[ 2 ];
HB_TRACE(HB_TR_DEBUG, ("hb_gt_xPutch(%hu, %hu, %d, %i)", uiRow, uiCol, (int) attr, byChar));
/* TOFIX: add correct support for a single byte instead of a string
*/
tmp[ 0 ] = byChar;
tmp[ 1 ] = '\0';
coord.X = ( SHORT ) uiCol;
coord.Y = ( SHORT ) uiRow;
FillConsoleOutputAttribute( s_HOutput, ( WORD )( attr & 0xFF ), ( DWORD ) 1, coord, &dwWritten );
WriteConsoleOutputCharacterA( s_HOutput, tmp, 1, coord, &dwWritten );
}
void hb_gt_Puts( USHORT uiRow, USHORT uiCol, BYTE attr, BYTE * str, ULONG len )
{
DWORD dwWritten;
COORD coord;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Puts(%hu, %hu, %d, %p, %lu)", uiRow, uiCol, (int) attr, str, len));
coord.X = ( SHORT ) uiCol;
coord.Y = ( SHORT ) uiRow;
FillConsoleOutputAttribute( s_HOutput, ( WORD )( attr & 0xFF ), ( DWORD ) len, coord, &dwWritten );
WriteConsoleOutputCharacterA( s_HOutput, ( char * ) str, ( DWORD ) len, coord, &dwWritten );
}
int hb_gt_RectSize( USHORT rows, USHORT cols )
{
return rows * cols * 2;
}
void hb_gt_GetText( USHORT uiTop, USHORT uiLeft, USHORT uiBottom, USHORT uiRight, BYTE * dest )
{
LPWORD pwattr;
BYTE * pstr;
USHORT width;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_GetText(%hu, %hu, %hu, %hu, %p)", uiTop, uiLeft, uiBottom, uiRight, dest));
width = ( uiRight - uiLeft + 1 );
pwattr = ( LPWORD ) hb_xgrab( width * sizeof( *pwattr ) );
pstr = ( BYTE * ) hb_xgrab( width );
for( ; uiTop <= uiBottom; uiTop++ )
{
COORD coord;
USHORT i;
DWORD dwWritten;
coord.X = ( SHORT ) uiLeft;
coord.Y = ( SHORT ) uiTop;
ReadConsoleOutputCharacterA( s_HOutput, ( char * ) pstr, width, coord, &dwWritten );
ReadConsoleOutputAttribute( s_HOutput, pwattr, width, coord, &dwWritten );
for( i = 0; i < width; i++ )
{
*dest = *( pstr + i );
dest++;
*dest = ( BYTE ) *( pwattr + i ) & 0xFF;
dest++;
}
}
hb_xfree( pstr );
hb_xfree( pwattr );
}
void hb_gt_PutText( USHORT uiTop, USHORT uiLeft, USHORT uiBottom, USHORT uiRight, BYTE * srce )
{
LPWORD pwattr;
BYTE * pstr;
USHORT width;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_PutText(%hu, %hu, %hu, %hu, %p)", uiTop, uiLeft, uiBottom, uiRight, srce));
width = ( uiRight - uiLeft + 1 );
pwattr = ( LPWORD ) hb_xgrab( width * sizeof( *pwattr ) );
pstr = ( BYTE * ) hb_xgrab( width );
for( ; uiTop <= uiBottom; uiTop++ )
{
COORD coord;
USHORT i;
DWORD dwWritten;
for( i = 0; i < width; i++ )
{
*( pstr + i ) = *srce;
srce++;
*( pwattr + i ) = ( ( WORD )( ( BYTE ) *srce ) & 0xFF );
srce++;
}
coord.X = ( SHORT ) uiLeft;
coord.Y = ( SHORT ) uiTop;
WriteConsoleOutputAttribute( s_HOutput, pwattr, width, coord, &dwWritten );
WriteConsoleOutputCharacterA( s_HOutput, ( char * ) pstr, width, coord, &dwWritten );
}
hb_xfree( pstr );
hb_xfree( pwattr );
}
void hb_gt_SetAttribute( USHORT uiTop, USHORT uiLeft, USHORT uiBottom, USHORT uiRight, BYTE attr )
{
/* ptucker */
COORD coord;
USHORT width;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_SetAttribute(%hu, %hu, %hu, %hu, %d)", uiTop, uiLeft, uiBottom, uiRight, (int) attr));
width = uiRight - uiLeft + 1;
coord.X = ( SHORT ) uiLeft;
for( ; uiTop <= uiBottom; uiTop++ )
{
DWORD dwWritten;
coord.Y = uiTop;
FillConsoleOutputAttribute( s_HOutput, ( WORD )( attr & 0xFF ), width, coord, &dwWritten );
}
}
SHORT hb_gt_Col( void )
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Col()"));
GetConsoleScreenBufferInfo( s_HActive, &csbi );
return csbi.dwCursorPosition.X;
}
SHORT hb_gt_Row( void )
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Row()"));
GetConsoleScreenBufferInfo( s_HActive, &csbi );
return csbi.dwCursorPosition.Y;
}
void hb_gt_Scroll( USHORT uiTop, USHORT uiLeft, USHORT uiBottom, USHORT uiRight, BYTE attr, SHORT iVert, SHORT iHoriz )
{
/* ptucker */
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Scroll(%hu, %hu, %hu, %hu, %d, %hd, %hd)", uiTop, uiLeft, uiBottom, uiRight, (int) attr, iVert, iHoriz));
if( ( iHoriz | iVert ) == 0 ) /* both zero? */
{
COORD coord;
USHORT width = uiRight - uiLeft + 1;
coord.X = ( SHORT ) uiLeft;
for( ; uiTop <= uiBottom; uiTop++ )
{
DWORD dwWritten;
coord.Y = uiTop;
FillConsoleOutputAttribute( s_HOutput, ( WORD )( attr & 0xFF ), width, coord, &dwWritten );
FillConsoleOutputCharacter( s_HOutput, ' ', width, coord, &dwWritten );
}
}
else
{
SMALL_RECT Source, Clip;
COORD Target;
CHAR_INFO FillChar;
Source.Top = uiTop;
Source.Left = uiLeft;
Source.Bottom = uiBottom;
Source.Right = uiRight;
memcpy( &Clip, &Source, sizeof( SMALL_RECT ) );
Target.Y = uiTop - iVert;
Target.X = uiLeft - iHoriz;
FillChar.Char.AsciiChar = ' ';
FillChar.Attributes = ( WORD )( attr & 0xFF );
ScrollConsoleScreenBuffer( s_HOutput, &Source, &Clip, Target, &FillChar );
}
}
void hb_gt_DispBegin( void )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_DispBegin()"));
/* ptucker */
if( ++s_uiDispCount == 1 )
{
COORD coDest = { 0, 0 };
COORD coBuf; /* the size of the buffer to read into */
CHAR_INFO * pCharInfo; /* buffer to store info from ReadConsoleOutput */
SMALL_RECT srWin; /* source rectangle to read from */
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo( s_HOutput, &csbi );
srWin.Top = srWin.Left = 0;
srWin.Bottom = ( coBuf.Y = csbi.dwSize.Y ) - 1;
srWin.Right = ( coBuf.X = csbi.dwSize.X ) - 1;
/* allocate a buffer for the screen rectangle */
pCharInfo = ( CHAR_INFO * ) hb_xgrab( coBuf.Y * coBuf.X * sizeof( CHAR_INFO ) );
/* read the screen rectangle into the buffer */
ReadConsoleOutput( s_HOutput, /* current screen handle */
pCharInfo, /* transfer area */
coBuf, /* size of destination buffer */
coDest, /* upper-left cell to write data to */
&srWin ); /* screen buffer rectangle to read from */
WriteConsoleOutput( s_HInactive, /* output handle */
pCharInfo, /* data to write */
coBuf, /* col/row size of source buffer */
coDest, /* upper-left cell to write data from in src */
&srWin ); /* screen buffer rect to write data to */
s_HOutput = s_HInactive;
{
CONSOLE_CURSOR_INFO cci;
GetConsoleCursorInfo( s_HActive, &cci );
s_bOldCursor = cci.bVisible;
cci.bVisible = FALSE;
SetConsoleCursorInfo( s_HActive, &cci );
}
hb_xfree( pCharInfo );
}
}
void hb_gt_DispEnd( void )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_DispEnd()"));
/* ptucker */
if( --s_uiDispCount == 0 )
{
s_HInactive = s_HActive;
s_HActive = s_HOutput;
SetConsoleActiveScreenBuffer( s_HActive );
{
CONSOLE_CURSOR_INFO cci;
GetConsoleCursorInfo( s_HActive, &cci );
cci.bVisible = s_bOldCursor;
SetConsoleCursorInfo( s_HActive, &cci );
}
}
}
BOOL hb_gt_SetMode( USHORT uiRows, USHORT uiCols )
{
/* ptucker */
BOOL bRetVal = TRUE;
CONSOLE_SCREEN_BUFFER_INFO csbi;
SMALL_RECT srWin;
COORD coBuf;
USHORT uiDispCount = s_uiDispCount;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_SetMode(%hu, %hu)", uiRows, uiCols));
while( s_uiDispCount )
hb_gt_DispEnd();
GetConsoleScreenBufferInfo( s_HOutput, &csbi );
coBuf = GetLargestConsoleWindowSize( s_HOutput );
/* new console window size and scroll position */
srWin.Top = srWin.Left = 0;
srWin.Bottom = ( SHORT ) ( HB_MIN( uiRows, coBuf.Y ) - 1 );
srWin.Right = ( SHORT ) ( HB_MIN( uiCols, coBuf.X ) - 1 );
/* new console buffer size */
coBuf.Y = uiRows;
coBuf.X = uiCols;
/* if the current buffer is larger than what we want, resize the */
/* console window first, then the buffer */
if( ( DWORD ) csbi.dwSize.X * csbi.dwSize.Y > ( DWORD ) uiCols * uiRows )
{
/* TODO: these calls are a temporary solution */
SetConsoleWindowInfo( s_HActive, TRUE, &srWin );
SetConsoleScreenBufferSize( s_HActive, coBuf );
SetConsoleWindowInfo( s_HInactive, TRUE, &srWin );
SetConsoleScreenBufferSize( s_HInactive, coBuf );
if( !SetConsoleWindowInfo( s_HOutput, TRUE, &srWin ) ||
!SetConsoleScreenBufferSize( s_HOutput, coBuf ) )
bRetVal = FALSE;
}
else if( ( DWORD ) csbi.dwSize.X * csbi.dwSize.Y < ( DWORD ) uiCols * uiRows )
{
/* TODO: these calls are a temporary solution */
SetConsoleScreenBufferSize( s_HActive, coBuf );
SetConsoleWindowInfo( s_HActive, TRUE, &srWin );
SetConsoleScreenBufferSize( s_HInactive, coBuf );
SetConsoleWindowInfo( s_HInactive, TRUE, &srWin );
if( !SetConsoleScreenBufferSize( s_HOutput, coBuf ) ||
!SetConsoleWindowInfo( s_HOutput, TRUE, &srWin ) )
bRetVal = FALSE;
}
while( s_uiDispCount < uiDispCount )
hb_gt_DispBegin();
return bRetVal;
}
void hb_gt_Replicate( USHORT uiRow, USHORT uiCol, BYTE byAttr, BYTE byChar, ULONG ulLength )
{
/* ptucker */
COORD coBuf;
DWORD dwWritten;
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Replicate(%hu, %hu, %i, %i, %lu)", uiRow, uiCol, byAttr, byChar, ulLength));
coBuf.Y = uiRow;
coBuf.X = uiCol;
FillConsoleOutputAttribute( s_HOutput, ( WORD )( byAttr & 0xFF ), ( DWORD )ulLength, coBuf, &dwWritten );
FillConsoleOutputCharacter(
s_HOutput, /* handle to screen buffer */
byChar, /* character to write */
( DWORD ) ulLength, /* number of cells to write */
coBuf, /* coordinates of first cell */
&dwWritten /* receives actual number written */
);
}
BOOL hb_gt_GetBlink()
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_GetBlink()"));
/* TODO */
return FALSE;
}
void hb_gt_SetBlink( BOOL bBlink )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_SetBlink(%d)", (int) bBlink));
/* TODO: set the bit if it's supported */
HB_SYMBOL_UNUSED( bBlink );
}
#if 0
static void hb_gt_DebugScreen( BOOL bActivate )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_DebugScreen(%d)", (int) bActivate));
/* ptucker */
/* TODO: This is not used and is still a work in progress */
if( bActivate )
{
if( s_HDOutput == INVALID_HANDLE_VALUE )
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
SMALL_RECT srWin;
s_HDOutput = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE, /* Access flag */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* Buffer share mode */
NULL, /* Security attribute */
CONSOLE_TEXTMODE_BUFFER, /* Type of buffer */
NULL ); /* reserved */
GetConsoleScreenBufferInfo( s_HOutput, &csbi );
/* new console window size and scroll position */
srWin.Top = srWin.Left = 0;
srWin.Bottom = csbi.dwSize.Y - 1;
srWin.Right = csbi.dwSize.X - 1;
SetConsoleScreenBufferSize( s_HDOutput, csbi.dwSize );
SetConsoleWindowInfo( s_HDOutput, TRUE, &csbi.srWindow );
SetConsoleWindowInfo( s_HDOutput, FALSE, &srWin );
}
s_HOsave = s_HOutput;
s_HOutput = s_HActive = s_HDOutput;
hb_gt_DispBegin();
hb_gt_DispEnd();
}
else
{
s_HOutput = s_HOsave;
s_HActive = s_HOriginal;
}
SetConsoleActiveScreenBuffer( s_HOutput );
}
#endif
void hb_gt_Tone( double dFrequency, double dDuration )
{
HB_TRACE(HB_TR_DEBUG, ("hb_gt_Tone(%lf, %lf)", dFrequency, dDuration));
/* The conversion from Clipper timer tick units to
milliseconds is * 1000.0 / 18.2. */
dDuration = dDuration * 1000.0 / 18.2; /* milliseconds */
dDuration = HB_MIN( HB_MAX( 0, dDuration ), ULONG_MAX );
if( dDuration > 0.0 ) {
/* Bad news for non-NT Windows platforms: Beep() ignores
both parameters and either generates the default sound
event or the standard system beep. */
Beep( ( ULONG ) HB_MIN( HB_MAX( 0.0, dFrequency ), 32767.0 ),
( ULONG ) dDuration );
}
}
char * hb_gt_Version( void )
{
return "Harbour Terminal: Win32 console";
}
USHORT hb_gt_DispCount()
{
return s_uiDispCount;
}
USHORT hb_gt_Box( SHORT Top, SHORT Left, SHORT Bottom, SHORT Right,
BYTE * szBox, BYTE byAttr )
{
USHORT ret = 1;
SHORT Row;
SHORT Col;
SHORT Height;
SHORT Width;
if( Left >= 0 || Left < hb_gt_GetScreenWidth()
|| Right >= 0 || Right < hb_gt_GetScreenWidth()
|| Top >= 0 || Top < hb_gt_GetScreenHeight()
|| Bottom >= 0 || Bottom < hb_gt_GetScreenHeight() )
{
/* Ensure that box is drawn from top left to bottom right. */
if( Top > Bottom )
{
SHORT tmp = Top;
Top = Bottom;
Bottom = tmp;
}
if( Left > Right )
{
SHORT tmp = Left;
Left = Right;
Right = tmp;
}
/* Draw the box or line as specified */
Height = Bottom - Top + 1;
Width = Right - Left + 1;
hb_gt_DispBegin();
if( Height > 1 && Width > 1 && Top >= 0 && Top < hb_gt_GetScreenHeight() && Left >= 0 && Left < hb_gt_GetScreenWidth() )
hb_gt_xPutch( Top, Left, byAttr, szBox[ 0 ] ); /* Upper left corner */
Col = ( Height > 1 ? Left + 1 : Left );
if(Col < 0 )
{
Width += Col;
Col = 0;
}
if( Right >= hb_gt_GetScreenWidth() )
{
Width -= Right - hb_gt_GetScreenWidth();
}
if( Col <= Right && Col < hb_gt_GetScreenWidth() && Top >= 0 && Top < hb_gt_GetScreenHeight() )
hb_gt_Replicate( Top, Col, byAttr, szBox[ 1 ], Width + ( (Right - Left) > 1 ? -2 : 0 ) ); /* Top line */
if( Height > 1 && (Right - Left) > 1 && Right < hb_gt_GetScreenWidth() && Top >= 0 && Top < hb_gt_GetScreenHeight() )
hb_gt_xPutch( Top, Right, byAttr, szBox[ 2 ] ); /* Upper right corner */
if( szBox[ 8 ] && Height > 2 && Width > 2 )
{
for( Row = Top + 1; Row < Bottom; Row++ )
{
if( Row >= 0 && Row < hb_gt_GetScreenHeight() )
{
Col = Left;
if( Col < 0 )
Col = 0; /* The width was corrected earlier. */
else
hb_gt_xPutch( Row, Col++, byAttr, szBox[ 7 ] ); /* Left side */
hb_gt_Replicate( Row, Col, byAttr, szBox[ 8 ], Width - 2 ); /* Fill */
if( Right < hb_gt_GetScreenWidth() )
hb_gt_xPutch( Row, Right, byAttr, szBox[ 3 ] ); /* Right side */
}
}
}
else
{
for( Row = ( Width > 1 ? Top + 1 : Top ); Row < ( (Right - Left ) > 1 ? Bottom : Bottom + 1 ); Row++ )
{
if( Row >= 0 && Row < hb_gt_GetScreenHeight() )
{
if( Left >= 0 && Left < hb_gt_GetScreenWidth() )
hb_gt_xPutch( Row, Left, byAttr, szBox[ 7 ] ); /* Left side */
if( ( Width > 1 || Left < 0 ) && Right < hb_gt_GetScreenWidth() )
hb_gt_xPutch( Row, Right, byAttr, szBox[ 3 ] ); /* Right side */
}
}
}
if( Height > 1 && Width > 1 )
{
if( Left >= 0 && Bottom < hb_gt_GetScreenHeight() )
hb_gt_xPutch( Bottom, Left, byAttr, szBox[ 6 ] ); /* Bottom left corner */
Col = Left + 1;
if( Col < 0 )
Col = 0; /* The width was corrected earlier. */
if( Col <= Right && Bottom < hb_gt_GetScreenHeight() )
hb_gt_Replicate( Bottom, Col, byAttr, szBox[ 5 ], Width - 2 ); /* Bottom line */
if( Right < hb_gt_GetScreenWidth() && Bottom < hb_gt_GetScreenHeight() )
hb_gt_xPutch( Bottom, Right, byAttr, szBox[ 4 ] ); /* Bottom right corner */
}
hb_gt_DispEnd();
ret = 0;
}
return ret;
}
USHORT hb_gt_BoxD( SHORT Top, SHORT Left, SHORT Bottom, SHORT Right, BYTE * pbyFrame, BYTE byAttr )
{
return hb_gt_Box( Top, Left, Bottom, Right, pbyFrame, byAttr );
}
USHORT hb_gt_BoxS( SHORT Top, SHORT Left, SHORT Bottom, SHORT Right, BYTE * pbyFrame, BYTE byAttr )
{
return hb_gt_Box( Top, Left, Bottom, Right, pbyFrame, byAttr );
}
USHORT hb_gt_HorizLine( SHORT Row, SHORT Left, SHORT Right, BYTE byChar, BYTE byAttr )
{
USHORT ret = 1;
if( Row >= 0 && Row < hb_gt_GetScreenHeight() )
{
if( Left < 0 )
Left = 0;
else if( Left >= hb_gt_GetScreenWidth() )
Left = hb_gt_GetScreenWidth() - 1;
if( Right < 0 )
Right = 0;
else if( Right >= hb_gt_GetScreenWidth() )
Right = hb_gt_GetScreenWidth() - 1;
if( Left < Right )
hb_gt_Replicate( Row, Left, byAttr, byChar, Right - Left + 1 );
else
hb_gt_Replicate( Row, Right, byAttr, byChar, Left - Right + 1 );
ret = 0;
}
return ret;
}
USHORT hb_gt_VertLine( SHORT Col, SHORT Top, SHORT Bottom, BYTE byChar, BYTE byAttr )
{
USHORT ret = 1;
USHORT Row;
if( Col >= 0 && Col < hb_gt_GetScreenWidth() )
{
if( Top < 0 )
Top = 0;
else if( Top >= hb_gt_GetScreenHeight() )
Top = hb_gt_GetScreenHeight() - 1;
if( Bottom < 0 )
Bottom = 0;
else if( Bottom >= hb_gt_GetScreenHeight() )
Bottom = hb_gt_GetScreenHeight() - 1;
if( Top <= Bottom )
Row = Top;
else
{
Row = Bottom;
Bottom = Top;
}
while( Row <= Bottom )
hb_gt_xPutch( Row++, Col, byAttr, byChar );
ret = 0;
}
return ret;
}
BOOL hb_gt_PreExt()
{
return TRUE;
}
BOOL hb_gt_PostExt()
{
return TRUE;
}
BOOL hb_gt_Suspend()
{
return TRUE;
}
BOOL hb_gt_Resume()
{
return TRUE;
}