blob: c44393fc0f859049cab55c38fcd089de5ff3aae6 [file] [log] [blame]
/* Public Domain Curses */
/* MS C doesn't return flags from int86() */
#ifdef MSC
# define USE_KBHIT
#endif
#ifdef USE_KBHIT
# include <conio.h>
#endif
#include "pdcdos.h"
RCSID("$Id: pdckbd.c,v 1.87 2008/07/13 16:08:17 wmcbrine Exp $")
/*man-start**************************************************************
Name: pdckbd
Synopsis:
unsigned long PDC_get_input_fd(void);
Description:
PDC_get_input_fd() returns the file descriptor that PDCurses
reads its input from. It can be used for select().
Portability X/Open BSD SYS V
PDC_get_input_fd - - -
**man-end****************************************************************/
#ifdef __DJGPP__
# include <fcntl.h>
# include <io.h>
# include <signal.h>
#endif
/************************************************************************
* Table for key code translation of function keys in keypad mode *
* These values are for strict IBM keyboard compatibles only *
************************************************************************/
static short key_table[] =
{
-1, ALT_ESC, -1, 0,
-1, -1, -1, -1,
-1, -1, -1, -1,
-1, -1, ALT_BKSP, KEY_BTAB,
ALT_Q, ALT_W, ALT_E, ALT_R,
ALT_T, ALT_Y, ALT_U, ALT_I,
ALT_O, ALT_P, ALT_LBRACKET, ALT_RBRACKET,
ALT_ENTER, -1, ALT_A, ALT_S,
ALT_D, ALT_F, ALT_G, ALT_H,
ALT_J, ALT_K, ALT_L, ALT_SEMICOLON,
ALT_FQUOTE, ALT_BQUOTE, -1, ALT_BSLASH,
ALT_Z, ALT_X, ALT_C, ALT_V,
ALT_B, ALT_N, ALT_M, ALT_COMMA,
ALT_STOP, ALT_FSLASH, -1, ALT_PADSTAR,
-1, -1, -1, KEY_F(1),
KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9),
KEY_F(10), -1, -1, KEY_HOME,
KEY_UP, KEY_PPAGE, ALT_PADMINUS, KEY_LEFT,
KEY_B2, KEY_RIGHT, ALT_PADPLUS, KEY_END,
KEY_DOWN, KEY_NPAGE, KEY_IC, KEY_DC,
KEY_F(13), KEY_F(14), KEY_F(15), KEY_F(16),
KEY_F(17), KEY_F(18), KEY_F(19), KEY_F(20),
KEY_F(21), KEY_F(22), KEY_F(25), KEY_F(26),
KEY_F(27), KEY_F(28), KEY_F(29), KEY_F(30),
KEY_F(31), KEY_F(32), KEY_F(33), KEY_F(34),
KEY_F(37), KEY_F(38), KEY_F(39), KEY_F(40),
KEY_F(41), KEY_F(42), KEY_F(43), KEY_F(44),
KEY_F(45), KEY_F(46), -1, CTL_LEFT,
CTL_RIGHT, CTL_END, CTL_PGDN, CTL_HOME,
ALT_1, ALT_2, ALT_3, ALT_4,
ALT_5, ALT_6, ALT_7, ALT_8,
ALT_9, ALT_0, ALT_MINUS, ALT_EQUAL,
CTL_PGUP, KEY_F(11), KEY_F(12), KEY_F(23),
KEY_F(24), KEY_F(35), KEY_F(36), KEY_F(47),
KEY_F(48), CTL_UP, CTL_PADMINUS, CTL_PADCENTER,
CTL_PADPLUS, CTL_DOWN, CTL_INS, CTL_DEL,
CTL_TAB, CTL_PADSLASH, CTL_PADSTAR, ALT_HOME,
ALT_UP, ALT_PGUP, -1, ALT_LEFT,
-1, ALT_RIGHT, -1, ALT_END,
ALT_DOWN, ALT_PGDN, ALT_INS, ALT_DEL,
ALT_PADSLASH, ALT_TAB, ALT_PADENTER, -1
};
unsigned long pdc_key_modifiers = 0L;
static struct {unsigned short pressed, released;} button[3];
static bool mouse_avail = FALSE, mouse_vis = FALSE, mouse_moved = FALSE,
mouse_button = FALSE, key_pressed = FALSE;
static unsigned char mouse_scroll = 0;
static PDCREGS ms_regs, old_ms;
static unsigned short shift_status, old_shift = 0;
static unsigned char keyboard_function = 0xff, shift_function = 0xff,
check_function = 0xff;
static const unsigned short button_map[3] = {0, 2, 1};
unsigned long PDC_get_input_fd(void)
{
PDC_LOG(("PDC_get_input_fd() - called\n"));
return (unsigned long)fileno(stdin);
}
void PDC_set_keyboard_binary(bool on)
{
PDC_LOG(("PDC_set_keyboard_binary() - called\n"));
#ifdef __DJGPP__
setmode(fileno(stdin), on ? O_BINARY : O_TEXT);
signal(SIGINT, on ? SIG_IGN : SIG_DFL);
#endif
}
/* check if a key or mouse event is waiting */
bool PDC_check_key(void)
{
PDCREGS regs;
if (shift_function == 0xff)
{
int scan;
/* get shift status for all keyboards */
regs.h.ah = 0x02;
PDCINT(0x16, regs);
scan = regs.h.al;
/* get shift status for enhanced keyboards */
regs.h.ah = 0x12;
PDCINT(0x16, regs);
if (scan == regs.h.al && getdosmembyte(0x496) == 0x10)
{
keyboard_function = 0x10;
check_function = 0x11;
shift_function = 0x12;
}
else
{
keyboard_function = 0;
check_function = 1;
shift_function = 2;
}
}
regs.h.ah = shift_function;
PDCINT(0x16, regs);
shift_status = regs.W.ax;
if (mouse_vis)
{
unsigned short i;
ms_regs.W.ax = 3;
PDCINT(0x33, ms_regs);
mouse_button = FALSE;
for (i = 0; i < 3; i++)
{
regs.W.ax = 6;
regs.W.bx = button_map[i];
PDCINT(0x33, regs);
button[i].released = regs.W.bx;
if (regs.W.bx)
{
ms_regs.W.cx = regs.W.cx;
ms_regs.W.dx = regs.W.dx;
mouse_button = TRUE;
}
regs.W.ax = 5;
regs.W.bx = button_map[i];
PDCINT(0x33, regs);
button[i].pressed = regs.W.bx;
if (regs.W.bx)
{
ms_regs.W.cx = regs.W.cx;
ms_regs.W.dx = regs.W.dx;
mouse_button = TRUE;
}
}
mouse_scroll = ms_regs.h.bh;
mouse_moved = !mouse_button && ms_regs.h.bl &&
ms_regs.h.bl == old_ms.h.bl &&
(((ms_regs.W.cx ^ old_ms.W.cx) >> 3) ||
((ms_regs.W.dx ^ old_ms.W.dx) >> 3));
if (mouse_scroll || mouse_button || mouse_moved)
return TRUE;
}
if (old_shift && !shift_status) /* modifier released */
{
if (!key_pressed && SP->return_key_modifiers)
return TRUE;
}
else if (!old_shift && shift_status) /* modifier pressed */
key_pressed = FALSE;
old_shift = shift_status;
#ifndef USE_KBHIT
regs.h.ah = check_function;
PDCINT(0x16, regs);
return !(regs.W.flags & 64);
#else
return kbhit();
#endif
}
static int _process_mouse_events(void)
{
int i;
short shift_flags = 0;
memset(&pdc_mouse_status, 0, sizeof(pdc_mouse_status));
key_pressed = TRUE;
old_shift = shift_status;
SP->key_code = TRUE;
/* Set shift modifiers */
if (shift_status & 3)
shift_flags |= BUTTON_SHIFT;
if (shift_status & 4)
shift_flags |= BUTTON_CONTROL;
if (shift_status & 8)
shift_flags |= BUTTON_ALT;
/* Scroll wheel support for CuteMouse */
if (mouse_scroll)
{
pdc_mouse_status.changes = mouse_scroll & 0x80 ?
PDC_MOUSE_WHEEL_UP : PDC_MOUSE_WHEEL_DOWN;
pdc_mouse_status.x = -1;
pdc_mouse_status.y = -1;
return KEY_MOUSE;
}
if (mouse_moved)
{
pdc_mouse_status.changes = PDC_MOUSE_MOVED;
for (i = 0; i < 3; i++)
{
if (ms_regs.h.bl & (1 << button_map[i]))
{
pdc_mouse_status.button[i] = BUTTON_MOVED | shift_flags;
pdc_mouse_status.changes |= (1 << i);
}
}
}
else /* button event */
{
for (i = 0; i < 3; i++)
{
if (button[i].pressed)
{
/* Check for a click -- a PRESS followed
immediately by a release */
if (!button[i].released)
{
if (SP->mouse_wait)
{
PDCREGS regs;
napms(SP->mouse_wait);
regs.W.ax = 6;
regs.W.bx = button_map[i];
PDCINT(0x33, regs);
pdc_mouse_status.button[i] = regs.W.bx ?
BUTTON_CLICKED : BUTTON_PRESSED;
}
else
pdc_mouse_status.button[i] = BUTTON_PRESSED;
}
else
pdc_mouse_status.button[i] = BUTTON_CLICKED;
}
if (button[i].pressed || button[i].released)
{
pdc_mouse_status.button[i] |= shift_flags;
pdc_mouse_status.changes |= (1 << i);
}
}
}
pdc_mouse_status.x = ms_regs.W.cx >> 3;
pdc_mouse_status.y = ms_regs.W.dx >> 3;
old_ms = ms_regs;
return KEY_MOUSE;
}
/* return the next available key or mouse event */
int PDC_get_key(void)
{
PDCREGS regs;
int key, scan;
pdc_key_modifiers = 0;
if (mouse_vis && (mouse_scroll || mouse_button || mouse_moved))
return _process_mouse_events();
/* Return modifiers as keys? */
if (old_shift && !shift_status)
{
key = -1;
if (old_shift & 1)
key = KEY_SHIFT_R;
if (old_shift & 2)
key = KEY_SHIFT_L;
if (shift_function == 0x12)
{
if (old_shift & 0x400)
key = KEY_CONTROL_R;
if (old_shift & 0x100)
key = KEY_CONTROL_L;
if (old_shift & 0x800)
key = KEY_ALT_R;
if (old_shift & 0x200)
key = KEY_ALT_L;
}
else
{
if (old_shift & 4)
key = KEY_CONTROL_R;
if (old_shift & 8)
key = KEY_ALT_R;
}
key_pressed = FALSE;
old_shift = shift_status;
SP->key_code = TRUE;
return key;
}
regs.h.ah = keyboard_function;
PDCINT(0x16, regs);
key = regs.h.al;
scan = regs.h.ah;
if (SP->save_key_modifiers)
{
if (shift_status & 3)
pdc_key_modifiers |= PDC_KEY_MODIFIER_SHIFT;
if (shift_status & 4)
pdc_key_modifiers |= PDC_KEY_MODIFIER_CONTROL;
if (shift_status & 8)
pdc_key_modifiers |= PDC_KEY_MODIFIER_ALT;
if (shift_status & 0x20)
pdc_key_modifiers |= PDC_KEY_MODIFIER_NUMLOCK;
}
if (scan == 0x1c && key == 0x0a) /* ^Enter */
key = CTL_ENTER;
else if (scan == 0xe0 && key == 0x0d) /* PadEnter */
key = PADENTER;
else if (scan == 0xe0 && key == 0x0a) /* ^PadEnter */
key = CTL_PADENTER;
else if (scan == 0x37 && key == 0x2a) /* Star */
key = PADSTAR;
else if (scan == 0x4a && key == 0x2d) /* Minus */
key = PADMINUS;
else if (scan == 0x4e && key == 0x2b) /* Plus */
key = PADPLUS;
else if (scan == 0xe0 && key == 0x2f) /* Slash */
key = PADSLASH;
else if (key == 0x00 || (key == 0xe0 && scan > 53 && scan != 86))
key = (scan > 0xa7) ? -1 : key_table[scan];
if (shift_status & 3)
{
switch (key)
{
case KEY_HOME: /* Shift Home */
key = KEY_SHOME;
break;
case KEY_UP: /* Shift Up */
key = KEY_SUP;
break;
case KEY_PPAGE: /* Shift PgUp */
key = KEY_SPREVIOUS;
break;
case KEY_LEFT: /* Shift Left */
key = KEY_SLEFT;
break;
case KEY_RIGHT: /* Shift Right */
key = KEY_SRIGHT;
break;
case KEY_END: /* Shift End */
key = KEY_SEND;
break;
case KEY_DOWN: /* Shift Down */
key = KEY_SDOWN;
break;
case KEY_NPAGE: /* Shift PgDn */
key = KEY_SNEXT;
break;
case KEY_IC: /* Shift Ins */
key = KEY_SIC;
break;
case KEY_DC: /* Shift Del */
key = KEY_SDC;
}
}
key_pressed = TRUE;
SP->key_code = ((unsigned)key >= 256);
return key;
}
/* discard any pending keyboard or mouse input -- this is the core
routine for flushinp() */
void PDC_flushinp(void)
{
PDC_LOG(("PDC_flushinp() - called\n"));
/* Force the BIOS keyboard buffer head and tail pointers to be
the same... Real nasty trick... */
setdosmemword(0x41a, getdosmemword(0x41c));
}
int PDC_mouse_set(void)
{
PDCREGS regs;
unsigned long mbe = SP->_trap_mbe;
if (mbe && !mouse_avail)
{
regs.W.ax = 0;
PDCINT(0x33, regs);
mouse_avail = !!(regs.W.ax);
}
if (mbe)
{
if (mouse_avail && !mouse_vis)
{
memset(&old_ms, 0, sizeof(old_ms));
regs.W.ax = 1;
PDCINT(0x33, regs);
mouse_vis = TRUE;
}
}
else
{
if (mouse_avail && mouse_vis)
{
regs.W.ax = 2;
PDCINT(0x33, regs);
mouse_vis = FALSE;
}
}
return (mouse_avail || !mbe) ? OK : ERR;
}
int PDC_modifiers_set(void)
{
key_pressed = FALSE;
return OK;
}