You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
526 lines
14 KiB
526 lines
14 KiB
/************************************************************/
|
|
/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
|
|
/************************************************************/
|
|
|
|
/* curskeys.c-- cursor key movement subroutines */
|
|
/* Oct 4, 1984, KJS */
|
|
|
|
#define NOGDICAPMASKS
|
|
#define NOWINMESSAGES
|
|
#define NOWINSTYLES
|
|
#define NOCLIPBOARD
|
|
#define NOCTLMGR
|
|
#define NOSYSMETRICS
|
|
#define NOATOM
|
|
#define NOSYSCOMMANDS
|
|
#define NOCOMM
|
|
#define NOSOUND
|
|
#define NOMENUS
|
|
#define NOGDI
|
|
#define NOPEN
|
|
#define NOBRUSH
|
|
#define NOFONT
|
|
#define NOWNDCLASS
|
|
#include <windows.h>
|
|
|
|
#include "mw.h"
|
|
#define NOUAC
|
|
#include "cmddefs.h"
|
|
#include "dispdefs.h"
|
|
#include "wwdefs.h"
|
|
#include "ch.h"
|
|
#include "docdefs.h"
|
|
#include "editdefs.h"
|
|
#include "propdefs.h"
|
|
#include "debug.h"
|
|
#include "fmtdefs.h"
|
|
#include "printdef.h"
|
|
|
|
struct DOD (**hpdocdod)[];
|
|
extern typeCP cpMinCur;
|
|
extern typeCP cpMacCur;
|
|
extern struct PAP vpapAbs;
|
|
extern int vfSeeSel;
|
|
extern int vfShiftKey;
|
|
extern struct FLI vfli;
|
|
extern struct SEL selCur;
|
|
extern int wwCur;
|
|
extern struct WWD rgwwd[];
|
|
extern struct WWD *pwwdCur; /* Current window descriptor */
|
|
extern int docCur;
|
|
extern typeCP vcpSelect;
|
|
extern int vfSelAtPara;
|
|
extern int vfLastCursor;
|
|
extern int vfMakeInsEnd;
|
|
extern CHAR *vpchFetch;
|
|
|
|
int vfSeeEdgeSel=FALSE; /* Whether Idle() should show edge of selection
|
|
even if selection is partially visible */
|
|
|
|
/* Absolute x-position to try to achieve on up-down motions;
|
|
used in this module only */
|
|
int vxpCursor;
|
|
|
|
|
|
|
|
|
|
MoveLeftRight( kc )
|
|
int kc;
|
|
{ /* Move or drag selection in left or right directions */
|
|
extern int vfInsEnd;
|
|
typeCP CpEdge();
|
|
|
|
extern int vfGotoKeyMode;
|
|
extern int xpRightLim;
|
|
int fDrag = vfShiftKey ;
|
|
int fFwdKey = FALSE;
|
|
int fForward = selCur.fForward;
|
|
int sty;
|
|
typeCP cp;
|
|
|
|
MSG msg;
|
|
|
|
PeekMessage(&msg, (HWND)NULL, NULL, NULL, PM_NOREMOVE);
|
|
|
|
vfGotoKeyMode |= (GetKeyState( kcGoto & ~wKcCommandMask) < 0);
|
|
|
|
switch( kc ) {
|
|
int dl;
|
|
int xp;
|
|
int xpJunk;
|
|
|
|
default:
|
|
Assert( FALSE );
|
|
return;
|
|
case kcNextPara:
|
|
fFwdKey = TRUE;
|
|
case kcPrevPara:
|
|
sty = styPara;
|
|
break;
|
|
case kcWordRight:
|
|
fFwdKey = TRUE;
|
|
case kcWordLeft:
|
|
sty = styWord;
|
|
break;
|
|
case kcEndLine:
|
|
if (vfGotoKeyMode)
|
|
{
|
|
MoveUpDown( kcEndDoc );
|
|
return;
|
|
}
|
|
xp = xpRightLim;
|
|
goto GoDlXp;
|
|
|
|
case kcBeginLine:
|
|
if (vfGotoKeyMode)
|
|
{
|
|
MoveUpDown( kcTopDoc );
|
|
return;
|
|
}
|
|
xp = xpSelBar - wwdCurrentDoc.xpMin;
|
|
GoDlXp:
|
|
|
|
if (CpBeginLine( &dl, CpEdge() ) == selCur.cpFirst &&
|
|
selCur.cpFirst > cpMinCur && vfInsEnd )
|
|
{
|
|
CpBeginLine( &dl, selCur.cpFirst - 1);
|
|
}
|
|
vcpSelect = cpNil;
|
|
vfSelAtPara = false;
|
|
SelectDlXp( dl, xp, styChar, fDrag );
|
|
goto SeeSel;
|
|
case kcRight:
|
|
fFwdKey = TRUE;
|
|
case kcLeft:
|
|
sty = (vfGotoKeyMode) ? stySent : styChar;
|
|
break;
|
|
}
|
|
|
|
/* Find cp to start extension from */
|
|
if (selCur.cpLim == selCur.cpFirst || fDrag)
|
|
cp = fForward ? selCur.cpLim : selCur.cpFirst;
|
|
else
|
|
cp = fFwdKey ? selCur.cpLim - 1 : selCur.cpFirst + 1;
|
|
|
|
/* Catch attempts to run off the document start or end */
|
|
|
|
if (fFwdKey)
|
|
{
|
|
if (cp == cpMacCur)
|
|
{
|
|
_beep();
|
|
return;
|
|
}
|
|
}
|
|
else if (cp == cpMinCur)
|
|
{
|
|
_beep();
|
|
return;
|
|
}
|
|
|
|
if (fFwdKey)
|
|
{
|
|
if (cp >= cpMacCur)
|
|
/* If at end, stay at end. */
|
|
cp = cpMacCur;
|
|
else
|
|
{
|
|
cp = CpLimSty( cp, sty );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (cp > cpMinCur)
|
|
/* So we go back to the PREVIOUS sty unit */
|
|
cp--;
|
|
cp = CpFirstSty( cp, sty );
|
|
}
|
|
|
|
if (fDrag)
|
|
{ /* Drag selection edge to new bound. */
|
|
/* If selection flips, keep one sty unit selected EXCEPT if it's styChar;
|
|
when dragging by char, the selection can become an insertion point */
|
|
|
|
ChangeSel( cp, sty == styChar ? styNil : sty );
|
|
}
|
|
else
|
|
{
|
|
Select(cp, cp);
|
|
if (!fFwdKey)
|
|
selCur.fForward = false;
|
|
}
|
|
|
|
SeeSel:
|
|
|
|
vfSeeSel = true; /* Tell Idle to scroll the selection into view */
|
|
vfSeeEdgeSel = true; /* And the edge of it even if it's already partly visible */
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* M O V E U P D O W N */
|
|
MoveUpDown(kc)
|
|
int kc;
|
|
{ /* Move the selection in direction of kc, in up or down directions */
|
|
|
|
/* Our goal with up-and-down motions is to keep (if applicable) an */
|
|
/* absolute x-position to which the cursor tends to go if there is */
|
|
/* text on the line at that position. We set this position (vxpCursor) */
|
|
/* when we process the first up/down key, and hang onto it thereafter */
|
|
/* A global flag, vfLastCursor, tells us whether we should use the */
|
|
/* last calculated setting of vxpCursor or generate a new one. vxpCursor */
|
|
/* is set below and cleared in Select() and AlphaMode() */
|
|
|
|
extern int vfGotoKeyMode;
|
|
int fDrag = vfShiftKey;
|
|
int dl;
|
|
typeCP cpT;
|
|
struct EDL (**hdndl)[] = wwdCurrentDoc.hdndl;
|
|
register struct EDL *pedl;
|
|
int dipgd;
|
|
int xpNow;
|
|
|
|
MSG msg;
|
|
|
|
PeekMessage(&msg, (HWND)NULL, NULL, NULL, PM_NOREMOVE);
|
|
|
|
vfGotoKeyMode |= (GetKeyState( kcGoto & ~wKcCommandMask) < 0);
|
|
|
|
/* Compute dl, vxpCursor for selection starting point */
|
|
|
|
switch (kc)
|
|
{
|
|
default:
|
|
Assert( FALSE );
|
|
break;
|
|
case kcUp:
|
|
if (vfGotoKeyMode)
|
|
{ /* GOTO-UP is Prev Para */
|
|
MoveLeftRight( kcPrevPara );
|
|
return;
|
|
}
|
|
case kcPageUp:
|
|
case kcUpScrollLock:
|
|
case kcTopScreen:
|
|
case kcTopDoc:
|
|
cpT = selCur.fForward && fDrag ? selCur.cpLim : selCur.cpFirst;
|
|
break;
|
|
case kcDown:
|
|
if (vfGotoKeyMode)
|
|
{ /* GOTO-DOWN is Next Para */
|
|
MoveLeftRight( kcNextPara );
|
|
return;
|
|
}
|
|
case kcPageDown:
|
|
case kcDownScrollLock:
|
|
case kcEndScreen:
|
|
case kcEndDoc:
|
|
cpT = selCur.fForward || !fDrag ? selCur.cpLim : selCur.cpFirst;
|
|
break;
|
|
}
|
|
|
|
CpToDlXp( cpT, &dl, (vfLastCursor) ? &xpNow : &vxpCursor );
|
|
|
|
|
|
/* HACK: If the guy is dragging up/down and is on the first/last line of
|
|
the doc but not right at the start/end of the doc, extend him to
|
|
the start/end of the doc */
|
|
|
|
if (fDrag && !vfGotoKeyMode)
|
|
{
|
|
switch (kc) {
|
|
case kcUp:
|
|
/* Special fix for dragging upward: if we are seeking up to a position
|
|
that is equivalent in cp space to where we are now, force a decrement
|
|
of the source dl so we really go up a line */
|
|
|
|
if (vfLastCursor && xpNow <= xpSelBar && vxpCursor > xpSelBar &&
|
|
cpT > cpMinCur)
|
|
{
|
|
CpToDlXp( CpFirstSty( cpT - 1, styChar), &dl, &xpNow );
|
|
}
|
|
case kcPageUp:
|
|
case kcUpScrollLock:
|
|
if (wwdCurrentDoc.cpFirst == cpMinCur && cpT > cpMinCur)
|
|
if (dl == 0 || kc == kcPageUp)
|
|
{
|
|
MoveUpDown( kcTopDoc );
|
|
return;
|
|
}
|
|
break;
|
|
case kcPageDown:
|
|
case kcDown:
|
|
case kcDownScrollLock:
|
|
{
|
|
typeCP cpLimDl;
|
|
|
|
pedl = &(**hdndl) [dl];
|
|
cpLimDl = pedl->cpMin + pedl->dcpMac;
|
|
if (cpLimDl >= cpMacCur && cpT >= pedl->cpMin && cpT < cpMacCur)
|
|
{
|
|
MoveUpDown( kcEndDoc );
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Do the cursor movement, scrolling if necessary */
|
|
switch (kc)
|
|
{
|
|
case kcPageUp:
|
|
if (vfGotoKeyMode)
|
|
{ /* Go to previous printed page */
|
|
extern int vipgd;
|
|
extern int rgval[];
|
|
struct PGTB **hpgtb;
|
|
int ipgd;
|
|
|
|
dipgd = -1;
|
|
|
|
CachePage( docCur, selCur.cpFirst );
|
|
if (vipgd != iNil)
|
|
{
|
|
hpgtb = (**hpdocdod) [docCur].hpgtb;
|
|
if ((**hpgtb).rgpgd [vipgd].cpMin != selCur.cpFirst)
|
|
/* Not at page start; go there first */
|
|
dipgd++;
|
|
}
|
|
|
|
GoPage: CachePage( docCur, selCur.cpFirst ); /*validate vipgd*/
|
|
hpgtb = (**hpdocdod)[docCur].hpgtb;
|
|
if ((vipgd == iNil) ||
|
|
((ipgd = vipgd + dipgd) < 0) ||
|
|
(ipgd >= (**hpgtb).cpgd))
|
|
{ /*Whole doc on one page || run off either end*/
|
|
_beep();
|
|
}
|
|
else
|
|
{
|
|
rgval [0] = (**hpgtb).rgpgd[ipgd].pgn;
|
|
CmdJumpPage(); /* rgval [0] is a parm to CmdJumpPage */
|
|
}
|
|
return;
|
|
}
|
|
ScrollUpDypWw();
|
|
break;
|
|
case kcPageDown:
|
|
if (vfGotoKeyMode)
|
|
{ /* Go to next printed page */
|
|
dipgd = 1;
|
|
goto GoPage;
|
|
}
|
|
|
|
/* Special case for extending selection one page down from the
|
|
top line of the ww -- extend to the NEXT line so we don't
|
|
end up without any part of the selection on the screen */
|
|
|
|
ScrollDownCtr( 100 ); /* 100 > tr's in a page */
|
|
vcpSelect = cpNil;
|
|
vfSelAtPara = false;
|
|
SelectDlXp( dl, (**hdndl)[dl].fGraphics ? 0 : vxpCursor, styChar, fDrag );
|
|
if (fDrag && (dl == 0) && selCur.cpLim == wwdCurrentDoc.cpFirst)
|
|
{
|
|
MoveUpDown( kcDown );
|
|
}
|
|
goto DontSelect;
|
|
|
|
case kcUpScrollLock:
|
|
case kcUp:
|
|
UpdateWw(wwCur, false);
|
|
|
|
pedl = &(**hdndl) [dl];
|
|
|
|
if ( fDrag && (selCur.fForward ? selCur.cpLim : selCur.cpFirst) ==
|
|
pedl->cpMin && pedl->cpMin > cpMinCur)
|
|
{ /* Up into picture == left */
|
|
CachePara( docCur, pedl->cpMin - 1 );
|
|
if (vpapAbs.fGraphics)
|
|
{
|
|
MoveLeftRight( kcLeft );
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ((pedl->cpMin == cpMinCur) && (pedl->ichCpMin == 0))
|
|
{ /* At beginning of doc or area */
|
|
int xpT;
|
|
|
|
_beep();
|
|
CpToDlXp(cpMinCur, &dl, &xpT);
|
|
goto DoSelect;
|
|
}
|
|
else if ( (dl == 0) || (kc == kcUpScrollLock) )
|
|
{ /* At top of screen OR keep posn */
|
|
ScrollUpCtr( 1 );
|
|
UpdateWw(wwCur, false);
|
|
}
|
|
else
|
|
{
|
|
--dl;
|
|
}
|
|
break;
|
|
|
|
case kcDownScrollLock:
|
|
case kcDown:
|
|
UpdateWw(wwCur, false);
|
|
pedl = &(**hdndl)[dl];
|
|
{
|
|
int xpT;
|
|
typeCP cp;
|
|
|
|
cp = pedl->cpMin + pedl->dcpMac;
|
|
|
|
if (selCur.cpFirst < selCur.cpLim && selCur.fForward &&
|
|
pedl->cpMin == selCur.cpLim &&
|
|
cp < cpMacCur &&
|
|
(!fDrag ||
|
|
((vxpCursor > pedl->xpLeft + xpSelBar) &&
|
|
(pedl->dcpMac > ccpEol))))
|
|
{ /* In this case, it thinks we are at the start of the
|
|
next line; incrementing/scrolling is unnecessary */
|
|
goto DoSelect;
|
|
}
|
|
|
|
if (pedl->fGraphics)
|
|
{ /* Special for pictures */
|
|
MoveLeftRight( kcRight );
|
|
|
|
if (!fDrag)
|
|
{
|
|
extern struct PAP vpapAbs;
|
|
|
|
CachePara( docCur, selCur.cpFirst );
|
|
if (vpapAbs.fGraphics)
|
|
{
|
|
vfShiftKey = TRUE;
|
|
MoveLeftRight( kcRight );
|
|
SetShiftFlags();
|
|
}
|
|
}
|
|
goto DontSelect;
|
|
}
|
|
|
|
if (cp > cpMacCur)
|
|
{
|
|
if (selCur.cpLim == selCur.cpFirst || selCur.cpLim == cpMacCur)
|
|
/* test is because CpToDlXp cannot account for
|
|
selection extending to end of next-to-last line */
|
|
_beep();
|
|
CpToDlXp(cpMacCur, &dl, &xpT);
|
|
goto DoSelect;
|
|
}
|
|
if ( (dl >= wwdCurrentDoc.dlMac - 2) || (kc == kcDownScrollLock) )
|
|
{ /* within one line of window end */
|
|
ScrollDownCtr( 1 );
|
|
UpdateWw(wwCur, false);
|
|
}
|
|
else
|
|
dl++;
|
|
}
|
|
break;
|
|
|
|
case kcTopScreen:
|
|
dl = 0;
|
|
break;
|
|
case kcEndScreen:
|
|
dl = wwdCurrentDoc.dlMac - 1;
|
|
if ( dl > 0 && (**wwdCurrentDoc.hdndl) [dl].yp >= wwdCurrentDoc.ypMac)
|
|
{ /* Back up if last (and not only) dl is partially clipped */
|
|
dl--;
|
|
}
|
|
break;
|
|
case kcTopDoc:
|
|
CpToDlXp(cpMinCur, &dl, &vxpCursor);
|
|
break;
|
|
case kcEndDoc:
|
|
CpToDlXp(cpMacCur, &dl, &vxpCursor);
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
DoSelect: /* select at/to position vxpCursor on line dl */
|
|
vcpSelect = cpNil;
|
|
vfSelAtPara = false;
|
|
SelectDlXp( dl, (**hdndl)[dl].fGraphics ? 0 : vxpCursor, styChar, fDrag );
|
|
DontSelect:
|
|
vfLastCursor = true; /* don't recalc vxpCursor next time */
|
|
}
|
|
|
|
|
|
|
|
|
|
/* C P T O D L X P */
|
|
CpToDlXp(cp, pdl, pxp)
|
|
typeCP cp;
|
|
int *pdl, *pxp;
|
|
{ /* Transform cp into cursor coordinates */
|
|
extern int vfInsEnd;
|
|
typeCP cpBegin;
|
|
int dcp;
|
|
int xp;
|
|
|
|
if (!vfInsEnd)
|
|
PutCpInWwHz(cp);
|
|
|
|
cpBegin = CpBeginLine(pdl, cp);
|
|
ClearInsertLine();
|
|
if ( (cp == selCur.cpFirst) && (cp == selCur.cpLim) && vfInsEnd &&
|
|
cp > cpMinCur)
|
|
{ /* cp indicates we are at line beginning, but we are really
|
|
kludged at the end of the previous line */
|
|
CpToDlXp( cp - 1, pdl, pxp );
|
|
PutCpInWwHz( cp - 1 );
|
|
return;
|
|
}
|
|
|
|
dcp = (int) (cp - cpBegin);
|
|
FormatLine(docCur, cpBegin, 0, cpMacCur, flmSandMode);
|
|
xp = DxpDiff(0, dcp, &xp) + vfli.xpLeft;
|
|
*pxp = xp + (xpSelBar - wwdCurrentDoc.xpMin);
|
|
}
|