367 lines
8.5 KiB
C
367 lines
8.5 KiB
C
/*** mhevt - help extension event handling code
|
||
*
|
||
* Copyright <C> 1988, Microsoft Corporation
|
||
*
|
||
* This file contains the code called by the edit in response to events
|
||
*
|
||
* Revision History (most recent first):
|
||
*
|
||
* 30-Mar-1989 ln Fudge with keyevent to react corectly to what we want.
|
||
* 23-Mar-1989 ln Created. Extracted from mhcore & others
|
||
*
|
||
*************************************************************************/
|
||
#include <string.h> /* string functions */
|
||
#include <malloc.h>
|
||
#include "mh.h" /* help extension include file */
|
||
|
||
/*************************************************************************
|
||
*
|
||
* static data
|
||
*/
|
||
static EVT EVThlp = { /* keyboard event definition */
|
||
EVT_KEY,
|
||
keyevent,
|
||
0,
|
||
0,
|
||
0 /* ALL keys */
|
||
};
|
||
static EVT EVTcan = { /* cancel event definition */
|
||
EVT_CANCEL,
|
||
CloseWin,
|
||
0,
|
||
0,
|
||
0
|
||
};
|
||
static EVT EVTxit = { /* exit event definition */
|
||
EVT_EXIT,
|
||
CloseWin,
|
||
0,
|
||
0,
|
||
0
|
||
};
|
||
static EVT EVTidl = { /* idle event definition */
|
||
EVT_IDLE,
|
||
IdleProc,
|
||
0,
|
||
0,
|
||
0
|
||
};
|
||
static EVT EVTfcs = { /* focus loss event definition */
|
||
EVT_LOSEFOCUS,
|
||
LooseFocus,
|
||
0,
|
||
0,
|
||
0
|
||
};
|
||
|
||
/*** mhevtinit - init editor event handling
|
||
*
|
||
* Input:
|
||
* none
|
||
*
|
||
* Output:
|
||
* Returns nothing
|
||
*
|
||
*************************************************************************/
|
||
void pascal near mhevtinit (void) {
|
||
|
||
EVTidl.focus = EVThlp.focus = pHelp;
|
||
RegisterEvent(&EVThlp); /* register help key event */
|
||
RegisterEvent(&EVTcan); /* register help cancel event */
|
||
RegisterEvent(&EVTidl); /* register help idle event */
|
||
RegisterEvent(&EVTxit); /* register help exit event */
|
||
RegisterEvent(&EVTfcs); /* register help focus event */
|
||
|
||
/* end mhevtinit */}
|
||
|
||
/*** keyevent - called by editor whenever a key is pressed in a help window
|
||
*
|
||
* When called we know that pHelp is being displayed, and was current.
|
||
* Process the key pressed by the user. Keys handled:
|
||
*
|
||
* TAB - move forward to next hot spot
|
||
* BACK-TAB - move backward to next hot spot
|
||
* lc Alpha - move forward to next hot spot whose text begins with alpha
|
||
* uc Alpha - move backward to next hot spot whose text begins with alpha
|
||
* Enter - execute cross reference, if we're on one
|
||
* Space - execute cross reference, if we're on one
|
||
*
|
||
* Input:
|
||
* parg = pointer to event arguments
|
||
*
|
||
* Output:
|
||
* If the key pressed is one we recognize return TRUE, else we return FALSE
|
||
* and let the editor process the key.
|
||
*
|
||
*************************************************************************/
|
||
flagType pascal EXTERNAL keyevent (
|
||
EVTargs far *parg
|
||
) {
|
||
|
||
uchar c; /* character hit */
|
||
int fDir; /* direction flag */
|
||
f fWrapped = FALSE; /* wrapped arounf flag */
|
||
hotspot hsCur; /* hot spot definition */
|
||
char *pText = NULL;
|
||
COL x;
|
||
LINE y;
|
||
|
||
c = parg->arg.key.KeyData.Ascii;
|
||
|
||
//
|
||
// if there is no topic, no sense doing anything
|
||
//
|
||
if (pTopic == 0) {
|
||
if ( ((c <= 'z') && (c >= 'a')) ||
|
||
((c <= 'Z') && (c >= 'A')) ||
|
||
(c == 0x09) ) {
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// start by getting this info, in case it is used later.
|
||
//
|
||
GetTextCursor(&x, &y);
|
||
hsCur.line = (ushort)++y;
|
||
hsCur.col = (ushort)++x;
|
||
|
||
//
|
||
// If he hit return or space, look for a cross reference at the current loc.
|
||
// If there is one, process it.
|
||
//
|
||
if ((c == 0x0d) || (c == ' ')) {
|
||
if (pText = HelpXRef (pTopic, &hsCur)) {
|
||
#ifdef DEBUG
|
||
debmsg ("Xref: ");
|
||
if (*pText) {
|
||
debmsg (pText);
|
||
} else {
|
||
debmsg ("@Local 0x");
|
||
debhex ((long)*(ushort far *)(pText+1));
|
||
}
|
||
debend (TRUE);
|
||
#endif
|
||
if (!fHelpCmd ( pText /* command/help to look up */
|
||
, FALSE /* change focus to help window */
|
||
, FALSE /* not pop-up */
|
||
)) {
|
||
errstat ("Cannot Process Cross Reference", NULL);
|
||
}
|
||
}
|
||
Display(); // Show CUrsor Position
|
||
return TRUE;
|
||
}
|
||
|
||
if ( parg->arg.key.KeyData.Flags & (FLAG_CTRL | FLAG_ALT) ) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Maneuvering keys:
|
||
// TAB: Move to next hot spot
|
||
// SHIFT+TAB Move to previous hot spot
|
||
// lcase alpha Move to next hot spot beginning with alpha
|
||
// ucase alpha Move to previous hot spot beginning with alpha
|
||
//
|
||
if ((c <= 'z') && (c >= 'a')) {
|
||
fDir = (int)c-0x20;
|
||
} else if ((c <= 'Z') && (c >= 'A')) {
|
||
fDir = -(int)c;
|
||
} else if (c == 0x09) {
|
||
if (parg->arg.key.KeyData.Flags & FLAG_SHIFT) {
|
||
fDir = -1;
|
||
} else {
|
||
fDir = 0;
|
||
}
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// loop looking for the next cross reference that either follows or precedes
|
||
// the current cursor position. Ensure that we do NOT end up on the same xref
|
||
// we are currently on. If we've reached the end/beginning of the topic, wrap
|
||
// around to the begining/end. Ensure we do this only ONCE, in case there are
|
||
// NO cross references at all.
|
||
//
|
||
while (TRUE) {
|
||
|
||
if (HelpHlNext(fDir,pTopic,&hsCur)) {
|
||
|
||
MoveCur((COL)hsCur.col-1,(LINE)hsCur.line-1);
|
||
IdleProc(parg);
|
||
Display();
|
||
|
||
if (fWrapped || ((LINE)hsCur.line != y)) {
|
||
break;
|
||
}
|
||
|
||
if ((fDir < 0) && ((COL)hsCur.ecol >= x)) {
|
||
hsCur.col--;
|
||
} else if ((fDir >= 0) && ((COL)hsCur.col <= x)) {
|
||
hsCur.col = (ushort)(hsCur.ecol+1);
|
||
} else {
|
||
break;
|
||
}
|
||
} else {
|
||
if (fWrapped++) {
|
||
break;
|
||
}
|
||
hsCur.col = 1;
|
||
hsCur.line = (fDir < 0) ? (ushort)FileLength(pHelp) : (ushort)1;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*** IdleProc - Idle event processor
|
||
*
|
||
* Purpose:
|
||
*
|
||
* Input:
|
||
* Editor event args passed, but ignored.
|
||
*
|
||
* Output:
|
||
* Returns .....
|
||
*
|
||
*************************************************************************/
|
||
flagType pascal EXTERNAL IdleProc (
|
||
EVTargs far *arg
|
||
) {
|
||
|
||
hotspot hsCur; /* hot spot definition */
|
||
fl flCur; /* current cursor location */
|
||
|
||
UNREFERENCED_PARAMETER( arg );
|
||
|
||
/*
|
||
** if there is no topic, no sense doing anything
|
||
*/
|
||
if (pTopic) {
|
||
/*
|
||
** If the cursor position has changed since the last idle call...
|
||
*/
|
||
GetTextCursor(&flCur.col, &flCur.lin);
|
||
if ((flCur.col != flIdle.col) || (flCur.lin != flIdle.lin)) {
|
||
/*
|
||
** restore the color to the previous line, and check for a cross reference at
|
||
** the current position. If there is one, change it's colors.
|
||
*/
|
||
if (flIdle.lin != -1)
|
||
PlaceColor (flIdle.lin, 0, 0);
|
||
|
||
hsCur.line = (ushort)(flCur.lin+1);
|
||
hsCur.col = (ushort)(flCur.col+1);
|
||
|
||
if (HelpXRef (pTopic, &hsCur))
|
||
SetColor (pHelp, flCur.lin, hsCur.col-1, hsCur.ecol-hsCur.col+1, C_WARNING);
|
||
|
||
flIdle = flCur;
|
||
}
|
||
}
|
||
Display();
|
||
return FALSE;
|
||
}
|
||
|
||
/*** LooseFocus - called when help file looses focus
|
||
*
|
||
* This is called each time a file looses focus. If the help file is no
|
||
* longer displayed, we clear it from memory and deallocate any associated
|
||
* help text.
|
||
*
|
||
* Input:
|
||
* e - ignored
|
||
*
|
||
* Output:
|
||
* Returns TRUE.
|
||
*
|
||
*************************************************************************/
|
||
flagType pascal EXTERNAL LooseFocus (
|
||
EVTargs far *e
|
||
) {
|
||
|
||
UNREFERENCED_PARAMETER( e );
|
||
|
||
if (!fInPopUp && pTopic && !fInOpen) {
|
||
/*
|
||
** Look for a window that has the help file in it. If found, we're done.
|
||
*/
|
||
if (FindHelpWin (FALSE))
|
||
return FALSE;
|
||
/*
|
||
** There is no help window currently displayed, deallocate any topic text
|
||
** we have lying around.
|
||
*/
|
||
if (pTopic) {
|
||
free (pTopic);
|
||
pTopic = NULL;
|
||
}
|
||
/*
|
||
** If there is a help pFile, discard it's contents
|
||
*/
|
||
if (pHelp)
|
||
DelFile (pHelp);
|
||
}
|
||
return TRUE;
|
||
/* end LooseFocus */}
|
||
|
||
/*** CloseWin - Close a window on the help file
|
||
*
|
||
* Closes the help window, if it is up. Maintains window currancy after the
|
||
* close. Relies on an eventual call to LooseFocus (above) to deallocate the
|
||
* topic text, if it is there, and discard the help pFile.
|
||
*
|
||
* Can be called by editor event processor, in response to CANCEL or EXIT
|
||
* event.
|
||
*
|
||
* Input:
|
||
* dummy - EVTargs ignored.
|
||
*
|
||
* Output:
|
||
* Returns TRUE.
|
||
*
|
||
*************************************************************************/
|
||
flagType pascal EXTERNAL CloseWin (
|
||
EVTargs far *dummy
|
||
) {
|
||
|
||
|
||
#if defined(PWB)
|
||
/*
|
||
** Look for the window that has the help file in it. If found, close it.
|
||
*/
|
||
if (pWinHelp) {
|
||
if (!CloseWnd (pWinHelp)) {
|
||
return TRUE;
|
||
}
|
||
|
||
#else
|
||
|
||
PWND pWinCur; /* window on entry */
|
||
|
||
UNREFERENCED_PARAMETER( dummy );
|
||
/*
|
||
** Look for the window that has the help file in it. If found, close it.
|
||
*/
|
||
if (pWinHelp) {
|
||
SetEditorObject (RQ_WIN_CUR | 0xff, pWinHelp, 0);
|
||
if (fSplit) {
|
||
fExecute ("meta window");
|
||
} else {
|
||
fExecute ("setfile");
|
||
}
|
||
GetEditorObject (RQ_WIN_HANDLE, 0, &pWinCur);
|
||
|
||
#endif
|
||
|
||
pWinHelp = 0;
|
||
if (pWinUser) {
|
||
SetEditorObject (RQ_WIN_CUR | 0xff, pWinUser, 0);
|
||
}
|
||
}
|
||
return TRUE;
|
||
}
|