1265 lines
45 KiB
C
1265 lines
45 KiB
C
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* Harbour Project source code:
|
|
* The Keyboard API
|
|
*
|
|
* Copyright 1999 David G. Holm <dholm@jsd-llc.com>
|
|
* 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 of the License, or
|
|
* (at your option) any later version, with one exception:
|
|
*
|
|
* The exception is that if you link the Harbour Runtime Library (HRL)
|
|
* and/or the Harbour Virtual Machine (HVM) 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 HRL
|
|
* and/or HVM code into it.
|
|
*
|
|
* 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 program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
|
|
* their web site at http://www.gnu.org/).
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* ChangeLog:
|
|
*
|
|
* V 1.63 David G. Holm Enable Unix-compatible keyboard input
|
|
* even when not using ncurses or slang.
|
|
* V 1.55 David G. Holm Added _SET_CANCEL support for
|
|
* Ctrl+Break, returning no key code
|
|
* when _SET_CANCEL is off.
|
|
* V 1.45 David G. Holm Removed Borland Windows support.
|
|
* Removed DOS-like Windows support.
|
|
* Removed Cygwin from Unix-like support.
|
|
* Added Console Mode Windows support.
|
|
* V 1.39 David G. Holm Added Borland Windows support.
|
|
* Restored Unix support to what
|
|
* it was in version 1.34.
|
|
* Added separate Cygwin support and
|
|
* set it up to cooperate between the
|
|
* hb_inkeyGet() and hb_inkeyNext()
|
|
* functions (but it still blocks).
|
|
* V 1.36 David G. Holm Added __MINGW32__ support
|
|
* V 1.35 David G. Holm Changed the __CYGWIN__ build to use
|
|
* the Unix keyboard input method and
|
|
* modified it to not block the VM.
|
|
* V 1.21 David G. Holm Added OS/2 DosSleep()
|
|
* V 1.15 David G. Holm Tested Borland 3.1 hb_releaseCPU()
|
|
* V 1.5 Paul Tucker ReleaseCPU comments
|
|
* V 1.4 Victor Szel
|
|
* V 1.3 Victor Szel #include <x> changed to #include "x".
|
|
* V 1.2 Gonzalo Diethelm ?
|
|
* V 1.1 David G. Holm Committed to CVS.
|
|
* V 1.0 David G. Holm Initial version.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* The following parts are Copyright of the individual authors.
|
|
* www - http://www.harbour-project.org
|
|
*
|
|
* Copyright 1999 Victor Szel <info@szelvesz.hu>
|
|
* HB___KEYPUT()
|
|
*
|
|
* See doc/license.txt for licensing terms.
|
|
*
|
|
*/
|
|
|
|
/* Note: The following #ifdef block for __IBMCPP__ must be ahead
|
|
of any and all #include statements and requires that
|
|
Harbour includes are ahead of platform includes.
|
|
*/
|
|
#ifdef __IBMCPP__
|
|
#define INCL_DOSPROCESS
|
|
#define INCL_NOPMAPI
|
|
#endif
|
|
|
|
/* NOTE: The following #include "hbwinapi.h" must
|
|
be ahead of any other #include statements! */
|
|
#include "hbwinapi.h"
|
|
|
|
#if defined(_Windows) || defined(WINNT)
|
|
#if ! defined(HARBOUR_USE_CRS_GTAPI) && ! defined(HARBOUR_USE_SLN_GTAPI)
|
|
#define INPUT_BUFFER_LEN 128
|
|
extern BOOL hb_gtBreak; /* This variable is located in source/rtl/gt/gtwin.c */
|
|
extern HANDLE hb_gtHInput; /* This variable is located in source/rtl/gt/gtwin.c */
|
|
static DWORD s_cNumRead = 0; /* Ok to use DWORD here, because this is specific... */
|
|
static DWORD s_cNumIndex = 0; /* ...to the Windows API, which defines DWORD, etc. */
|
|
static INPUT_RECORD s_irInBuf[ INPUT_BUFFER_LEN ];
|
|
#endif
|
|
#endif
|
|
|
|
#define HB_BREAK_FLAG 256 /* 256, because that's what DJGPP returns Ctrl+Break as.
|
|
Clipper has no key code 256, so it may as well be
|
|
used for all the Harbour builds that need it */
|
|
#include "extend.h"
|
|
#include "ctoharb.h"
|
|
#include "errorapi.h"
|
|
#include "itemapi.h"
|
|
#include "set.h"
|
|
#include "inkey.h"
|
|
#include "inkey.ch"
|
|
#include "init.h"
|
|
|
|
#if defined(__TURBOC__) || defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
|
|
#include <conio.h>
|
|
#include <dos.h>
|
|
#elif defined(__DJGPP__)
|
|
#include <pc.h>
|
|
#include <dos.h>
|
|
#include <sys\exceptn.h>
|
|
#elif defined(HARBOUR_GCC_OS2)
|
|
#include <stdlib.h>
|
|
#elif defined(__IBMCPP__)
|
|
#include <bsedos.h>
|
|
#include <conio.h>
|
|
#endif
|
|
#include <time.h>
|
|
|
|
#ifdef __WATCOMC__
|
|
#include <conio.h>
|
|
#include <i86.h>
|
|
#if defined(__386__) && !defined(__WINDOWS_386__)
|
|
#define INT_86 int386
|
|
#define DOS_REGS REGS
|
|
#else
|
|
#define INT_86 int86
|
|
#define DOS_REGS REGS
|
|
#endif
|
|
#elif defined(__EMX__)
|
|
#define INT_86 _int86
|
|
#define DOS_REGS REGS
|
|
#elif defined(_MSC_VER)
|
|
#define INT_86 _int86
|
|
#define DOS_REGS _REGS
|
|
#else
|
|
#define INT_86 int86
|
|
#define DOS_REGS REGS
|
|
#endif
|
|
|
|
#if defined(HARBOUR_GCC_OS2)
|
|
ULONG DosSleep( ULONG ulMilliseconds );
|
|
#endif
|
|
|
|
#if defined(OS_UNIX_COMPATIBLE)
|
|
#include <unistd.h>
|
|
#include <termios.h>
|
|
|
|
static struct termios startup_attributes;
|
|
|
|
static void restore_input_mode( void )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("restore_input_mode()"));
|
|
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &startup_attributes );
|
|
}
|
|
|
|
HB_CALL_ON_STARTUP_BEGIN( init_input_mode )
|
|
struct termios ta;
|
|
|
|
tcgetattr( STDIN_FILENO, &startup_attributes );
|
|
atexit( restore_input_mode );
|
|
|
|
tcgetattr( STDIN_FILENO, &ta );
|
|
ta.c_lflag &= ~( ICANON | ECHO );
|
|
ta.c_iflag &= ~ICRNL;
|
|
ta.c_cc[ VMIN ] = 0;
|
|
ta.c_cc[ VTIME ] = 0;
|
|
tcsetattr( STDIN_FILENO, TCSAFLUSH, &ta );
|
|
HB_CALL_ON_STARTUP_END( init_input_mode )
|
|
|
|
#elif defined(HARBOUR_USE_DOS_GTAPI) && ! defined(__DJGPP__)
|
|
extern BOOL hb_gtBreak; /* This variable is located in source/rtl/gt/gtdos.c */
|
|
#endif
|
|
|
|
static int * s_inkeyBuffer = 0; /* Harbour keyboard buffer (empty if head == tail) */
|
|
static int s_inkeyHead; /* Harbour keyboard buffer head pointer (next insert) */
|
|
static int s_inkeyTail; /* Harbour keyboard buffer tail pointer (next extract) */
|
|
static int s_inkeyLast; /* Last key extracted from Harbour keyboard buffer */
|
|
static BOOL s_inkeyPoll; /* Flag to override no polling when TYPEAHEAD is 0 */
|
|
static int s_inkeyForce; /* Variable to hold keyboard input when TYPEAHEAD is 0 */
|
|
static HB_inkey_enum s_eventmask;
|
|
|
|
void hb_releaseCPU( void )
|
|
{
|
|
/* TODO: Add code to release time slices on all platforms */
|
|
#if defined(_Windows) || defined(__MINGW32__)
|
|
/* according to ms docs, you should not do this in a Win app. dos only */
|
|
#elif defined(OS2)
|
|
DosSleep( 25 ); /* Duration is in milliseconds */
|
|
#elif defined(DOS)
|
|
/* NOTE: there is a bug under NT 4 (2000 unknown) - if the app is running
|
|
in protected mode, time slices will _not_ be released - you must switch
|
|
to real mode first, execute the following, and switch back.
|
|
|
|
It just occurred to me that this is actually by design. Since MS doesn't
|
|
want you to do this from a console app, their solution was to not allow
|
|
the call to work in protected mode - screw the rest of the planet <g>.
|
|
|
|
returns zero on failure. (means not supported)
|
|
*/
|
|
#if defined(__TURBOC__)
|
|
_AX = 0x1680;
|
|
geninterrupt( 0x2f );
|
|
_AH = 0;
|
|
_AL ^= 0x80;
|
|
#elif ! defined(__DJGPP__)
|
|
union REGS regs;
|
|
regs.h.ah = 0x16;
|
|
regs.h.al = 0x80;
|
|
#if defined(__WATCOMC__) && defined(__386__)
|
|
int386( 0x2f, ®s, ®s );
|
|
#else
|
|
int86( 0x2f, ®s, ®s );
|
|
#endif
|
|
regs.h.ah = 0;
|
|
regs.h.al ^= 0x80;
|
|
#endif
|
|
#elif defined(OS_UNIX_COMPATIBLE)
|
|
#else
|
|
#endif
|
|
HB_TRACE(HB_TR_DEBUG, ("releaseCPU()"));
|
|
}
|
|
|
|
int hb_inkey( double seconds, HB_inkey_enum event_mask, BOOL wait, BOOL forever )
|
|
{
|
|
int key;
|
|
clock_t end_clock;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_inkey(%lf, %d, %d, %d)", seconds, (int) event_mask, (int) wait, (int) forever));
|
|
|
|
s_eventmask = event_mask; /* Set current input event mask */
|
|
/* Check or wait for input events */
|
|
if( wait ) end_clock = clock() + seconds * CLOCKS_PER_SEC;
|
|
s_inkeyPoll = TRUE; /* Force polling */
|
|
|
|
while( wait && hb_inkeyNext() == 0 )
|
|
{
|
|
/* Release the CPU between checks */
|
|
hb_releaseCPU();
|
|
|
|
/* Check for timeout */
|
|
if( !forever && clock() >= end_clock ) wait = FALSE;
|
|
}
|
|
/* Get the current input event or 0 */
|
|
key = hb_inkeyGet();
|
|
s_inkeyPoll = FALSE; /* Stop forced polling */
|
|
s_eventmask = hb_set.HB_SET_EVENTMASK; /* Restore original input event mask */
|
|
return key;
|
|
}
|
|
|
|
int hb_inkeyGet( void ) /* Extract the next key from the keyboard buffer */
|
|
{
|
|
int key;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_inkeyGet()"));
|
|
|
|
hb_inkeyPoll();
|
|
if( hb_set.HB_SET_TYPEAHEAD )
|
|
{
|
|
/* Proper typeahead support is set */
|
|
if( s_inkeyHead == s_inkeyTail ) key = 0; /* Keyboard buffer is empty */
|
|
else
|
|
{ /* Keyboard buffer is not empty */
|
|
s_inkeyLast = s_inkeyBuffer[ s_inkeyTail++ ];
|
|
if( s_inkeyTail >= hb_set.HB_SET_TYPEAHEAD )
|
|
{ /* Limit keyboard buffer to set size */
|
|
s_inkeyTail = 0;
|
|
}
|
|
key = s_inkeyLast;
|
|
}
|
|
}
|
|
else key = s_inkeyLast = s_inkeyForce; /* Typeahead support is disabled */
|
|
s_inkeyForce = 0;
|
|
return key;
|
|
}
|
|
|
|
int hb_inkeyLast( void ) /* Return the value of the last key that was extracted */
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_inkeyLast()"));
|
|
|
|
hb_inkeyPoll();
|
|
return s_inkeyLast;
|
|
}
|
|
|
|
int hb_inkeyNext( void ) /* Return the next key without extracting it */
|
|
{
|
|
int key;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_inkeyNext()"));
|
|
|
|
hb_inkeyPoll();
|
|
if( hb_set.HB_SET_TYPEAHEAD )
|
|
{
|
|
/* Proper typeahead support is enabled */
|
|
if( s_inkeyHead == s_inkeyTail ) key = 0; /* No key */
|
|
else key = s_inkeyBuffer[ s_inkeyTail ]; /* Next key */
|
|
}
|
|
else key = s_inkeyForce; /* Typeahead support is disabled */
|
|
return key;
|
|
}
|
|
|
|
void hb_inkeyPoll( void ) /* Poll the console keyboard to stuff the Harbour buffer */
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_inkeyPoll()"));
|
|
|
|
/* TODO: Add mouse support */
|
|
if( hb_set.HB_SET_TYPEAHEAD || s_inkeyPoll )
|
|
{
|
|
int ch = 0;
|
|
#if defined(HARBOUR_USE_CRS_GTAPI) || defined(HARBOUR_USE_SLN_GTAPI)
|
|
ch = hb_gtReadKey();
|
|
#elif defined(OS_UNIX_COMPATIBLE)
|
|
if( ! read( STDIN_FILENO, &ch, 1 ) )
|
|
ch = 0;
|
|
#elif defined(_Windows) || defined(WINNT)
|
|
/* First check for Ctrl+Break, which is handled by gt/gtwin.c */
|
|
if( hb_gtBreak )
|
|
{
|
|
/* Reset the global Ctrl+Break flag */
|
|
hb_gtBreak = 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( hb_gtHInput, &s_cNumRead );
|
|
if( s_cNumRead )
|
|
{
|
|
/* Read keyboard input */
|
|
ReadConsoleInput(
|
|
hb_gtHInput, /* 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 )
|
|
{
|
|
/* Only process keyboard events for now... */
|
|
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;
|
|
ch = s_irInBuf[ s_cNumIndex ].Event.KeyEvent.uChar.AsciiChar;
|
|
if( ch == 0 || ( dwState & ( ENHANCED_KEY | LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED | RIGHT_CTRL_PRESSED | SHIFT_PRESSED ) ) )
|
|
{
|
|
/* Process non-ASCII key codes */
|
|
WORD wKey;
|
|
if( s_eventmask & INKEY_EXTENDED )
|
|
wKey = s_irInBuf[ s_cNumIndex ].Event.KeyEvent.wVirtualKeyCode;
|
|
else
|
|
wKey = s_irInBuf[ s_cNumIndex ].Event.KeyEvent.wVirtualScanCode;
|
|
/* Discard standalone state key presses for normal mode only */
|
|
if( ( s_eventmask & INKEY_EXTENDED ) == 0 ) switch( wKey )
|
|
{
|
|
/* Virtual scan codes to ignore */
|
|
case 29: /* Ctrl */
|
|
case 42: /* Left Shift */
|
|
case 54: /* Right Shift */
|
|
case 56: /* Alt */
|
|
case 69: /* Num Lock */
|
|
case 70: /* Pause or Scroll Lock */
|
|
wKey = 0;
|
|
}
|
|
if( wKey == 0 ) ch = 0;
|
|
else
|
|
{
|
|
if( s_eventmask & INKEY_EXTENDED )
|
|
{
|
|
/* 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;
|
|
}
|
|
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 bEnhanced = dwState & ENHANCED_KEY;
|
|
|
|
HB_TRACE(HB_TR_INFO, ("hb_inkeyPoll: wKey is %d, dwState is %d, ch is %d", wKey, dwState, ch));
|
|
|
|
if( bAlt )
|
|
{
|
|
/* Alt key held */
|
|
if( wKey == 1 ) ch = K_ALT_ESC; /* Esc */
|
|
else if( wKey == 15 ) ch = K_ALT_TAB; /* Tab */
|
|
else if( wKey <= 12 ) ch = wKey + 374; /* Numeric row */
|
|
else if( wKey == 28 ) ch = KP_ALT_ENTER; /* Num Pad Enter */
|
|
else if( wKey <= 52 ) ch = wKey + 256; /* Alpha rows */
|
|
else if( wKey == 53 && bEnhanced ) ch = KP_ALT_SLASH; /* Num Pad / */
|
|
else if( wKey == 55 ) ch = KP_ALT_ASTERISK; /* Num Pad * */
|
|
else if( wKey <= 58 ) ch = wKey + 367; /* ? */
|
|
else if( wKey <= 68 ) ch = 29 - wKey; /* F1 - F10 */
|
|
else if( wKey == 74 ) ch = KP_ALT_MINUS; /* Num Pad - */
|
|
else if( wKey == 76 ) ch = KP_ALT_5; /* Num Pad 5 */
|
|
else if( wKey == 78 ) ch = KP_ALT_PLUS; /* Num Pad + */
|
|
else if( wKey <= 86 ) ch = wKey + 336; /* Cursor */
|
|
else if( wKey <= 88 ) ch = 41 - wKey; /* F11, F12 */
|
|
else ch = wKey + 384;
|
|
}
|
|
else if( bCtrl )
|
|
{
|
|
/* Ctrl key held */
|
|
if( wKey == 53 && bEnhanced ) ch = KP_CTRL_SLASH; /* Num Pad / */
|
|
else if( wKey >= 59 && wKey <= 68 ) ch = 39 - wKey; /* F1 - F10 */
|
|
else switch( wKey )
|
|
{
|
|
case 1: /* Esc */
|
|
ch = K_ESC;
|
|
break;
|
|
case 3: /* 2 */
|
|
ch = 259;
|
|
break;
|
|
case 7: /* 6 */
|
|
ch = K_CTRL_PGDN;
|
|
break;
|
|
case 12: /* - */
|
|
ch = K_CTRL_PGUP;
|
|
break;
|
|
case 14: /* Backspace */
|
|
ch = K_CTRL_BS;
|
|
break;
|
|
case 15: /* Tab */
|
|
ch = K_CTRL_TAB;
|
|
break;
|
|
case 26: /* [ */
|
|
ch = K_ESC;
|
|
break;
|
|
case 27: /* ] */
|
|
ch = K_CTRL_HOME;
|
|
break;
|
|
case 28: /* Num Pad Enter */
|
|
ch = K_CTRL_ENTER;
|
|
break;
|
|
case 43: /* \ */
|
|
ch = K_F1;
|
|
break;
|
|
case 55: /* Num Pad * */
|
|
ch = KP_CTRL_ASTERISK;
|
|
break;
|
|
case 71: /* Home */
|
|
ch = K_CTRL_HOME;
|
|
break;
|
|
case 72: /* Up */
|
|
ch = K_CTRL_UP;
|
|
break;
|
|
case 73: /* PgUp */
|
|
ch = K_CTRL_PGUP;
|
|
break;
|
|
case 74: /* Num Pad - */
|
|
ch = KP_CTRL_MINUS;
|
|
break;
|
|
case 75: /* Left */
|
|
ch = K_CTRL_LEFT;
|
|
break;
|
|
case 76: /* Num Pad 5 */
|
|
ch = KP_CTRL_5;
|
|
break;
|
|
case 77: /* Right */
|
|
ch = K_CTRL_RIGHT;
|
|
break;
|
|
case 78: /* Num Pad + */
|
|
ch = KP_CTRL_PLUS;
|
|
break;
|
|
case 79: /* End */
|
|
ch = K_CTRL_END;
|
|
break;
|
|
case 80: /* Down */
|
|
ch = K_CTRL_DOWN;
|
|
break;
|
|
case 81: /* PgDn */
|
|
ch = K_CTRL_PGDN;
|
|
break;
|
|
case 82: /* Ins */
|
|
ch = K_CTRL_INS;
|
|
break;
|
|
case 83: /* Del */
|
|
ch = K_CTRL_DEL;
|
|
break;
|
|
case 87: /* F11 */
|
|
case 88: /* F12 */
|
|
ch = 43 - wKey;
|
|
break;
|
|
default:
|
|
/* Keep Ctrl+Alpha, but scrap everything
|
|
else that hasn't been translated yet. */
|
|
if( ch < 1 || ch > 26 )
|
|
ch = 0;
|
|
}
|
|
}
|
|
else if( bShift )
|
|
{
|
|
/* Shift key held */
|
|
if( wKey == 53 && bEnhanced ) ch = '/'; /* Num Pad / */
|
|
else if( wKey >= 59 && wKey <= 68 ) ch = 49 - wKey; /* F1 - F10 */
|
|
else switch( wKey )
|
|
{
|
|
case 1: /* Esc */
|
|
ch = K_ESC;
|
|
break;
|
|
case 15: /* Tab */
|
|
ch = K_SH_TAB;
|
|
break;
|
|
case 28: /* Num Pad Enter */
|
|
ch = K_ENTER;
|
|
break;
|
|
case 76: /* Num Pad 5 */
|
|
ch = '5';
|
|
break;
|
|
case 87: /* F11 */
|
|
case 88: /* F12 */
|
|
ch = 45 - wKey;
|
|
break;
|
|
case 82: /* Ins */
|
|
ch = K_INS;
|
|
break;
|
|
case 83: /* Del */
|
|
ch = K_DEL;
|
|
break;
|
|
case 71: /* Home */
|
|
ch = K_HOME;
|
|
break;
|
|
case 79: /* End */
|
|
ch = K_END;
|
|
break;
|
|
case 73: /* Page Up */
|
|
ch = K_PGUP;
|
|
break;
|
|
case 81: /* Page Down */
|
|
ch = K_PGDN;
|
|
break;
|
|
case 72: /* Up */
|
|
ch = K_UP;
|
|
break;
|
|
case 80: /* Down */
|
|
ch = K_DOWN;
|
|
break;
|
|
case 77: /* Right */
|
|
ch = K_RIGHT;
|
|
break;
|
|
case 75: /* Left */
|
|
ch = K_LEFT;
|
|
break;
|
|
default: /* Any thing not explicitly translated */
|
|
if( ch == 0 )
|
|
/* Only provide a translation for those key
|
|
codes that don't have a default one. */
|
|
ch = wKey + 128;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Normal key */
|
|
if( wKey == 28 ) ch = K_ENTER; /* Num Pad Enter */
|
|
else if( wKey == 53 && bEnhanced ) ch = '/'; /* Num Pad / */
|
|
else if( wKey == 59 ) ch = K_F1; /* F1 */
|
|
else if( wKey > 59 && wKey <= 68 ) ch = 59 - wKey; /* F2 - F10 */
|
|
else if( wKey == 76 ) ch = 332; /* Num Pad 5 */
|
|
else if( wKey == 87 || wKey == 88 ) ch = 47 - wKey; /* F11, F12 */
|
|
else switch( wKey )
|
|
{
|
|
case 82: /* Ins */
|
|
ch = K_INS;
|
|
break;
|
|
case 83: /* Del */
|
|
ch = K_DEL;
|
|
break;
|
|
case 71: /* Home */
|
|
ch = K_HOME;
|
|
break;
|
|
case 79: /* End */
|
|
ch = K_END;
|
|
break;
|
|
case 73: /* Page Up */
|
|
ch = K_PGUP;
|
|
break;
|
|
case 81: /* Page Down */
|
|
ch = K_PGDN;
|
|
break;
|
|
case 72: /* Up */
|
|
ch = K_UP;
|
|
break;
|
|
case 80: /* Down */
|
|
ch = K_DOWN;
|
|
break;
|
|
case 77: /* Right */
|
|
ch = K_RIGHT;
|
|
break;
|
|
case 75: /* Left */
|
|
ch = K_LEFT;
|
|
break;
|
|
case 76: /* Num Pad 5 */
|
|
ch = 332;
|
|
break;
|
|
case 28: /* Num pad Enter */
|
|
ch = K_ENTER;
|
|
break;
|
|
default:
|
|
ch = wKey + 128;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
/* Debug code: */
|
|
else
|
|
{
|
|
|
|
WORD wKey;
|
|
if( s_eventmask & INKEY_EXTENDED )
|
|
wKey = s_irInBuf[ s_cNumIndex ].Event.KeyEvent.wVirtualKeyCode;
|
|
else
|
|
wKey = s_irInBuf[ s_cNumIndex ].Event.KeyEvent.wVirtualScanCode;
|
|
HB_TRACE(HB_TR_INFO, ("hb_inkeyPoll: wKey is %d", wKey));
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
/* Set up to process the next input event (if any) */
|
|
s_cNumIndex++;
|
|
}
|
|
#elif defined(OS_DOS_COMPATIBLE) || defined(HARBOUR_GCC_OS2) || defined(__IBMCPP__)
|
|
/* The reason for including _Windows here is that kbhit() and getch() appear
|
|
to work properly in console mode. For true Windows mode, changes are needed. */
|
|
#if defined(HARBOUR_GCC_OS2)
|
|
/* Read from the keyboard with no echo, no wait, and no SIGSEV on Ctrl-C */
|
|
ch = _read_kbd( 0, 0, 0 );
|
|
if( ch == 0 )
|
|
{
|
|
/* It's a function key lead-in, so read the function key scan code */
|
|
ch = _read_kbd( 0, 0, 0 );
|
|
if( ch != -1 ) ch += 256; /* If it's really a scan code, offset it */
|
|
}
|
|
/* _read_kbd() returns -1 for no key, the switch statement will handle
|
|
this. */
|
|
#else
|
|
#if defined(HARBOUR_USE_DOS_GTAPI)
|
|
#if defined(__DJGPP__)
|
|
/* Check to see if Ctrl+Break has been detected */
|
|
if( __djgpp_cbrk_count )
|
|
{
|
|
__djgpp_cbrk_count = 0; /* Indicate that Ctrl+Break has been handled */
|
|
ch = HB_BREAK_FLAG; /* Note that Ctrl+Break was pressed */
|
|
}
|
|
#else
|
|
/* First check for Ctrl+Break, which is handled by gt/gtdos.c,
|
|
with the exception of the DJGPP compiler */
|
|
if( hb_gtBreak )
|
|
{
|
|
hb_gtBreak = FALSE; /* Indicate that Ctrl+Break has been handled */
|
|
ch = HB_BREAK_FLAG; /* Note that Ctrl+Break was pressed */
|
|
}
|
|
#endif
|
|
else
|
|
#endif
|
|
if( kbhit() )
|
|
{
|
|
/* A key code is available in the BIOS keyboard buffer, so read it */
|
|
#if defined(__DJGPP__)
|
|
if( s_eventmask & INKEY_EXTENDED ) ch = getxkey();
|
|
else ch = getkey();
|
|
if( ch == 256 )
|
|
/* Ignore Ctrl+Break, because it is being handled as soon as it
|
|
happens (see above) rather than waiting for it to show up in
|
|
the keyboard input queue */
|
|
ch = -1;
|
|
#else
|
|
/* A key code is available in the BIOS keyboard buffer */
|
|
ch = getch(); /* Get the key code */
|
|
if( ch == 0 && kbhit() )
|
|
{
|
|
/* It was a function key lead-in code, so read the actual
|
|
function key and then offset it by 256 */
|
|
ch = getch() + 256;
|
|
}
|
|
else if( ch == 224 && kbhit() )
|
|
{
|
|
/* It was an extended function key lead-in code, so read
|
|
the actual function key and then offset it by 256,
|
|
unless extended keyboard events are allowed, in which
|
|
case offset it by 512 */
|
|
if( s_eventmask & INKEY_EXTENDED ) ch = getch() + 512;
|
|
else ch = getch() + 256;
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
/* Perform key translations */
|
|
switch( ch )
|
|
{
|
|
case -1: /* No key available */
|
|
return;
|
|
case 328: /* Up arrow */
|
|
ch = K_UP;
|
|
break;
|
|
case 336: /* Down arrow */
|
|
ch = K_DOWN;
|
|
break;
|
|
case 331: /* Left arrow */
|
|
ch = K_LEFT;
|
|
break;
|
|
case 333: /* Right arrow */
|
|
ch = K_RIGHT;
|
|
break;
|
|
case 327: /* Home */
|
|
ch = K_HOME;
|
|
break;
|
|
case 335: /* End */
|
|
ch = K_END;
|
|
break;
|
|
case 329: /* Page Up */
|
|
ch = K_PGUP;
|
|
break;
|
|
case 337: /* Page Down */
|
|
ch = K_PGDN;
|
|
break;
|
|
case 371: /* Ctrl + Left arrow */
|
|
ch = K_CTRL_LEFT;
|
|
break;
|
|
case 372: /* Ctrl + Right arrow */
|
|
ch = K_CTRL_RIGHT;
|
|
break;
|
|
case 375: /* Ctrl + Home */
|
|
ch = K_CTRL_HOME;
|
|
break;
|
|
case 373: /* Ctrl + End */
|
|
ch = K_CTRL_END;
|
|
break;
|
|
case 388: /* Ctrl + Page Up */
|
|
ch = K_CTRL_PGUP;
|
|
break;
|
|
case 374: /* Ctrl + Page Down */
|
|
ch = K_CTRL_PGDN;
|
|
break;
|
|
case 338: /* Insert */
|
|
ch = K_INS;
|
|
break;
|
|
case 339: /* Delete */
|
|
ch = K_DEL;
|
|
break;
|
|
case 315: /* F1 */
|
|
ch = K_F1;
|
|
break;
|
|
case 316: /* F2 */
|
|
case 317: /* F3 */
|
|
case 318: /* F4 */
|
|
case 319: /* F5 */
|
|
case 320: /* F6 */
|
|
case 321: /* F7 */
|
|
case 322: /* F8 */
|
|
case 323: /* F9 */
|
|
case 324: /* F10 */
|
|
ch = 315 - ch;
|
|
break;
|
|
case 340: /* Shift + F1 */
|
|
case 341: /* Shift + F2 */
|
|
case 342: /* Shift + F3 */
|
|
case 343: /* Shift + F4 */
|
|
case 344: /* Shift + F5 */
|
|
case 345: /* Shift + F6 */
|
|
case 346: /* Shift + F7 */
|
|
case 347: /* Shift + F8 */
|
|
case 348: /* Shift + F9 */
|
|
case 349: /* Shift + F10 */
|
|
case 350: /* Ctrl + F1 */
|
|
case 351: /* Ctrl + F2 */
|
|
case 352: /* Ctrl + F3 */
|
|
case 353: /* Ctrl + F4 */
|
|
case 354: /* Ctrl + F5 */
|
|
case 355: /* Ctrl + F6 */
|
|
case 356: /* Ctrl + F7 */
|
|
case 357: /* Ctrl + F8 */
|
|
case 358: /* Ctrl + F9 */
|
|
case 359: /* Ctrl + F10 */
|
|
case 360: /* Alt + F1 */
|
|
case 361: /* Alt + F2 */
|
|
case 362: /* Alt + F3 */
|
|
case 363: /* Alt + F4 */
|
|
case 364: /* Alt + F5 */
|
|
case 365: /* Alt + F6 */
|
|
case 366: /* Alt + F7 */
|
|
case 367: /* Alt + F8 */
|
|
case 368: /* Alt + F9 */
|
|
case 369: /* Alt + F10 */
|
|
ch = 330 - ch;
|
|
break;
|
|
case 389: /* F11 */
|
|
case 390: /* F12 */
|
|
case 391: /* Shift + F11 */
|
|
case 392: /* Shift + F12 */
|
|
case 393: /* Ctrl + F11 */
|
|
case 394: /* Ctrl + F12 */
|
|
case 395: /* Alt + F11 */
|
|
case 396: /* Alt + F12 */
|
|
ch = 349 - ch;
|
|
}
|
|
#else
|
|
/* TODO: Support for other platforms, such as Mac */
|
|
#endif
|
|
switch( ch )
|
|
{
|
|
case HB_BREAK_FLAG: /* Check for Ctrl+Break */
|
|
if( ! hb_set.HB_SET_CANCEL ) /* If cancel is disabled, */
|
|
ch = 0; /* then ignore the keystroke */
|
|
/* In either case, handle like Alt+C */
|
|
case K_ALT_C: /* Alt+C was pressed */
|
|
hb_vmRequestCancel();
|
|
}
|
|
hb_inkeyPut( ch );
|
|
}
|
|
}
|
|
|
|
void hb_inkeyReset( BOOL allocate ) /* Reset the keyboard buffer */
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_inkeyReset(%d)", (int) allocate));
|
|
|
|
/* Reset the buffer head and tail pointers, the last key value,
|
|
and the polling override flag */
|
|
s_inkeyHead = 0;
|
|
s_inkeyTail = 0;
|
|
s_inkeyLast = 0;
|
|
s_inkeyPoll = FALSE;
|
|
s_inkeyForce = 0;
|
|
/* The allocate flag allows the same function to be used to reset the
|
|
buffer or to reset and allocate, reallocate, or free the buffer */
|
|
if( allocate )
|
|
{
|
|
/* If the buffer already exists, free it */
|
|
if( s_inkeyBuffer ) hb_xfree( s_inkeyBuffer );
|
|
/* Always allocate a new buffer, unless it's being freed from hb_setRelease() */
|
|
if( hb_set.HB_SET_TYPEAHEAD > -1 )
|
|
{
|
|
/* The buffer min and max are determined by SET(HB_SET_TYPEAHEAD, but it
|
|
can also set the typeahead to 0 to disable polling, in which case the
|
|
minimum buffer size (which is 16) must still be allocated, because
|
|
even when polling is disabled, calling INKEY() or NEXTKEY() will
|
|
temporarily re-enable polling */
|
|
s_inkeyBuffer = ( int * ) hb_xgrab( sizeof( int )
|
|
* ( hb_set.HB_SET_TYPEAHEAD == 0 ? 16 : hb_set.HB_SET_TYPEAHEAD ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* INKEY()
|
|
* $CATEGORY$
|
|
* Console input
|
|
* $ONELINER$
|
|
* Extracts the next key code from the Harbour keyboard buffer
|
|
* $SYNTAX$
|
|
* INKEY( [<nTimeout>] [,<nEvents>] ) --> nKey
|
|
* $ARGUMENTS$
|
|
* <nTimeout> is an optional timeout value in seconds, with a granularity
|
|
* of 1/10th of a second. If omitted, INKEY() returns immediately. If set
|
|
* to 0, INKEY() waits until an input event occurs. If set to any other
|
|
* value, INKEY() will return either when an input event occurs or when
|
|
* the timeout period has elapsed. If only this parameter is specified
|
|
* and it is not numeric, it will be treated as if it were 0. But if both
|
|
* parameters are specified and this parameter is not numeric, it will be
|
|
* treated as if it were not present.
|
|
*
|
|
* <nEvents> is an optional mask of input events that are to be enabled.
|
|
* If omitted, defaults to hb_set.HB_SET_EVENTMASK. Valid input maks are
|
|
* in inkey.ch and are explained below. It is recommended that the mask
|
|
* names be used rather than their numeric values, in case the numeric
|
|
* values change in future releases of Harbour. To allow more than one
|
|
* type of input event, simply add the various mask names together.
|
|
* INKEY_MOVE = Mouse motion events are allowed
|
|
* INKEY_LDOWN = The mouse left click down event is allowed
|
|
* INKEY_LUP = The mouse left click up event is allowed
|
|
* INKEY_RDOWN = The mouse right click down event is allowed
|
|
* INKEY_RUP = The mouse right click up event is allowed
|
|
* INKEY_KEYBOARD = All keyboard events are allowed
|
|
* INKEY_ALL = All mouse and keyboard events are allowed
|
|
* If the parameter is not numeric, it will be treated as if it were set
|
|
* to hb_set.HB_SET_EVENTMASK.
|
|
* $RETURNS$
|
|
* 0 in case of timeout with no input event, otherwise returns a value
|
|
* in the range -39 to 386 for keyboard events or the range 1001 to 1007
|
|
* for mouse events. Mouse events and non-printable keyboard events are
|
|
* represented by the K_<event> values listed in inkey.ch. Keyboard
|
|
* event return codes in the range 32 through 127 are equivalent to the
|
|
* printable ASCII character set. Keyboard event return codes in the
|
|
* range 128 through 255 are assumed to be printable, but results may
|
|
* vary based on hardware and nationality.
|
|
* $DESCRIPTION$
|
|
* INKEY() can be used to detect input events, such as keypress, mouse
|
|
* movement, or mouse key clicks (up and/or down).
|
|
* $EXAMPLES$
|
|
* // Wait for the user to press the Esc key
|
|
* ? "Please press the ESC key."
|
|
* WHILE INKEY( 0.1 ) != K_ESC
|
|
* END
|
|
* $TESTS$
|
|
* KEYBOARD "AB"; ? INKEY(), INKEY() ==> 65 66
|
|
* $STATUS$
|
|
* S
|
|
* $COMPLIANCE$
|
|
* INKEY() is compliant with the Clipper 5.3 INKEY() function with one
|
|
* exceptions: The Harbour INKEY() function will raise an argument error
|
|
* if the first parameter is less than or equal to 0 and the second
|
|
* parameter (or the default mask) is not valid, because otherwise INKEY
|
|
* would never return, because it was, in effect, asked to wait forever
|
|
* for no events (Note: In Clipper, this also blocks SET KEY events).
|
|
* $SEEALSO$
|
|
* inkey.ch
|
|
* $END$
|
|
*/
|
|
|
|
HARBOUR HB_INKEY( void )
|
|
{
|
|
int args = hb_pcount();
|
|
int key = 0;
|
|
BOOL wait = FALSE, forever = FALSE;
|
|
double seconds = 0.0;
|
|
HB_inkey_enum event_mask = hb_set.HB_SET_EVENTMASK; /* Default to the SET input event mask */
|
|
|
|
if( args == 1 || ( args > 1 && hb_param( 1, IT_NUMERIC ) ) )
|
|
{
|
|
/* If only one parameter or if 1st parameter is numeric, then use it
|
|
as the number of seconds to wait for an input event, in seconds. */
|
|
seconds = hb_parnd( 1 );
|
|
wait = TRUE;
|
|
if( seconds * CLOCKS_PER_SEC < 1 ) forever = TRUE;
|
|
#ifndef HARBOUR_USE_GTAPI
|
|
/* When not using the GT API, flush both stdout and stderr,
|
|
because we are waiting for input and want to ensure that
|
|
any user prompts are visible. */
|
|
/* fflush( stdout ); */
|
|
/* fflush( stderr ); */
|
|
#endif
|
|
}
|
|
|
|
if( args > 1 && hb_param( 2, IT_NUMERIC ) )
|
|
{
|
|
/* If 2nd parameter is numeric, then use it as the input mask */
|
|
event_mask = ( HB_inkey_enum )hb_parni( 2 );
|
|
}
|
|
|
|
if( wait && forever && ( event_mask & ( INKEY_ALL + INKEY_EXTENDED ) ) == 0 )
|
|
{
|
|
/* There is no point in waiting forever for no input events! */
|
|
hb_errRT_BASE( EG_ARG, 3007, NULL, "INKEY" );
|
|
}
|
|
else
|
|
{
|
|
/* Call the low-level hb_inkey() function. */
|
|
key = hb_inkey( seconds, event_mask, wait, forever );
|
|
}
|
|
hb_retni( key );
|
|
}
|
|
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* __KEYBOARD()
|
|
* $CATEGORY$
|
|
* Console input
|
|
* $ONELINER$
|
|
* DO NOT CALL THIS FUNCTION DIRECTLY!
|
|
* $SYNTAX$
|
|
* KEYBOARD <cString>
|
|
* CLEAR TYPEAHEAD
|
|
* $ARGUMENTS$
|
|
* <cString> is the optional string to stuff into the Harbour keyboard
|
|
* buffer after clearing it first.
|
|
* $RETURNS$
|
|
* There is no return value
|
|
* $DESCRIPTION$
|
|
* Clears the Harbour keyboard typeahead buffer and then inserts an
|
|
* optional string into it.
|
|
* $EXAMPLES$
|
|
* // Stuff an Enter key into the keyboard buffer
|
|
* KEYBOARD CHR(13)
|
|
* // Clear the keyboard buffer
|
|
* CLEAR TYPEAHEAD
|
|
* $TESTS$
|
|
* KEYBOARD CHR(13); ? INKEY() ==> 13
|
|
* KEYBOARD "HELLO"; CLEAR TYPEAHEAD; ? INKEY() ==> 0
|
|
* $STATUS$
|
|
* R
|
|
* $COMPLIANCE$
|
|
* __KEYBOARD() is compliant with CA-Clipper 5.3
|
|
* $SEEALSO$
|
|
CLEAR TYPEAHEAD,KEYBOARD
|
|
* $END$
|
|
*/
|
|
|
|
HARBOUR HB___KEYBOARD( void )
|
|
{
|
|
/* Clear the typeahead buffer without reallocating the keyboard buffer */
|
|
hb_inkeyReset( FALSE );
|
|
|
|
if( ISCHAR( 1 ) )
|
|
{
|
|
long size = hb_parclen( 1 );
|
|
|
|
if( size != 0 )
|
|
{
|
|
/* Stuff the string */
|
|
char *fPtr = hb_parc( 1 );
|
|
|
|
if( size >= hb_set.HB_SET_TYPEAHEAD )
|
|
{
|
|
/* Have to allow for a zero size typehead buffer */
|
|
if( hb_set.HB_SET_TYPEAHEAD ) size = hb_set.HB_SET_TYPEAHEAD - 1;
|
|
else size = 0;
|
|
}
|
|
|
|
while( size-- )
|
|
hb_inkeyPut( *fPtr++ );
|
|
}
|
|
}
|
|
}
|
|
|
|
void hb_inkeyPut( int ch )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_inkeyPut(%d)", ch));
|
|
|
|
if( ch )
|
|
{
|
|
if( hb_set.HB_SET_TYPEAHEAD )
|
|
{
|
|
/* Proper typeahead support is set */
|
|
int head = s_inkeyHead;
|
|
s_inkeyBuffer[ head++ ] = ch;
|
|
if( head >= hb_set.HB_SET_TYPEAHEAD ) head = 0;
|
|
if( head != s_inkeyTail ) s_inkeyHead = head;
|
|
else /* TODO: Add error sound */ ;
|
|
}
|
|
else
|
|
s_inkeyForce = ch; /* Typeahead support is disabled */
|
|
}
|
|
}
|
|
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* __KEYPUT()
|
|
* $CATEGORY$
|
|
* Console input
|
|
* $ONELINER$
|
|
* Put an inkey code to the keyboard buffer
|
|
* $SYNTAX$
|
|
* __keyPut( <nInkeyCode> )
|
|
* $ARGUMENTS$
|
|
* <nInkeyCode> is the inkey code, which should be inserted into the
|
|
* keyboard buffer.
|
|
* $RETURNS$
|
|
* There is no return value
|
|
* $DESCRIPTION$
|
|
* Inserts an inkey code to the string buffer. The buffer is *not*
|
|
* cleared in this operation. This function allows to insert such
|
|
* inkey codes which are not in the range of 0 to 255. To insert more
|
|
* than one code, call the function repeatedly. The zero code cannot
|
|
* be inserted.
|
|
* $EXAMPLES$
|
|
* // Stuff an Alt+PgDn key into the keyboard buffer
|
|
* __keyPut( K_ALT_PGDN )
|
|
* $TESTS$
|
|
* __keyPut( K_ALT_PGDN ) ; ? INKEY() ==> 417
|
|
* __keyPut( K_F11 ) ; ? INKEY() ==> -40
|
|
* $STATUS$
|
|
* R
|
|
* $COMPLIANCE$
|
|
* Was not part of Clipper
|
|
* $SEEALSO$
|
|
* KEYBOARD,CLEAR TYPEAHEAD,INKEY()
|
|
* $END$
|
|
*/
|
|
|
|
HARBOUR HB___KEYPUT( void )
|
|
{
|
|
if( ISNUM( 1 ) )
|
|
hb_inkeyPut( hb_parni( 1 ) );
|
|
}
|
|
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* NEXTKEY()
|
|
* $CATEGORY$
|
|
* Console input
|
|
* $ONELINER$
|
|
* Returns the value of the next key in the Harbour keyboard buffer
|
|
* $SYNTAX$
|
|
* NEXTKEY() --> nKey
|
|
* $ARGUMENTS$
|
|
* None
|
|
* $RETURNS$
|
|
* There is no return value
|
|
* $DESCRIPTION$
|
|
* Returns the value of the next key in the Harbour keyboard buffer
|
|
* without extracting it.
|
|
* $EXAMPLES$
|
|
* // Use NEXTKEY() with INKEY() to change display character or by
|
|
* // itself to exit the loop, so that the caller can detect the Esc.
|
|
* LOCAL nKey, cChar := "+"
|
|
* WHILE TRUE
|
|
* ?? cChar
|
|
* nKey := NEXTKEY()
|
|
* IF nKey == K_ESC
|
|
* EXIT
|
|
* ELSE
|
|
* IF nKey != 0
|
|
* cChar := CHR( nKey )
|
|
* END IF
|
|
* END IF
|
|
* END WHILE
|
|
* $TESTS$
|
|
* KEYBOARD "AB"; ? NEXTKEY(), NEXTKEY() ==> 65 65
|
|
* $STATUS$
|
|
* R
|
|
* $COMPLIANCE$
|
|
* NEXTKEY() is compliant with CA-Clipper 5.3
|
|
* $SEEALSO$
|
|
* INKEY(),LASTKEY()
|
|
* $END$
|
|
*/
|
|
|
|
HARBOUR HB_NEXTKEY( void )
|
|
{
|
|
hb_retni( hb_inkeyNext() );
|
|
}
|
|
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* LASTKEY()
|
|
* $CATEGORY$
|
|
* Console input
|
|
* $ONELINER$
|
|
* Returns the last key exttracted from the Harbour keyboard buffer
|
|
* $SYNTAX$
|
|
* LASTKEY() --> nKey
|
|
* $ARGUMENTS$
|
|
* None
|
|
* $RETURNS$
|
|
* There is no return value
|
|
* $DESCRIPTION$
|
|
* Returns the value of the last key exttracted from the Harbour
|
|
* keyboard buffer
|
|
* $EXAMPLES$
|
|
* // Continue looping unless the ESC key was pressed in MainFunc()
|
|
* WHILE TRUE
|
|
* MainFunc()
|
|
* IF LASTKEY() == K_ESC
|
|
* EXIT
|
|
* END IF
|
|
* END WHILE
|
|
* $TESTS$
|
|
* KEYBOARD "AB"; ? INKEY(), LASTKEY() ==> 65 65
|
|
* $STATUS$
|
|
* R
|
|
* $COMPLIANCE$
|
|
* LASTKEY() is compliant with CA-Clipper 5.3
|
|
* $SEEALSO$
|
|
* INKEY(),LASTKEY()
|
|
* $END$
|
|
*/
|
|
|
|
HARBOUR HB_LASTKEY( void )
|
|
{
|
|
hb_retni( s_inkeyLast );
|
|
}
|
|
|
|
/* Dumb function to maintain dBase III+ and CA-Cl*pper compatibility */
|
|
|
|
HARBOUR HB_FKLABEL( void )
|
|
{
|
|
PHB_ITEM pPar1 = hb_param( 1, IT_NUMERIC );
|
|
|
|
if( pPar1 != NULL )
|
|
{
|
|
USHORT uiFKey = hb_itemGetNI( pPar1 );
|
|
|
|
if( uiFKey > 0 && uiFKey <= 40 )
|
|
{
|
|
char szName[ 4 ];
|
|
|
|
sprintf( szName, "F%i", uiFKey );
|
|
|
|
hb_retc( szName );
|
|
}
|
|
else
|
|
hb_retc( "" );
|
|
}
|
|
else
|
|
hb_retc( "" );
|
|
}
|
|
|
|
/* Dumb function to maintain dBase III+ and CA-Cl*pper compatibility */
|
|
|
|
HARBOUR HB_FKMAX( void )
|
|
{
|
|
hb_retni( 40 ); /* IBM specific */
|
|
}
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* KEYBOARD
|
|
* $CATEGORY$
|
|
* Command
|
|
* $ONELINER$
|
|
* Stuffs the keyboard with a string
|
|
* $SYNTAX$
|
|
* KEYBOARD <cString>
|
|
* $ARGUMENTS$
|
|
* <cString> String to be processed, one character at a time,
|
|
* by the Harbour keyboard processor
|
|
* $RETURNS$
|
|
*
|
|
* $DESCRIPTION$
|
|
* This command stuff the input buffer with <cString>. The
|
|
* number of character that can be stuffed into the keyboard
|
|
* buffer is controled by SET TYPEAHEAD command and may range
|
|
* from 0 to 32,622, with each character appearing in the ASCII
|
|
* range of 0 to 255. None of the extended keys may be stuffed
|
|
* in the keyboard buffer.
|
|
* Issuing a KEYBOARD " " will clear the keyboard buffer.
|
|
* $EXAMPLES$
|
|
* // Stuff an Enter key into the keyboard buffer
|
|
* KEYBOARD CHR(13)
|
|
* // Clear the keyboard buffer
|
|
* CLEAR TYPEAHEAD
|
|
* $TESTS$
|
|
* KEYBOARD CHR(13); ? INKEY() ==> 13
|
|
* KEYBOARD "HELLO"; CLEAR TYPEAHEAD; ? INKEY() ==> 0
|
|
* $STATUS$
|
|
* R
|
|
* $COMPLIANCE$
|
|
* __KEYBOARD() is compliant with CA-Clipper 5.3
|
|
* $SEEALSO$
|
|
* CLEAR TYPEAHEAD,__KEYBOARD()
|
|
* $END$
|
|
*/
|